Version in base suite: 4.20.2+37-g61ff35323e-0+deb13u1 Base version: xen_4.20.2+37-g61ff35323e-0+deb13u1 Target version: xen_4.20.3+127-gc42374a105-0+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/x/xen/xen_4.20.2+37-g61ff35323e-0+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/x/xen/xen_4.20.3+127-gc42374a105-0+deb13u1.dsc CHANGELOG.md | 6 SUPPORT.md | 18 + automation/eclair_analysis/ECLAIR/analysis.ecl | 7 automation/gitlab-ci/build.yaml | 4 automation/gitlab-ci/test.yaml | 85 +++++ debian/changelog | 64 +++ docs/misc/xen-command-line.pandoc | 5 tools/flask/policy/modules/xen.if | 1 tools/include/xen-sd-notify.h | 1 tools/libfsimage/iso9660/fsys_iso9660.c | 61 +++ tools/libs/light/libxl_cpuid.c | 21 - tools/libs/light/libxl_internal.c | 2 tools/libs/light/libxl_usb.c | 16 tools/ocaml/common.make | 1 tools/ocaml/libs/xb/xb.ml | 25 + tools/ocaml/libs/xc/xenctrl_stubs.c | 2 tools/ocaml/xenstored/store.ml | 3 tools/tests/x86_emulator/predicates.c | 2 tools/xenstored/core.c | 5 tools/xenstored/transaction.c | 20 - xen/Makefile | 4 xen/arch/arm/Kconfig | 21 + xen/arch/arm/acpi/domain_build.c | 2 xen/arch/arm/arm64/insn.c | 8 xen/arch/arm/cpuerrata.c | 86 +++++ xen/arch/arm/cpufeature.c | 3 xen/arch/arm/dom0less-build.c | 15 xen/arch/arm/domain.c | 12 xen/arch/arm/domain_build.c | 4 xen/arch/arm/domctl.c | 41 +- xen/arch/arm/gic-v2.c | 20 - xen/arch/arm/gic-v3-its.c | 2 xen/arch/arm/gic-v3.c | 39 +- xen/arch/arm/guestcopy.c | 6 xen/arch/arm/include/asm/arm32/flushtlb.h | 3 xen/arch/arm/include/asm/arm64/flushtlb.h | 108 ++++-- xen/arch/arm/include/asm/domain.h | 1 xen/arch/arm/include/asm/flushtlb.h | 1 xen/arch/arm/include/asm/gic.h | 25 + xen/arch/arm/include/asm/gic_v3_defs.h | 1 xen/arch/arm/include/asm/guest_access.h | 2 xen/arch/arm/include/asm/mm.h | 10 xen/arch/arm/include/asm/mmu/layout.h | 4 xen/arch/arm/include/asm/processor.h | 23 + xen/arch/arm/mm.c | 46 +- xen/arch/arm/smpboot.c | 9 xen/arch/arm/static-shmem.c | 2 xen/arch/arm/time.c | 4 xen/arch/arm/traps.c | 4 xen/arch/arm/vgic-v3.c | 2 xen/arch/arm/vgic.c | 9 xen/arch/ppc/include/asm/irq.h | 6 xen/arch/ppc/include/asm/mm.h | 10 xen/arch/riscv/include/asm/irq.h | 6 xen/arch/riscv/include/asm/mm.h | 10 xen/arch/x86/Kconfig | 4 xen/arch/x86/Makefile | 2 xen/arch/x86/acpi/cpu_idle.c | 37 +- xen/arch/x86/apic.c | 18 - xen/arch/x86/arch.mk | 2 xen/arch/x86/boot/mkelf32.c | 2 xen/arch/x86/boot/reloc.c | 2 xen/arch/x86/cpu/amd.c | 61 +++ xen/arch/x86/cpu/common.c | 14 xen/arch/x86/cpu/intel.c | 4 xen/arch/x86/cpu/mcheck/mce.c | 20 + xen/arch/x86/cpu/microcode/amd.c | 9 xen/arch/x86/cpu/microcode/core.c | 20 + xen/arch/x86/cpu/mwait-idle.c | 17 - xen/arch/x86/dom0_build.c | 12 xen/arch/x86/domain_page.c | 48 +- xen/arch/x86/domctl.c | 95 +++-- xen/arch/x86/flushtlb.c | 5 xen/arch/x86/hpet.c | 10 xen/arch/x86/hvm/dm.c | 17 - xen/arch/x86/hvm/dom0_build.c | 3 xen/arch/x86/hvm/emulate.c | 1 xen/arch/x86/hvm/hvm.c | 1 xen/arch/x86/hvm/io.c | 72 +++- xen/arch/x86/hvm/rtc.c | 19 - xen/arch/x86/hvm/svm/intr.c | 19 + xen/arch/x86/hvm/svm/nestedhvm.h | 1 xen/arch/x86/hvm/svm/nestedsvm.c | 15 xen/arch/x86/hvm/svm/svm.c | 25 + xen/arch/x86/hvm/svm/vmcb.c | 2 xen/arch/x86/hvm/viridian/time.c | 13 xen/arch/x86/include/asm/amd.h | 4 xen/arch/x86/include/asm/dom0_build.h | 2 xen/arch/x86/include/asm/domain.h | 1 xen/arch/x86/include/asm/flushtlb.h | 2 xen/arch/x86/include/asm/hvm/domain.h | 1 xen/arch/x86/include/asm/hvm/svm/svm.h | 2 xen/arch/x86/include/asm/hvm/svm/vmcb.h | 8 xen/arch/x86/include/asm/hvm/vcpu.h | 2 xen/arch/x86/include/asm/mm.h | 18 - xen/arch/x86/include/asm/msr-index.h | 1 xen/arch/x86/include/asm/processor.h | 5 xen/arch/x86/include/asm/pv/traps.h | 2 xen/arch/x86/include/asm/time.h | 1 xen/arch/x86/irq.c | 4 xen/arch/x86/mm.c | 4 xen/arch/x86/mm/p2m-pod.c | 8 xen/arch/x86/mm/p2m.c | 30 + xen/arch/x86/mm/paging.c | 6 xen/arch/x86/platform_hypercall.c | 16 xen/arch/x86/pv/dom0_build.c | 22 - xen/arch/x86/pv/domain.c | 13 xen/arch/x86/pv/emul-gate-op.c | 6 xen/arch/x86/pv/emul-priv-op.c | 53 +++ xen/arch/x86/pv/mm.c | 6 xen/arch/x86/setup.c | 16 xen/arch/x86/smpboot.c | 95 +++-- xen/arch/x86/sysctl.c | 10 xen/arch/x86/time.c | 43 +- xen/arch/x86/traps.c | 3 xen/arch/x86/x86_64/mmconfig-shared.c | 12 xen/arch/x86/x86_emulate/decode.c | 6 xen/arch/x86/x86_emulate/x86_emulate.c | 4 xen/arch/x86/xstate.c | 17 - xen/common/device-tree/bootfdt.c | 33 +- xen/common/dm.c | 3 xen/common/domain.c | 39 -- xen/common/domctl.c | 402 +++++++++++++++---------- xen/common/efi/boot.c | 54 ++- xen/common/efi/common-stub.c | 5 xen/common/efi/runtime.c | 21 - xen/common/event_fifo.c | 8 xen/common/grant_table.c | 126 ++++++- xen/common/irq.c | 12 xen/common/libfdt/fdt_sw.c | 3 xen/common/llc-coloring.c | 3 xen/common/memory.c | 168 +++------- xen/common/monitor.c | 5 xen/common/numa.c | 6 xen/common/page_alloc.c | 13 xen/common/sched/arinc653.c | 12 xen/common/sched/core.c | 77 +--- xen/common/sched/rt.c | 34 ++ xen/common/sysctl.c | 10 xen/common/vm_event.c | 9 xen/drivers/char/ns16550.c | 66 +++- xen/drivers/cpufreq/cpufreq_ondemand.c | 8 xen/drivers/passthrough/amd/iommu_init.c | 33 +- xen/drivers/passthrough/device_tree.c | 36 +- xen/drivers/passthrough/pci.c | 12 xen/drivers/passthrough/vtd/dmar.c | 3 xen/drivers/video/vesa.c | 4 xen/drivers/vpci/header.c | 2 xen/include/public/arch-x86/cpufeatureset.h | 1 xen/include/public/domctl.h | 5 xen/include/xen/acpi.h | 34 +- xen/include/xen/cpuidle.h | 2 xen/include/xen/domain.h | 5 xen/include/xen/efi.h | 1 xen/include/xen/grant_table.h | 15 xen/include/xen/iocap.h | 3 xen/include/xen/irq.h | 1 xen/include/xen/mm.h | 11 xen/include/xen/sched.h | 10 xen/include/xen/seqcount.h | 139 ++++++++ xen/include/xen/xvmalloc.h | 3 xen/include/xsm/dummy.h | 128 +------ xen/include/xsm/xsm.h | 106 ------ xen/tools/symbols.c | 4 xen/xsm/dummy.c | 17 - xen/xsm/flask/avc.c | 3 xen/xsm/flask/hooks.c | 244 ++++++++------- 167 files changed, 2462 insertions(+), 1368 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp0h197xq9/xen_4.20.2+37-g61ff35323e-0+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp0h197xq9/xen_4.20.3+127-gc42374a105-0+deb13u1.dsc: no acceptable signature found diff -Nru xen-4.20.2+37-g61ff35323e/CHANGELOG.md xen-4.20.3+127-gc42374a105/CHANGELOG.md --- xen-4.20.2+37-g61ff35323e/CHANGELOG.md 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/CHANGELOG.md 2026-07-28 12:08:27.000000000 +0000 @@ -4,6 +4,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [4.20.3](https://xenbits.xenproject.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.20.3) + +### Added + - On x86: + - Support for CPIO microcode in discrete multiboot modules. + ## [4.20.1](https://xenbits.xenproject.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.20.1) ### Added diff -Nru xen-4.20.2+37-g61ff35323e/SUPPORT.md xen-4.20.3+127-gc42374a105/SUPPORT.md --- xen-4.20.2+37-g61ff35323e/SUPPORT.md 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/SUPPORT.md 2026-07-28 12:08:27.000000000 +0000 @@ -275,6 +275,12 @@ Status, untrusted driver domains: Supported, not security supported Status, Liveupdate: Not functional +## Guest boot loaders + +### Pygrub + + Status: Supported, security supported only when run de-privileged + ## Toolstack/3rd party ### libvirt driver for xl @@ -353,6 +359,16 @@ Status: Supported +### Shadow paging + +Allows fully virtualized guests (HVM / PVH) to be run without (host side) page +translation support by hardware (AMD: NPT, Intel: EPT). + +It is also required to migrate PV guests, and to allow L1TF-vulnerable guests +to continue to run without compromising host security. + + Status: Supported, not security supported + ### Populate-on-demand memory This is a mechanism that allows normal operating systems with only a balloon driver @@ -485,7 +501,7 @@ of the ARM "page granularity" feature (see below). Status, x86 HVM/PVH, HAP: Supported - Status, x86 HVM/PVH, Shadow, 2MiB: Supported + Status, x86 HVM/PVH, Shadow, 2MiB: Supported, not security supported Status, ARM: Supported On x86 in shadow mode, only 2MiB (L2) superpages are available; diff -Nru xen-4.20.2+37-g61ff35323e/automation/eclair_analysis/ECLAIR/analysis.ecl xen-4.20.3+127-gc42374a105/automation/eclair_analysis/ECLAIR/analysis.ecl --- xen-4.20.2+37-g61ff35323e/automation/eclair_analysis/ECLAIR/analysis.ecl 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/automation/eclair_analysis/ECLAIR/analysis.ecl 2026-07-28 12:08:27.000000000 +0000 @@ -34,6 +34,13 @@ -doc_end +-doc_begin="Do not analyze intermediate linking artifacts, as they do not differ from their final +counterparts for the purposes of MISRA C static analysis." +-file_tag+={xen_efi_tmp, "^xen/\\.xen\\.efi\\..*$"} +-file_tag+={xen_syms_tmp, "^xen/\\.xen-syms\\..*$"} +-frames+={hide, "kind(program)&&target(xen_syms_tmp||xen_efi_tmp)"} +-doc_end + -eval_file=toolchain.ecl -eval_file=public_APIs.ecl diff -Nru xen-4.20.2+37-g61ff35323e/automation/gitlab-ci/build.yaml xen-4.20.3+127-gc42374a105/automation/gitlab-ci/build.yaml --- xen-4.20.2+37-g61ff35323e/automation/gitlab-ci/build.yaml 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/automation/gitlab-ci/build.yaml 2026-07-28 12:08:27.000000000 +0000 @@ -312,11 +312,15 @@ extends: .gcc-x86-64-build-debug variables: CONTAINER: debian:12-x86_64 + EXTRA_XEN_CONFIG: | + CONFIG_SHADOW_PAGING=y debian-12-x86_64-clang-debug: extends: .clang-x86-64-build-debug variables: CONTAINER: debian:12-x86_64 + EXTRA_XEN_CONFIG: | + CONFIG_SHADOW_PAGING=y debian-12-ppc64le-gcc-debug: extends: .gcc-ppc64le-cross-build-debug diff -Nru xen-4.20.2+37-g61ff35323e/automation/gitlab-ci/test.yaml xen-4.20.3+127-gc42374a105/automation/gitlab-ci/test.yaml --- xen-4.20.2+37-g61ff35323e/automation/gitlab-ci/test.yaml 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/automation/gitlab-ci/test.yaml 2026-07-28 12:08:27.000000000 +0000 @@ -118,7 +118,7 @@ when: never - if: $XILINX_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" tags: - - xilinx + - xilinx-zynq-423 .xilinx-x86_64: extends: .test-jobs-common @@ -139,7 +139,7 @@ when: never - if: $XILINX_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" tags: - - xilinx + - xilinx-crater-001 .adl-x86-64: extends: .test-jobs-common @@ -175,6 +175,17 @@ tags: - qubes-hw3 +.ptl-x86_64: + # it's really similar to the ADL one + extends: .adl-x86-64 + variables: + PCIDEV: "56:00.0" + PCIDEV_INTR: "MSI-X" + CONSOLE_OPTS: "console=com1 com1=115200,8n1" + SUT_ADDR: test-22.testnet + tags: + - qubes-hw22 + .zen2-x86-64: # it's really similar to the above extends: .adl-x86-64 @@ -404,6 +415,76 @@ script: - ./automation/scripts/qubes-x86-64.sh tools-tests-pvh 2>&1 | tee ${LOGFILE} artifacts: + reports: + junit: tests-junit.xml + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-smoke-x86_64-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh 2>&1 | tee ${LOGFILE} + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-smoke-x86_64-dom0pvh-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh dom0pvh 2>&1 | tee ${LOGFILE} + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-smoke-x86_64-dom0pvh-hvm-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh dom0pvh-hvm 2>&1 | tee ${LOGFILE} + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-pci-pv-x86_64-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh pci-pv 2>&1 | tee ${LOGFILE} + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-pci-hvm-x86_64-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh pci-hvm 2>&1 | tee ${LOGFILE} + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-pvshim-x86_64-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh pvshim 2>&1 | tee ${LOGFILE} + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-tools-tests-pv-x86_64-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh tools-tests-pv 2>&1 | tee ${LOGFILE} + artifacts: + reports: + junit: tests-junit.xml + needs: + - *x86-64-test-needs + - alpine-3.18-gcc-debug + +ptl-tools-tests-pvh-x86_64-gcc-debug: + extends: .ptl-x86_64 + script: + - ./automation/scripts/qubes-x86-64.sh tools-tests-pvh 2>&1 | tee ${LOGFILE} + artifacts: reports: junit: tests-junit.xml needs: diff -Nru xen-4.20.2+37-g61ff35323e/debian/changelog xen-4.20.3+127-gc42374a105/debian/changelog --- xen-4.20.2+37-g61ff35323e/debian/changelog 2026-03-05 20:05:14.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/debian/changelog 2026-07-31 21:59:26.000000000 +0000 @@ -1,3 +1,67 @@ +xen (4.20.3+127-gc42374a105-0+deb13u1) trixie-security; urgency=medium + + * Update to new upstream version 4.20.3+127-gc42374a105, which also contains + security fixes for the following issues: + (Closes: #1129037) + - Use after free of paging structures in EPT + XSA-480 CVE-2026-23554 + - Xenstored DoS by unprivileged domain + XSA-481 CVE-2026-23555 + - oxenstored keeps quota related use counts across domain destruction + XSA-483 CVE-2026-23556 + - Xenstored DoS via XS_RESET_WATCHES command + XSA-484 CVE-2026-23557 + - grant table v2 race in status page mapping + XSA-486 CVE-2026-23558 + - x86: Floating Point Divider State Sampling + XSA-488 CVE-2025-54505 + - x86: CPU Opcode Cache corruption + XSA-490 CVE-2025-54518 + - x86 HVM I/O port list traversal + XSA-491 CVE-2026-42487 + - domctl lock open to abuse + XSA-492 CVE-2026-42489 CVE-2026-42490 + - Arm: Completion of memory accesses not guaranteed by completion of a TLBI + XSA-493 CVE-2025-10263 + - x86: mismatched mapcache metadata + XSA-494 CVE-2026-42488 + - x86 shadow paging is deprecated + XSA-495 CVE-2026-42493 + - buffer overruns in libfsimage iso9660 handling + XSA-497 CVE-2026-42494 CVE-2026-42495 CVE-2026-62423 CVE-2026-62424 CVE-2026-62425 + - sysctl and platform-op locks open to abuse + XSA-499 CVE-2026-62426 CVE-2026-62427 + - grant-table: type confusion in grant-copy + XSA-500 CVE-2026-62428 + - grant-table: version change racing with other operations + XSA-501 CVE-2026-62435 CVE-2026-62436 + - vNUMA domain cleanup may race other operations + XSA-502 CVE-2026-62429 + - x86: Out-of-bounds read in vRTC emulation + XSA-503 CVE-2026-62430 + - Viridian STIMER division by zero + XSA-504 CVE-2026-62431 + - evtchn: Race between FIFO expand and reset + XSA-505 CVE-2026-62432 + - correct buffer checks for DM_OP hypercalls + XSA-506 CVE-2026-62433 + - PoD: Don't try to reclaim special pages + XSA-507 CVE-2026-62434 + - pygrub: security-supported only when run de-privileged + XSA-508 + * Drop the following patches which are now included upstream: + - ARM: Drop ThumbEE support + - xen/arm: Set ThumbEE as not present in PFR0 + * Note that the following XSA are not listed, because... + - XSA-482 has patches for the Linux kernel + - XSA-485 has patches for the Linux kernel + - XSA-487 has patches for the Linux kernel + - XSA-489 applies to XAPI which is not included in Debian + - XSA-496 only applies to Xen 4.21 and later + - XSA-498 applies to XAPI which is not included in Debian + + -- Hans van Kranenburg Fri, 31 Jul 2026 23:59:26 +0200 + xen (4.20.2+37-g61ff35323e-0+deb13u1) trixie; urgency=medium * Update to new upstream version 4.20.2+37-g61ff35323e, which also contains diff -Nru xen-4.20.2+37-g61ff35323e/docs/misc/xen-command-line.pandoc xen-4.20.3+127-gc42374a105/docs/misc/xen-command-line.pandoc --- xen-4.20.2+37-g61ff35323e/docs/misc/xen-command-line.pandoc 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/docs/misc/xen-command-line.pandoc 2026-07-28 12:08:27.000000000 +0000 @@ -446,8 +446,9 @@ cleared. This allows a single port to be shared by two subsystems (e.g. console and debugger). -`pv` indicates that Xen should use Xen's PV console. This option is -only available when used together with `pv-in-pvh`. +`pv` indicates that Xen should use Xen's PV console. This option requires +Xen running as a Xen guest. and is only available if the hypervisor was +compiled with `CONFIG_XEN_GUEST` enabled. `dbgp` or `ehci` indicates that Xen should use a USB2 debug port. diff -Nru xen-4.20.2+37-g61ff35323e/tools/flask/policy/modules/xen.if xen-4.20.3+127-gc42374a105/tools/flask/policy/modules/xen.if --- xen-4.20.2+37-g61ff35323e/tools/flask/policy/modules/xen.if 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/flask/policy/modules/xen.if 2026-07-28 12:08:27.000000000 +0000 @@ -90,6 +90,7 @@ # manage_domain(priv, target) # Allow managing a running domain define(`manage_domain', ` + allow $1 domxen_t:domain getdomaininfo; allow $1 $2:domain { getdomaininfo getvcpuinfo getaffinity getaddrsize pause unpause trigger shutdown destroy setaffinity setdomainmaxmem getscheduler resume diff -Nru xen-4.20.2+37-g61ff35323e/tools/include/xen-sd-notify.h xen-4.20.3+127-gc42374a105/tools/include/xen-sd-notify.h --- xen-4.20.2+37-g61ff35323e/tools/include/xen-sd-notify.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/include/xen-sd-notify.h 2026-07-28 12:08:27.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff -Nru xen-4.20.2+37-g61ff35323e/tools/libfsimage/iso9660/fsys_iso9660.c xen-4.20.3+127-gc42374a105/tools/libfsimage/iso9660/fsys_iso9660.c --- xen-4.20.2+37-g61ff35323e/tools/libfsimage/iso9660/fsys_iso9660.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/libfsimage/iso9660/fsys_iso9660.c 2026-07-28 12:08:27.000000000 +0000 @@ -180,7 +180,15 @@ extent++; idr = (struct iso_directory_record *)DIRREC; - for (; idr->length.l > 0; + /* + * length is taken verbatim from the (untrusted) image. A record + * shorter than the fixed part of the on-disk layout cannot hold its + * own mandatory fields (name_len, extent, size, ...), which the loop + * body reads below; stop the walk rather than dereference past it. + */ + for (; idr->length.l >= sizeof(*idr) - sizeof(idr->name) + && idr->length.l + >= sizeof(*idr) - sizeof(idr->name) + idr->name_len.l; idr = (struct iso_directory_record *)((char *)idr + idr->length.l) ) { const char *name = (const char *)idr->name; @@ -201,21 +209,39 @@ } /* - * Parse Rock-Ridge extension + * Parse Rock-Ridge extension. + * + * length and name_len are taken verbatim from the (untrusted) + * image. Reject a record whose name would already overrun the + * fixed on-disk layout, so that the System Use area length does + * not underflow to a huge value below. */ - rr_len = (idr->length.l - idr->name_len.l - - sizeof(struct iso_directory_record) - + sizeof(idr->name)); + if (idr->length.l < idr->name_len.l + + sizeof(struct iso_directory_record) - sizeof(idr->name)) + rr_len = 0; + else + rr_len = (idr->length.l - idr->name_len.l + - sizeof(struct iso_directory_record) + + sizeof(idr->name)); rr_ptr.ptr = ((char *)idr + idr->name_len.l + sizeof(struct iso_directory_record) - sizeof(idr->name)); - if (rr_ptr.i & 1) + if ((rr_ptr.i & 1) && rr_len) rr_ptr.i++, rr_len--; ce_ptr = NULL; rr_flag = RR_FLAG_NM | RR_FLAG_PX /*| RR_FLAG_SL*/; while (rr_len >= 4) { + /* + * A SUSP entry is at least 4 bytes (signature, length, + * version) and must fit in the remaining System Use area. + * A shorter or overlong len is unparseable: stop, rather + * than spin forever (len == 0) or underflow rr_len in the + * advance below (len > rr_len). + */ + if (rr_ptr.rr->len < 4 || rr_ptr.rr->len > rr_len) + break; if (rr_ptr.rr->version != 1) { #ifndef STAGE1_5 @@ -236,9 +262,17 @@ rr_flag &= rr_ptr.rr->u.rr.flags.l; break; case RRMAGIC('N', 'M'): - name = (const char *)rr_ptr.rr->u.nm.name; - name_len = rr_ptr.rr->len - (4+sizeof(struct NM)); - rr_flag &= ~RR_FLAG_NM; + /* + * The generic check above only guarantees len >= 4; + * NM additionally has a flags byte, so len must be at + * least 5 for name_len not to underflow. + */ + if (rr_ptr.rr->len >= (4+sizeof(struct NM))) + { + name = (const char *)rr_ptr.rr->u.nm.name; + name_len = rr_ptr.rr->len - (4+sizeof(struct NM)); + rr_flag &= ~RR_FLAG_NM; + } break; case RRMAGIC('P', 'X'): if (rr_ptr.rr->len >= (4+sizeof(struct PX))) @@ -339,6 +373,15 @@ memcpy(NAME_BUF, name, name_len); name = (const char *)NAME_BUF; } + /* + * offset and size are image-controlled; the loaded + * continuation lives in a single-sector buffer. Bail + * out if the referenced window does not fit inside it. + */ + if (ce_ptr->u.ce.offset.l >= ISO_SECTOR_SIZE + || ce_ptr->u.ce.size.l + > ISO_SECTOR_SIZE - ce_ptr->u.ce.offset.l) + break; rr_ptr.ptr = (char *)RRCONT_BUF + ce_ptr->u.ce.offset.l; rr_len = ce_ptr->u.ce.size.l; if (!iso9660_devread(ffi, ce_ptr->u.ce.extent.l, 0, ISO_SECTOR_SIZE, (char *)RRCONT_BUF)) diff -Nru xen-4.20.2+37-g61ff35323e/tools/libs/light/libxl_cpuid.c xen-4.20.3+127-gc42374a105/tools/libs/light/libxl_cpuid.c --- xen-4.20.2+37-g61ff35323e/tools/libs/light/libxl_cpuid.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/libs/light/libxl_cpuid.c 2026-07-28 12:08:27.000000000 +0000 @@ -440,29 +440,32 @@ str = endptr + 1; entry = cpuid_find_match(policy, leaf, subleaf); for (str = endptr + 1; *str != 0;) { + const char *endptrc; + if (str[0] != 'e' || str[2] != 'x') { return 4; } value = str[1] - 'a'; - endptr = strchr(str, '='); - if (value > 3 || endptr == NULL) { + endptrc = strchr(str, '='); + if (value > 3 || endptrc == NULL) { return 4; } - str = endptr + 1; - endptr = strchr(str, ','); - if (endptr == NULL) { - endptr = strchr(str, 0); + str = endptrc + 1; + endptrc = strchr(str, ','); + if (endptrc == NULL) { + endptrc = strchr(str, 0); } - if (endptr - str != 32) { + if (endptrc - str != 32) { return 5; } entry->policy[value] = calloc(32 + 1, 1); strncpy(entry->policy[value], str, 32); entry->policy[value][32] = 0; - if (*endptr == 0) { + if (*endptrc == 0) { break; } - for (str = endptr + 1; *str == ' ' || *str == '\n'; str++); + for (str = endptrc + 1; *str == ' ' || *str == '\n'; str++) + ; } return 0; } diff -Nru xen-4.20.2+37-g61ff35323e/tools/libs/light/libxl_internal.c xen-4.20.3+127-gc42374a105/tools/libs/light/libxl_internal.c --- xen-4.20.2+37-g61ff35323e/tools/libs/light/libxl_internal.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/libs/light/libxl_internal.c 2026-07-28 12:08:27.000000000 +0000 @@ -204,7 +204,7 @@ char *libxl__dirname(libxl__gc *gc, const char *s) { - char *c = strrchr(s, '/'); + const char *c = strrchr(s, '/'); if (!c) return NULL; diff -Nru xen-4.20.2+37-g61ff35323e/tools/libs/light/libxl_usb.c xen-4.20.3+127-gc42374a105/tools/libs/light/libxl_usb.c --- xen-4.20.2+37-g61ff35323e/tools/libs/light/libxl_usb.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/libs/light/libxl_usb.c 2026-07-28 12:08:27.000000000 +0000 @@ -367,10 +367,10 @@ case 3: libxl__qmp_param_add_string(gc, &qmp_args, "driver", "nec-usb-xhci"); - libxl__qmp_param_add_string(gc, &qmp_args, "p2", - GCSPRINTF("%d", usbctrl->ports)); - libxl__qmp_param_add_string(gc, &qmp_args, "p3", - GCSPRINTF("%d", usbctrl->ports)); + libxl__qmp_param_add_integer(gc, &qmp_args, "p2", + usbctrl->ports); + libxl__qmp_param_add_integer(gc, &qmp_args, "p3", + usbctrl->ports); break; default: abort(); /* Should not be possible. */ @@ -411,10 +411,10 @@ GCSPRINTF("xenusb-%d.0", usbdev->ctrl)); libxl__qmp_param_add_string(gc, &qmp_args, "port", GCSPRINTF("%d", usbdev->port)); - libxl__qmp_param_add_string(gc, &qmp_args, "hostbus", - GCSPRINTF("%d", usbdev->u.hostdev.hostbus)); - libxl__qmp_param_add_string(gc, &qmp_args, "hostaddr", - GCSPRINTF("%d", usbdev->u.hostdev.hostaddr)); + libxl__qmp_param_add_integer(gc, &qmp_args, "hostbus", + usbdev->u.hostdev.hostbus); + libxl__qmp_param_add_integer(gc, &qmp_args, "hostaddr", + usbdev->u.hostdev.hostaddr); return libxl__ev_qmp_send(egc, qmp, "device_add", qmp_args); } diff -Nru xen-4.20.2+37-g61ff35323e/tools/ocaml/common.make xen-4.20.3+127-gc42374a105/tools/ocaml/common.make --- xen-4.20.2+37-g61ff35323e/tools/ocaml/common.make 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/ocaml/common.make 2026-07-28 12:08:27.000000000 +0000 @@ -11,6 +11,7 @@ CFLAGS += -fPIC -I$(shell ocamlc -where) +OCAMLINCLUDE += -I +unix -I +dynlink OCAMLOPTFLAGS = -g -ccopt "$(LDFLAGS)" -dtypes $(OCAMLINCLUDE) -w F -warn-error F OCAMLCFLAGS += -g $(OCAMLINCLUDE) -w F -warn-error F diff -Nru xen-4.20.2+37-g61ff35323e/tools/ocaml/libs/xb/xb.ml xen-4.20.3+127-gc42374a105/tools/ocaml/libs/xb/xb.ml --- xen-4.20.2+37-g61ff35323e/tools/ocaml/libs/xb/xb.ml 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/ocaml/libs/xb/xb.ml 2026-07-28 12:08:27.000000000 +0000 @@ -249,6 +249,11 @@ (* NB: can throw Reconnect *) let input con = + let reset_and_return partial_pkt = + let pkt = Packet.of_partialpkt partial_pkt in + con.partial_in <- init_partial_in (); + Some pkt + in if not (can_input con) then None else let to_read = to_read con in @@ -264,17 +269,25 @@ if sz > 0 then Partial.append partial_pkt (Bytes.to_string b) sz; if Partial.to_complete partial_pkt = 0 then ( - let pkt = Packet.of_partialpkt partial_pkt in - con.partial_in <- init_partial_in (); - Some pkt + reset_and_return partial_pkt ) else None | NoHdr (i, buf) -> (* we complete the partial header *) if sz > 0 then Bytes.blit b 0 buf (Partial.header_size () - i) sz; - con.partial_in <- if sz = i then - HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf); - None + if sz = i then + let partial_pkt = Partial.of_string (Bytes.to_string buf) in + (* If there is no body, we can return the full request immediately *) + if Partial.to_complete partial_pkt = 0 then + reset_and_return partial_pkt + else ( + con.partial_in <- HaveHdr partial_pkt; + None + ) + else ( + con.partial_in <- NoHdr (i - sz, buf); + None + ) ) let classify t = diff -Nru xen-4.20.2+37-g61ff35323e/tools/ocaml/libs/xc/xenctrl_stubs.c xen-4.20.3+127-gc42374a105/tools/ocaml/libs/xc/xenctrl_stubs.c --- xen-4.20.2+37-g61ff35323e/tools/ocaml/libs/xc/xenctrl_stubs.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/ocaml/libs/xc/xenctrl_stubs.c 2026-07-28 12:08:27.000000000 +0000 @@ -934,7 +934,7 @@ int retval; uint32_t c_domid = Int_val(domid); - unsigned int c_max_memkb = Int64_val(max_memkb); + uint64_t c_max_memkb = Int64_val(max_memkb); caml_enter_blocking_section(); retval = xc_domain_setmaxmem(xch, c_domid, c_max_memkb); caml_leave_blocking_section(); diff -Nru xen-4.20.2+37-g61ff35323e/tools/ocaml/xenstored/store.ml xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/store.ml --- xen-4.20.2+37-g61ff35323e/tools/ocaml/xenstored/store.ml 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/store.ml 2026-07-28 12:08:27.000000000 +0000 @@ -465,7 +465,8 @@ if perms <> node.perms then Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node); Some { node with Node.perms } - ) store.root + ) store.root; + store.quota <- Quota.del store.quota domid type ops = { store: t; diff -Nru xen-4.20.2+37-g61ff35323e/tools/tests/x86_emulator/predicates.c xen-4.20.3+127-gc42374a105/tools/tests/x86_emulator/predicates.c --- xen-4.20.2+37-g61ff35323e/tools/tests/x86_emulator/predicates.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/tests/x86_emulator/predicates.c 2026-07-28 12:08:27.000000000 +0000 @@ -1945,7 +1945,7 @@ { { 0x83 }, 2, T, R, pfx_66, W1, Ln }, /* vpmultishiftqb */ { { 0x88 }, 2, T, R, pfx_66, Wn, Ln }, /* vpexpandp{s,d} */ { { 0x89 }, 2, T, R, pfx_66, Wn, Ln }, /* vpexpand{d,q} */ - { { 0x8a }, 2, T, W, pfx_66, Wn, Ln }, /* vpcompressp{s,d} */ + { { 0x8a }, 2, T, W, pfx_66, Wn, Ln }, /* vcompressp{s,d} */ { { 0x8b }, 2, T, W, pfx_66, Wn, Ln }, /* vpcompress{d,q} */ { { 0x8d }, 2, F, R, pfx_66, Wn, Ln }, /* vperm{b,w} */ { { 0x8f }, 2, F, R, pfx_66, W0, Ln }, /* vpshufbitqmb */ diff -Nru xen-4.20.2+37-g61ff35323e/tools/xenstored/core.c xen-4.20.3+127-gc42374a105/tools/xenstored/core.c --- xen-4.20.2+37-g61ff35323e/tools/xenstored/core.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/xenstored/core.c 2026-07-28 12:08:27.000000000 +0000 @@ -1242,11 +1242,10 @@ * - illegal character in node * - starts with '@' but no special node allowed */ - errno = EINVAL; if (!node || !valid_chars(node) || (node[0] == '@' && !allow_special)) - return NULL; + goto inval; if (node[0] != '/' && node[0] != '@') { name = talloc_asprintf(ctx, "%s/%s", get_implicit_path(conn), @@ -1274,6 +1273,8 @@ if (name != node) talloc_free(name); + inval: + errno = EINVAL; return NULL; } diff -Nru xen-4.20.2+37-g61ff35323e/tools/xenstored/transaction.c xen-4.20.3+127-gc42374a105/tools/xenstored/transaction.c --- xen-4.20.2+37-g61ff35323e/tools/xenstored/transaction.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/tools/xenstored/transaction.c 2026-07-28 12:08:27.000000000 +0000 @@ -432,17 +432,23 @@ static int destroy_transaction(void *_transaction) { struct transaction *trans = _transaction; + struct connection *conn = trans->conn; struct accessed_node *i; wrl_ntransactions--; trace_destroy(trans, "transaction"); while ((i = list_top(&trans->accessed, struct accessed_node, list))) { if (i->ta_node) - db_delete(trans->conn, i->trans_name, NULL); + db_delete(conn, i->trans_name, NULL); list_del(&i->list); talloc_free(i); } + list_del(&trans->list); + domain_transaction_dec(conn); + if (list_empty(&conn->transaction_list)) + conn->ta_start_time = 0; + return 0; } @@ -523,10 +529,6 @@ return ENOENT; conn->transaction = NULL; - list_del(&trans->list); - domain_transaction_dec(conn); - if (list_empty(&conn->transaction_list)) - conn->ta_start_time = 0; chk_quota = trans->node_created && domain_is_unprivileged(conn); @@ -572,14 +574,10 @@ struct transaction *trans; while ((trans = list_top(&conn->transaction_list, - struct transaction, list))) { - list_del(&trans->list); + struct transaction, list))) talloc_free(trans); - } - - assert(conn->transaction == NULL); - conn->ta_start_time = 0; + conn->transaction = NULL; } int check_transactions(struct hashtable *hash) diff -Nru xen-4.20.2+37-g61ff35323e/xen/Makefile xen-4.20.3+127-gc42374a105/xen/Makefile --- xen-4.20.2+37-g61ff35323e/xen/Makefile 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/Makefile 2026-07-28 12:08:27.000000000 +0000 @@ -6,7 +6,7 @@ # All other places this is stored (eg. compile.h) should be autogenerated. export XEN_VERSION = 4 export XEN_SUBVERSION = 20 -export XEN_EXTRAVERSION ?= .3-pre$(XEN_VENDORVERSION) +export XEN_EXTRAVERSION ?= .4-pre$(XEN_VENDORVERSION) export XEN_FULLVERSION = $(XEN_VERSION).$(XEN_SUBVERSION)$(XEN_EXTRAVERSION) -include xen-version @@ -415,7 +415,7 @@ AFLAGS += -D__ASSEMBLY__ -$(call cc-option-add,AFLAGS,CC,-Wa$$(comma)--noexecstack) +$(call cc-option-add,CFLAGS,CC,-Wa$$(comma)--noexecstack) LDFLAGS-$(call ld-option,--warn-rwx-segments) += --no-warn-rwx-segments diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/Kconfig xen-4.20.3+127-gc42374a105/xen/arch/arm/Kconfig --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/Kconfig 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/Kconfig 2026-07-28 12:08:27.000000000 +0000 @@ -467,6 +467,27 @@ If unsure, say Y. +config ARM64_ERRATUM_CVE_2025_10263 + bool "Cortex-*/Neoverse-*/C1-*: Completion of affected memory accesses might not be guaranteed by completion of a TLBI" + default y + depends on ARM_64 + select ARM64_WORKAROUND_REPEAT_TLBI + help + This option adds a workaround for CVE-2025-10263. + + A broadcast TLBI on another PE may complete before affected memory + accesses are globally observed. This may permit bypass of Stage 1 + translation, Stage-2 translation, or GPT protection. + + The workaround repeats the TLBI VALE2IS, XZR + DSB ISH operation for all + the broadcast TLB flush operations. A single additional TLBI and DSB are + sufficient regardless of how many TLBIs are completed by the DSB. + + Note that software workarounds are required at all execution levels for + affected parts to fully mitigate this issue. + + If unsure, say Y. + endmenu config ARM64_HARDEN_BRANCH_PREDICTOR diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/acpi/domain_build.c xen-4.20.3+127-gc42374a105/xen/arch/arm/acpi/domain_build.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/acpi/domain_build.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/acpi/domain_build.c 2026-07-28 12:08:27.000000000 +0000 @@ -47,7 +47,7 @@ { mfn = spcr->serial_port.address >> PAGE_SHIFT; /* Deny MMIO access for UART */ - rc = iomem_deny_access(d, mfn, mfn + 1); + rc = iomem_deny_access(d, mfn, mfn); if ( rc ) return rc; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/arm64/insn.c xen-4.20.3+127-gc42374a105/xen/arch/arm/arm64/insn.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/arm64/insn.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/arm64/insn.c 2026-07-28 12:08:27.000000000 +0000 @@ -225,22 +225,22 @@ */ int32_t aarch64_get_branch_offset(uint32_t insn) { - int32_t imm; + uint32_t imm; if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) { imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn); - return (imm << 6) >> 4; + return (int32_t)(imm << 6) >> 4; } if (aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) || aarch64_insn_is_bcond(insn)) { imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_19, insn); - return (imm << 13) >> 11; + return (int32_t)(imm << 13) >> 11; } if (aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn)) { imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_14, insn); - return (imm << 18) >> 16; + return (int32_t)(imm << 18) >> 16; } /* Unhandled instruction */ diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/cpuerrata.c xen-4.20.3+127-gc42374a105/xen/arch/arm/cpuerrata.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/cpuerrata.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/cpuerrata.c 2026-07-28 12:08:27.000000000 +0000 @@ -534,6 +534,92 @@ MIDR_RANGE(MIDR_NEOVERSE_N1, 0, 3 << MIDR_VARIANT_SHIFT), }, #endif +#ifdef CONFIG_ARM64_ERRATUM_CVE_2025_10263 + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A76), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A76AE), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A77), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78AE), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_X1), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_X1C), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_X2), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_X3), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_X4), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_CORTEX_X925), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V3), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V3AE), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_C1_ULTRA), + }, + { + .capability = ARM64_WORKAROUND_REPEAT_TLBI, + MIDR_ALL_VERSIONS(MIDR_C1_PREMIUM), + }, +#endif #ifdef CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR { .capability = ARM_HARDEN_BRANCH_PREDICTOR, diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/cpufeature.c xen-4.20.3+127-gc42374a105/xen/arch/arm/cpufeature.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/cpufeature.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/cpufeature.c 2026-07-28 12:08:27.000000000 +0000 @@ -227,6 +227,9 @@ #endif domain_cpuinfo.pfr32.amu = 0; + /* Hide ThumbEE support */ + domain_cpuinfo.pfr32.thumbee = 0; + /* Hide RAS support as Xen does not support it */ #ifdef CONFIG_ARM_64 domain_cpuinfo.pfr64.ras = 0; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/dom0less-build.c xen-4.20.3+127-gc42374a105/xen/arch/arm/dom0less-build.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/dom0less-build.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/dom0less-build.c 2026-07-28 12:08:27.000000000 +0000 @@ -258,10 +258,23 @@ int res; paddr_t mstart, size, gstart; + /* + * xen,reg holds flat host/guest physical addresses and sizes, so the + * inherited #address-cells/#size-cells must each be 1 or 2. This also + * guards the len division below against a zero or wrapped divisor. + */ + if ( (address_cells < 1) || (address_cells > 2) || + (size_cells < 1) || (size_cells > 2) ) + { + printk(XENLOG_ERR "Invalid address_cells %u or size_cells %u\n", + address_cells, size_cells); + return -EINVAL; + } + /* xen,reg specifies where to map the MMIO region */ cell = (const __be32 *)xen_reg->data; len = fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells) * - sizeof(uint32_t)); + sizeof(*cell)); for ( i = 0; i < len; i++ ) { diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/domain.c xen-4.20.3+127-gc42374a105/xen/arch/arm/domain.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/domain.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/domain.c 2026-07-28 12:08:27.000000000 +0000 @@ -111,12 +111,6 @@ p->arch.cntkctl = READ_SYSREG(CNTKCTL_EL1); virt_timer_save(p); - if ( is_32bit_domain(p->domain) && cpu_has_thumbee ) - { - p->arch.teecr = READ_SYSREG(TEECR32_EL1); - p->arch.teehbr = READ_SYSREG(TEEHBR32_EL1); - } - #ifdef CONFIG_ARM_32 p->arch.joscr = READ_CP32(JOSCR); p->arch.jmcr = READ_CP32(JMCR); @@ -244,12 +238,6 @@ WRITE_SYSREG(n->arch.tpidrro_el0, TPIDRRO_EL0); WRITE_SYSREG(n->arch.tpidr_el1, TPIDR_EL1); - if ( is_32bit_domain(n->domain) && cpu_has_thumbee ) - { - WRITE_SYSREG(n->arch.teecr, TEECR32_EL1); - WRITE_SYSREG(n->arch.teehbr, TEEHBR32_EL1); - } - #ifdef CONFIG_ARM_32 WRITE_CP32(n->arch.joscr, JOSCR); WRITE_CP32(n->arch.jmcr, JMCR); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/domain_build.c xen-4.20.3+127-gc42374a105/xen/arch/arm/domain_build.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/domain_build.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/domain_build.c 2026-07-28 12:08:27.000000000 +0000 @@ -826,7 +826,7 @@ continue; nr_cells += reg_size; - BUG_ON(nr_cells >= ARRAY_SIZE(reg)); + BUG_ON(nr_cells > ARRAY_SIZE(reg)); dt_child_set_range(&cells, addrcells, sizecells, start, size); } @@ -2254,7 +2254,7 @@ if ( vcpu_create(d, i) == NULL ) { printk("Failed to allocate d%dv%d\n", d->domain_id, i); - break; + return -ENOMEM; } if ( is_64bit_domain(d) ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/domctl.c xen-4.20.3+127-gc42374a105/xen/arch/arm/domctl.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/domctl.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/domctl.c 2026-07-28 12:08:27.000000000 +0000 @@ -76,6 +76,7 @@ case XEN_DOMCTL_bind_pt_irq: { int rc; + struct domain *currd = current->domain; struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq; uint32_t irq = bind->u.spi.spi; uint32_t virq = bind->machine_irq; @@ -103,25 +104,30 @@ if ( rc ) return rc; - rc = xsm_bind_pt_irq(XSM_HOOK, d, bind); + rc = xsm_bind_pt_irq(XSM_DM_PRIV, d, bind); if ( rc ) return rc; - if ( !irq_access_permitted(current->domain, irq) ) - return -EPERM; + read_lock(&currd->caps_lock); - if ( !vgic_reserve_virq(d, virq) ) - return -EBUSY; - - rc = route_irq_to_guest(d, virq, irq, "routed IRQ"); - if ( rc ) - vgic_free_virq(d, virq); + if ( !irq_access_permitted(currd, irq) ) + rc = -EPERM; + else if ( !vgic_reserve_virq(d, virq) ) + rc = -EBUSY; + else + { + rc = route_irq_to_guest(d, virq, irq, "routed IRQ"); + if ( rc ) + vgic_free_virq(d, virq); + } + read_unlock(&currd->caps_lock); return rc; } case XEN_DOMCTL_unbind_pt_irq: { int rc; + struct domain *currd = current->domain; struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq; uint32_t irq = bind->u.spi.spi; uint32_t virq = bind->machine_irq; @@ -134,20 +140,19 @@ if ( irq != virq ) return -EINVAL; - rc = xsm_unbind_pt_irq(XSM_HOOK, d, bind); + rc = xsm_unbind_pt_irq(XSM_DM_PRIV, d, bind); if ( rc ) return rc; - if ( !irq_access_permitted(current->domain, irq) ) - return -EPERM; - - rc = release_guest_irq(d, virq); - if ( rc ) - return rc; + read_lock(&currd->caps_lock); - vgic_free_virq(d, virq); + if ( !irq_access_permitted(currd, irq) ) + rc = -EPERM; + else if ( !(rc = release_guest_irq(d, virq)) ) + vgic_free_virq(d, virq); - return 0; + read_unlock(&currd->caps_lock); + return rc; } case XEN_DOMCTL_vuart_op: diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/gic-v2.c xen-4.20.3+127-gc42374a105/xen/arch/arm/gic-v2.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/gic-v2.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/gic-v2.c 2026-07-28 12:08:27.000000000 +0000 @@ -408,7 +408,17 @@ static void gicv2_cpu_disable(void) { - writel_gicc(0x0, GICC_CTLR); + uint32_t ctlr = readl_gicc(GICC_CTLR); + + if ( readl_gicd(GICD_TYPER) & GICD_TYPE_SEC ) + ctlr |= GICC_NS_CTLR_BYPASS_DISABLE_GRP1_MASK; + else + ctlr |= GICC_CTLR_BYPASS_DISABLE_GRP0_MASK | + GICC_CTLR_BYPASS_DISABLE_GRP1_MASK; + + ctlr &= ~GICC_CTL_ENABLE; + + writel_gicc(ctlr, GICC_CTLR); } static void gicv2_hyp_init(void) @@ -1079,23 +1089,23 @@ unsigned long mfn, nr; mfn = dbase >> PAGE_SHIFT; - rc = iomem_deny_access(d, mfn, mfn + 1); + rc = iomem_deny_access(d, mfn, mfn); if ( rc ) return rc; mfn = hbase >> PAGE_SHIFT; - rc = iomem_deny_access(d, mfn, mfn + 1); + rc = iomem_deny_access(d, mfn, mfn); if ( rc ) return rc; mfn = cbase >> PAGE_SHIFT; nr = DIV_ROUND_UP(csize, PAGE_SIZE); - rc = iomem_deny_access(d, mfn, mfn + nr); + rc = iomem_deny_access(d, mfn, mfn + nr - 1); if ( rc ) return rc; mfn = vbase >> PAGE_SHIFT; - return iomem_deny_access(d, mfn, mfn + nr); + return iomem_deny_access(d, mfn, mfn + nr - 1); } #ifdef CONFIG_ACPI diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/gic-v3-its.c xen-4.20.3+127-gc42374a105/xen/arch/arm/gic-v3-its.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/gic-v3-its.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/gic-v3-its.c 2026-07-28 12:08:27.000000000 +0000 @@ -894,7 +894,7 @@ { mfn = paddr_to_pfn(its_data->addr); nr = PFN_UP(its_data->size); - rc = iomem_deny_access(d, mfn, mfn + nr); + rc = iomem_deny_access(d, mfn, mfn + nr - 1); if ( rc ) { printk("iomem_deny_access failed for %lx:%lx \r\n", mfn, nr); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/gic-v3.c xen-4.20.3+127-gc42374a105/xen/arch/arm/gic-v3.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/gic-v3.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/gic-v3.c 2026-07-28 12:08:27.000000000 +0000 @@ -274,16 +274,20 @@ isb(); } -/* Wait for completion of a distributor change */ -static void gicv3_do_wait_for_rwp(void __iomem *base) +/* Wait for completion of a distributor/redistributor change */ +static void gicv3_do_wait_for_rwp(void __iomem *base, uint32_t rwp_bit) { uint32_t val; bool timeout = false; s_time_t deadline = NOW() + MILLISECS(1000); do { + /* + * GICD_CTLR and GICR_CTLR are both at offset 0, so this is + * valid for either a distributor or redistributor base. + */ val = readl_relaxed(base + GICD_CTLR); - if ( !(val & GICD_CTLR_RWP) ) + if ( !(val & rwp_bit) ) break; if ( NOW() > deadline ) { @@ -300,12 +304,12 @@ static void gicv3_dist_wait_for_rwp(void) { - gicv3_do_wait_for_rwp(GICD); + gicv3_do_wait_for_rwp(GICD, GICD_CTLR_RWP); } static void gicv3_redist_wait_for_rwp(void) { - gicv3_do_wait_for_rwp(GICD_RDIST_BASE); + gicv3_do_wait_for_rwp(GICD_RDIST_BASE, GICR_CTLR_RWP); } static void gicv3_wait_for_rwp(int irq) @@ -616,12 +620,17 @@ static void __init gicv3_dist_init(void) { uint32_t type; + uint32_t ctlr; uint64_t affinity; unsigned int nr_lines; int i; - /* Disable the distributor */ - writel_relaxed(0, GICD + GICD_CTLR); + /* + * Disable the distributor without clearing ARE_NS. The GIC architecture + * makes changing ARE_NS from 1 to 0 UNPREDICTABLE. + */ + ctlr = readl_relaxed(GICD + GICD_CTLR); + writel_relaxed(ctlr & GICD_CTLR_ARE_NS, GICD + GICD_CTLR); type = readl_relaxed(GICD + GICD_TYPER); nr_lines = 32 * ((type & GICD_TYPE_LINES) + 1); @@ -695,11 +704,11 @@ } cpu_relax(); udelay(1); - } while ( timeout ); + } while ( 1 ); if ( timeout ) { - dprintk(XENLOG_ERR, "GICv3: Redist enable RWP timeout\n"); + dprintk(XENLOG_ERR, "GICv3: Redist wakeup timeout\n"); return 1; } @@ -895,7 +904,7 @@ static void gicv3_cpu_disable(void) { - WRITE_SYSREG(0, ICC_CTLR_EL1); + WRITE_SYSREG(0, ICC_IGRPEN1_EL1); isb(); } @@ -1463,7 +1472,7 @@ mfn = dbase >> PAGE_SHIFT; nr = PFN_UP(SZ_64K); - rc = iomem_deny_access(d, mfn, mfn + nr); + rc = iomem_deny_access(d, mfn, mfn + nr - 1); if ( rc ) return rc; @@ -1475,7 +1484,7 @@ { mfn = gicv3.rdist_regions[i].base >> PAGE_SHIFT; nr = PFN_UP(gicv3.rdist_regions[i].size); - rc = iomem_deny_access(d, mfn, mfn + nr); + rc = iomem_deny_access(d, mfn, mfn + nr - 1); if ( rc ) return rc; } @@ -1484,7 +1493,7 @@ { mfn = cbase >> PAGE_SHIFT; nr = PFN_UP(csize); - rc = iomem_deny_access(d, mfn, mfn + nr); + rc = iomem_deny_access(d, mfn, mfn + nr - 1); if ( rc ) return rc; } @@ -1492,8 +1501,8 @@ if ( vbase != INVALID_PADDR ) { mfn = vbase >> PAGE_SHIFT; - nr = PFN_UP(csize); - return iomem_deny_access(d, mfn, mfn + nr); + nr = PFN_UP(vsize); + return iomem_deny_access(d, mfn, mfn + nr - 1); } return 0; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/guestcopy.c xen-4.20.3+127-gc42374a105/xen/arch/arm/guestcopy.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/guestcopy.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/guestcopy.c 2026-07-28 12:08:27.000000000 +0000 @@ -53,7 +53,7 @@ return page; } -static unsigned long copy_guest(void *buf, uint64_t addr, unsigned int len, +static unsigned long copy_guest(void *buf, uint64_t addr, unsigned long len, copy_info_t info, unsigned int flags) { /* XXX needs to handle faults */ @@ -65,7 +65,7 @@ while ( len ) { void *p; - unsigned int size = min(len, (unsigned int)PAGE_SIZE - offset); + unsigned long size = min(len, PAGE_SIZE + 0UL - offset); struct page_info *page; page = translate_get_page(info, addr, flags & COPY_linear, @@ -136,7 +136,7 @@ unsigned long copy_to_guest_phys_flush_dcache(struct domain *d, paddr_t gpa, void *buf, - unsigned int len) + unsigned long len) { return copy_guest(buf, gpa, len, GPA_INFO(d), COPY_to_guest | COPY_ipa | COPY_flush_dcache); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/arm32/flushtlb.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/arm32/flushtlb.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/arm32/flushtlb.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/arm32/flushtlb.h 2026-07-28 12:08:27.000000000 +0000 @@ -57,6 +57,9 @@ asm volatile(STORE_CP32(0, TLBIMVAHIS) : : "r" (va) : "memory"); } +/* Only for ARM64_WORKAROUND_REPEAT_TLBI */ +static inline void __tlb_repeat_sync(void) {} + #endif /* __ASM_ARM_ARM32_FLUSHTLB_H__ */ /* * Local variables: diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/arm64/flushtlb.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/arm64/flushtlb.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/arm64/flushtlb.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/arm64/flushtlb.h 2026-07-28 12:08:27.000000000 +0000 @@ -12,9 +12,14 @@ * ARM64_WORKAROUND_REPEAT_TLBI: * Modification of the translation table for a virtual address might lead to * read-after-read ordering violation. - * The workaround repeats TLBI+DSB ISH operation for all the TLB flush - * operations. While this is strictly not necessary, we don't want to - * take any risk. + * The workaround repeats TLBI+DSB ISH operation for broadcast TLB flush + * operations. The workaround is not needed for local operations. + * + * It is sufficient for the additional TLBI to use *any* operation which will + * be broadcast, regardless of which translation regime or stage of translation + * the operation applies to. TLBI VALE2IS is used passing XZR. While there is + * an identity mapping there, it's only used during suspend/resume, CPU on/off, + * so the impact (performance if any) is negligible. * * For Xen page-tables the ISB will discard any instructions fetched * from the old mappings. @@ -26,69 +31,90 @@ * Note that for local TLB flush, using non-shareable (nsh) is sufficient * (see D5-4929 in ARM DDI 0487H.a). Although, the memory barrier in * for the workaround is left as inner-shareable to match with Linux - * v6.1-rc8. + * v6.19. */ -#define TLB_HELPER(name, tlbop, sh) \ +#define TLB_HELPER_LOCAL(name, tlbop) \ static inline void name(void) \ { \ asm volatile( \ - "dsb " # sh "st;" \ + "dsb nshst;" \ "tlbi " # tlbop ";" \ - ALTERNATIVE( \ - "nop; nop;", \ - "dsb ish;" \ - "tlbi " # tlbop ";", \ - ARM64_WORKAROUND_REPEAT_TLBI, \ - CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ - "dsb " # sh ";" \ + "dsb nsh;" \ "isb;" \ : : : "memory"); \ } -/* - * FLush TLB by VA. This will likely be used in a loop, so the caller - * is responsible to use the appropriate memory barriers before/after - * the sequence. - * - * See above about the ARM64_WORKAROUND_REPEAT_TLBI sequence. - */ -#define TLB_HELPER_VA(name, tlbop) \ -static inline void name(vaddr_t va) \ -{ \ - asm volatile( \ - "tlbi " # tlbop ", %0;" \ - ALTERNATIVE( \ - "nop; nop;", \ - "dsb ish;" \ - "tlbi " # tlbop ", %0;", \ - ARM64_WORKAROUND_REPEAT_TLBI, \ - CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ - : : "r" (va >> PAGE_SHIFT) : "memory"); \ +#define TLB_HELPER(name, tlbop) \ +static inline void name(void) \ +{ \ + asm volatile ( \ + "dsb ishst;" \ + "tlbi " # tlbop ";" \ + ALTERNATIVE( \ + "nop; nop;", \ + "dsb ish;" \ + "tlbi vale2is, xzr;", \ + ARM64_WORKAROUND_REPEAT_TLBI, \ + CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ + "dsb ish;" \ + "isb;" \ + : : : "memory"); \ } /* Flush local TLBs, current VMID only. */ -TLB_HELPER(flush_guest_tlb_local, vmalls12e1, nsh) +TLB_HELPER_LOCAL(flush_guest_tlb_local, vmalls12e1) /* Flush innershareable TLBs, current VMID only */ -TLB_HELPER(flush_guest_tlb, vmalls12e1is, ish) +TLB_HELPER(flush_guest_tlb, vmalls12e1is) /* Flush local TLBs, all VMIDs, non-hypervisor mode */ -TLB_HELPER(flush_all_guests_tlb_local, alle1, nsh) +TLB_HELPER_LOCAL(flush_all_guests_tlb_local, alle1) /* Flush innershareable TLBs, all VMIDs, non-hypervisor mode */ -TLB_HELPER(flush_all_guests_tlb, alle1is, ish) +TLB_HELPER(flush_all_guests_tlb, alle1is) /* Flush all hypervisor mappings from the TLB of the local processor. */ -TLB_HELPER(flush_xen_tlb_local, alle2, nsh) +TLB_HELPER_LOCAL(flush_xen_tlb_local, alle2) + +#undef TLB_HELPER_LOCAL +#undef TLB_HELPER + +/* + * FLush TLB by VA. This will likely be used in a loop, so the caller + * is responsible to use the appropriate memory barriers before/after + * the sequence. + */ /* Flush TLB of local processor for address va. */ -TLB_HELPER_VA(__flush_xen_tlb_one_local, vae2) +static inline void __flush_xen_tlb_one_local(vaddr_t va) +{ + asm volatile ( + "tlbi vae2, %0" : : "r" (va >> PAGE_SHIFT) : "memory"); +} /* Flush TLB of all processors in the inner-shareable domain for address va. */ -TLB_HELPER_VA(__flush_xen_tlb_one, vae2is) +static inline void __flush_xen_tlb_one(vaddr_t va) +{ + asm volatile ( + "tlbi vae2is, %0" : : "r" (va >> PAGE_SHIFT) : "memory"); +} -#undef TLB_HELPER -#undef TLB_HELPER_VA +/* + * ARM64_WORKAROUND_REPEAT_TLBI: + * For all relevant erratas it is only necessary to execute a single + * additional TLBI;DSB sequence after any number of TLBIs are completed by DSB. + */ +static inline void __tlb_repeat_sync(void) +{ + asm volatile ( + ALTERNATIVE( + "nop; nop;", + "tlbi vale2is, xzr;" + "dsb ish;", + ARM64_WORKAROUND_REPEAT_TLBI, + CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) + : : : "memory"); +} #endif /* __ASM_ARM_ARM64_FLUSHTLB_H__ */ /* diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/domain.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/domain.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/domain.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/domain.h 2026-07-28 12:08:27.000000000 +0000 @@ -204,7 +204,6 @@ register_t hcr_el2; register_t mdcr_el2; - uint32_t teecr, teehbr; /* ThumbEE, 32-bit guests only */ #ifdef CONFIG_ARM_32 /* * ARMv8 only supports a trivial implementation on Jazelle when in AArch32 diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/flushtlb.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/flushtlb.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/flushtlb.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/flushtlb.h 2026-07-28 12:08:27.000000000 +0000 @@ -65,6 +65,7 @@ va += PAGE_SIZE; } dsb(ish); /* Ensure the TLB invalidation has completed */ + __tlb_repeat_sync(); isb(); } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/gic.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/gic.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/gic.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/gic.h 2026-07-28 12:08:27.000000000 +0000 @@ -102,8 +102,29 @@ #define GICD_TYPE_SEC 0x400 #define GICD_TYPER_DVIS (1U << 18) -#define GICC_CTL_ENABLE 0x1 -#define GICC_CTL_EOI (0x1 << 9) +/* + * Xen runs in the Non-secure world. When Security Extensions are present, + * Xen accesses the Non-secure GICC_CTLR view, where bit[0] is EnableGrp1 + * and bits[6:5] are the Group 1 bypass-disable bits. Otherwise Xen sees the + * common GICC_CTLR layout, where bit[0] is EnableGrp0, bit[1] is EnableGrp1, + * bits[6:5] are the Group 0 bypass-disable bits, and bits[8:7] are the + * Group 1 bypass-disable bits. + */ +#define GICC_CTL_ENABLE (0x1 << 0) +#define GICC_CTL_ENABLE_GRP1 (0x1 << 1) +#define GICC_CTL_FIQBypDisGrp0 (0x1 << 5) +#define GICC_CTL_IRQBypDisGrp0 (0x1 << 6) +#define GICC_CTL_FIQBypDisGrp1 (0x1 << 7) +#define GICC_CTL_IRQBypDisGrp1 (0x1 << 8) + +#define GICC_CTLR_BYPASS_DISABLE_GRP0_MASK \ + (GICC_CTL_FIQBypDisGrp0 | GICC_CTL_IRQBypDisGrp0) +#define GICC_CTLR_BYPASS_DISABLE_GRP1_MASK \ + (GICC_CTL_FIQBypDisGrp1 | GICC_CTL_IRQBypDisGrp1) +#define GICC_NS_CTLR_BYPASS_DISABLE_GRP1_MASK \ + GICC_CTLR_BYPASS_DISABLE_GRP0_MASK + +#define GICC_CTL_EOI (0x1 << 9) #define GICC_IA_IRQ 0x03ff #define GICC_IA_CPU_MASK 0x1c00 diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/gic_v3_defs.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/gic_v3_defs.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/gic_v3_defs.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/gic_v3_defs.h 2026-07-28 12:08:27.000000000 +0000 @@ -108,6 +108,7 @@ #define GICR_NSACR (0x0E00) #define GICR_CTLR_ENABLE_LPIS (1U << 0) +#define GICR_CTLR_RWP (1U << 3) #define GICR_TYPER_PLPIS (1U << 0) #define GICR_TYPER_VLPIS (1U << 1) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/guest_access.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/guest_access.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/guest_access.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/guest_access.h 2026-07-28 12:08:27.000000000 +0000 @@ -14,7 +14,7 @@ unsigned long copy_to_guest_phys_flush_dcache(struct domain *d, paddr_t gpa, void *buf, - unsigned int len); + unsigned long len); int access_guest_memory_by_gpa(struct domain *d, paddr_t gpa, void *buf, uint32_t size, bool is_write); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/mm.h xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/mm.h --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/include/asm/mm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/mm.h 2026-07-28 12:08:27.000000000 +0000 @@ -150,9 +150,6 @@ #define _PGC_colored PG_shift(4) #define PGC_colored PG_mask(1, 4) #endif -/* Page needs to be scrubbed. */ -#define _PGC_need_scrub PG_shift(5) -#define PGC_need_scrub PG_mask(1, 5) /* ... */ /* Page is broken? */ #define _PGC_broken PG_shift(7) @@ -172,6 +169,13 @@ #define PGC_count_width PG_shift(10) #define PGC_count_mask ((1UL< */ +#define HSTR_TTEE (_AC(1,U)<<16) /* Trap ThumbEE */ /* HDCR Hyp. Debug Configuration Register */ #define HDCR_TDRA (_AC(1,U)<<11) /* Trap Debug ROM access */ diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/mm.c xen-4.20.3+127-gc42374a105/xen/arch/arm/mm.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/mm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/mm.c 2026-07-28 12:08:27.000000000 +0000 @@ -114,12 +114,10 @@ switch ( space ) { case XENMAPSPACE_grant_table: - rc = gnttab_map_frame(d, idx, gfn, &mfn); + rc = gnttab_map_frame_begin(d, idx, gfn, &mfn); if ( rc ) return rc; - /* Need to take care of the reference obtained in gnttab_map_frame(). */ - page = mfn_to_page(mfn); t = p2m_ram_rw; break; @@ -136,20 +134,25 @@ struct domain *od; p2m_type_t p2mt; - od = get_pg_owner(extra.foreign_domid); - if ( od == NULL ) - return -ESRCH; - - if ( od == d ) + if ( extra.foreign_domid == DOMID_XEN ) + od = rcu_lock_domain(dom_xen); + else { - put_pg_owner(od); - return -EINVAL; + rc = rcu_lock_remote_domain_by_id(extra.foreign_domid, &od); + if ( rc ) + return rc; + + if ( od == d ) + { + rcu_unlock_domain(od); + return -EINVAL; + } } rc = xsm_map_gmfn_foreign(XSM_TARGET, d, od); if ( rc ) { - put_pg_owner(od); + rcu_unlock_domain(od); return rc; } @@ -158,7 +161,7 @@ page = get_page_from_gfn(od, idx, &p2mt, P2M_ALLOC); if ( !page ) { - put_pg_owner(od); + rcu_unlock_domain(od); return -EINVAL; } @@ -167,13 +170,13 @@ else { put_page(page); - put_pg_owner(od); + rcu_unlock_domain(od); return -EINVAL; } mfn = page_to_mfn(page); - put_pg_owner(od); + rcu_unlock_domain(od); break; } case XENMAPSPACE_dev_mmio: @@ -221,10 +224,23 @@ * to drop the reference we took earlier. In all other cases we need to * drop any reference we took earlier (perhaps indirectly). */ - if ( space == XENMAPSPACE_gmfn_foreign ? rc : page != NULL ) + switch ( space ) { + default: + if ( page ) + put_page(page); + break; + + case XENMAPSPACE_grant_table: + gnttab_map_frame_end(d, mfn); + break; + + case XENMAPSPACE_gmfn_foreign: + if ( !rc ) + break; ASSERT(page != NULL); put_page(page); + break; } return rc; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/smpboot.c xen-4.20.3+127-gc42374a105/xen/arch/arm/smpboot.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/smpboot.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/smpboot.c 2026-07-28 12:08:27.000000000 +0000 @@ -242,7 +242,9 @@ if ( (rc = arch_cpu_init(i, cpu)) < 0 ) { printk("cpu%d init failed (hwid %"PRIregister"): %d\n", i, hwid, rc); - tmp_map[i] = MPIDR_INVALID; + + if ( i != 0 ) + cpuidx--; } else tmp_map[i] = hwid; @@ -255,10 +257,9 @@ return; } - for ( i = 0; i < cpuidx; i++ ) + /* Skip CPU 0 as it was already initialized in smp_prepare_boot_cpu(). */ + for ( i = 1; i < cpuidx; i++ ) { - if ( tmp_map[i] == MPIDR_INVALID ) - continue; cpumask_set_cpu(i, &cpu_possible_map); cpu_logical_map(i) = tmp_map[i]; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/static-shmem.c xen-4.20.3+127-gc42374a105/xen/arch/arm/static-shmem.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/static-shmem.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/static-shmem.c 2026-07-28 12:08:27.000000000 +0000 @@ -896,7 +896,7 @@ paddr_t size = mem->bank[i].size; *nr_cells += addrcells + sizecells; - BUG_ON(*nr_cells >= DT_MEM_NODE_REG_RANGE_SIZE); + BUG_ON(*nr_cells > DT_MEM_NODE_REG_RANGE_SIZE); dt_child_set_range(&cells, addrcells, sizecells, start, size); } } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/time.c xen-4.20.3+127-gc42374a105/xen/arch/arm/time.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/time.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/time.c 2026-07-28 12:08:27.000000000 +0000 @@ -128,7 +128,7 @@ res = dt_property_read_u32(timer, "clock-frequency", &rate); if ( res ) { - cpu_khz = rate / 1000; + cpu_khz = DIV_ROUND(rate, 1000); validate_timer_frequency(); timer_dt_clock_frequency = rate; } @@ -146,7 +146,7 @@ if ( !cpu_khz ) { - cpu_khz = (READ_SYSREG(CNTFRQ_EL0) & CNTFRQ_MASK) / 1000; + cpu_khz = DIV_ROUND(READ_SYSREG(CNTFRQ_EL0) & CNTFRQ_MASK, 1000); validate_timer_frequency(); } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/traps.c xen-4.20.3+127-gc42374a105/xen/arch/arm/traps.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/traps.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/traps.c 2026-07-28 12:08:27.000000000 +0000 @@ -158,8 +158,8 @@ WRITE_SYSREG(HDCR_TDRA|HDCR_TDOSA|HDCR_TDA|HDCR_TPM|HDCR_TPMCR, MDCR_EL2); - /* Trap CP15 c15 used for implementation defined registers */ - WRITE_SYSREG(HSTR_T(15), HSTR_EL2); + /* Trap CP15 c15 used for implementation defined registers, and ThumbEE. */ + WRITE_SYSREG(HSTR_T(15) | (cpu_has_thumbee ? HSTR_TTEE : 0), HSTR_EL2); WRITE_SYSREG(get_default_cptr_flags(), CPTR_EL2); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/vgic-v3.c xen-4.20.3+127-gc42374a105/xen/arch/arm/vgic-v3.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/vgic-v3.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/vgic-v3.c 2026-07-28 12:08:27.000000000 +0000 @@ -1708,7 +1708,7 @@ * not match the number of pCPUs). Update the number of regions to * avoid exposing unused region as they will not get emulated. */ - d->arch.vgic.nr_regions = i + 1; + d->arch.vgic.nr_regions = min(i + 1U, vgic_v3_hw.nr_rdist_regions); d->arch.vgic.intid_bits = vgic_v3_hw.intid_bits; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/arm/vgic.c xen-4.20.3+127-gc42374a105/xen/arch/arm/vgic.c --- xen-4.20.2+37-g61ff35323e/xen/arch/arm/vgic.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/arm/vgic.c 2026-07-28 12:08:27.000000000 +0000 @@ -198,7 +198,7 @@ int vcpu_vgic_init(struct vcpu *v) { - int i; + int i, ret; v->arch.vgic.private_irqs = xzalloc(struct vgic_irq_rank); if ( v->arch.vgic.private_irqs == NULL ) @@ -207,7 +207,12 @@ /* SGIs/PPIs are always routed to this VCPU */ vgic_rank_init(v->arch.vgic.private_irqs, 0, v->vcpu_id); - v->domain->arch.vgic.handler->vcpu_init(v); + ret = v->domain->arch.vgic.handler->vcpu_init(v); + if ( ret ) + { + XFREE(v->arch.vgic.private_irqs); + return ret; + } memset(&v->arch.vgic.pending_irqs, 0, sizeof(v->arch.vgic.pending_irqs)); for (i = 0; i < 32; i++) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/ppc/include/asm/irq.h xen-4.20.3+127-gc42374a105/xen/arch/ppc/include/asm/irq.h --- xen-4.20.2+37-g61ff35323e/xen/arch/ppc/include/asm/irq.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/ppc/include/asm/irq.h 2026-07-28 12:08:27.000000000 +0000 @@ -30,4 +30,10 @@ BUG_ON("unimplemented"); } +static inline void *irq_to_desc(unsigned int irq) +{ + BUG_ON("unimplemented"); +} +#define irq_to_desc irq_to_desc + #endif /* __ASM_PPC_IRQ_H__ */ diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/ppc/include/asm/mm.h xen-4.20.3+127-gc42374a105/xen/arch/ppc/include/asm/mm.h --- xen-4.20.2+37-g61ff35323e/xen/arch/ppc/include/asm/mm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/ppc/include/asm/mm.h 2026-07-28 12:08:27.000000000 +0000 @@ -58,9 +58,6 @@ /* Page is Xen heap? */ #define _PGC_xen_heap PG_shift(2) #define PGC_xen_heap PG_mask(1, 2) -/* Page needs to be scrubbed. */ -#define _PGC_need_scrub PG_shift(3) -#define PGC_need_scrub PG_mask(1, 3) /* Page is broken? */ #define _PGC_broken PG_shift(7) #define PGC_broken PG_mask(1, 7) @@ -79,6 +76,13 @@ #define PGC_count_width PG_shift(10) #define PGC_count_mask ((1UL<count_info & PGC_xen_heap) #define is_xen_heap_mfn(mfn) \ (mfn_valid(mfn) && is_xen_heap_page(mfn_to_page(mfn))) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/riscv/include/asm/irq.h xen-4.20.3+127-gc42374a105/xen/arch/riscv/include/asm/irq.h --- xen-4.20.2+37-g61ff35323e/xen/arch/riscv/include/asm/irq.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/riscv/include/asm/irq.h 2026-07-28 12:08:27.000000000 +0000 @@ -25,6 +25,12 @@ BUG_ON("unimplemented"); } +static inline void *irq_to_desc(unsigned int irq) +{ + BUG_ON("unimplemented"); +} +#define irq_to_desc irq_to_desc + #endif /* ASM__RISCV__IRQ_H */ /* diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/riscv/include/asm/mm.h xen-4.20.3+127-gc42374a105/xen/arch/riscv/include/asm/mm.h --- xen-4.20.2+37-g61ff35323e/xen/arch/riscv/include/asm/mm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/riscv/include/asm/mm.h 2026-07-28 12:08:27.000000000 +0000 @@ -221,15 +221,19 @@ #define PGT_count_width PG_shift(2) #define PGT_count_mask ((1UL << PGT_count_width) - 1) +/* + * Page needs to be scrubbed. Since this bit can only be set on a page that is + * free (i.e. in PGC_state_free) we can reuse PGC_allocated bit. + */ +#define _PGC_need_scrub _PGC_allocated +#define PGC_need_scrub PGC_allocated + /* Cleared when the owning guest 'frees' this page. */ #define _PGC_allocated PG_shift(1) #define PGC_allocated PG_mask(1, 1) /* Page is Xen heap? */ #define _PGC_xen_heap PG_shift(2) #define PGC_xen_heap PG_mask(1, 2) -/* Page needs to be scrubbed. */ -#define _PGC_need_scrub PG_shift(4) -#define PGC_need_scrub PG_mask(1, 4) /* Page is broken? */ #define _PGC_broken PG_shift(7) #define PGC_broken PG_mask(1, 7) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/Kconfig xen-4.20.3+127-gc42374a105/xen/arch/x86/Kconfig --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/Kconfig 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/Kconfig 2026-07-28 12:08:27.000000000 +0000 @@ -177,7 +177,6 @@ config SHADOW_PAGING bool "Shadow Paging" - default !PV_SHIM_EXCLUSIVE depends on PV || HVM help @@ -193,7 +192,8 @@ Under a small number of specific workloads, shadow paging may be deliberately used as a performance optimisation. - If unsure, say Y. + NOTE: This feature is now deprecated. It is in particular no longer + security supported. config BIGMEM bool "big memory support" diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/Makefile xen-4.20.3+127-gc42374a105/xen/arch/x86/Makefile --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/Makefile 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/Makefile 2026-07-28 12:08:27.000000000 +0000 @@ -216,6 +216,7 @@ > $(dot-target).0r.S $(NM) -pa --format=sysv $(dot-target).$(VIRT_BASE).0 \ | $(objtree)/tools/symbols $(all_symbols) --sysv --sort \ + --source-name=$(@F).S \ > $(dot-target).0s.S $(MAKE) $(build)=$(@D) .$(@F).0r.o .$(@F).0s.o $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ @@ -226,6 +227,7 @@ > $(dot-target).1r.S $(NM) -pa --format=sysv $(dot-target).$(VIRT_BASE).1 \ | $(objtree)/tools/symbols $(all_symbols) --sysv --sort \ + --source-name=$(@F).S \ > $(dot-target).1s.S $(MAKE) $(build)=$(@D) .$(@F).1r.o .$(@F).1s.o $(LD) $(call EFI_LDFLAGS,$(VIRT_BASE)) -T $(obj)/efi.lds $< \ diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/acpi/cpu_idle.c xen-4.20.3+127-gc42374a105/xen/arch/x86/acpi/cpu_idle.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/acpi/cpu_idle.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/acpi/cpu_idle.c 2026-07-28 12:08:27.000000000 +0000 @@ -118,7 +118,7 @@ lapic_timer_off = hpet_broadcast_enter; lapic_timer_on = hpet_broadcast_exit; } - else if ( pit_broadcast_is_available() ) + else if ( cpuidle_usable_deep_cstate() ) { lapic_timer_off = pit_broadcast_enter; lapic_timer_on = pit_broadcast_exit; @@ -130,12 +130,15 @@ } void (*__read_mostly pm_idle_save)(void); -unsigned int max_cstate __read_mostly = UINT_MAX; + +unsigned int max_usable_cstate __read_mostly = UINT_MAX; +unsigned int max_allowed_cstate __read_mostly = UINT_MAX; unsigned int max_csubstate __read_mostly = UINT_MAX; static int __init cf_check parse_cstate(const char *s) { - max_cstate = simple_strtoul(s, &s, 0); + max_allowed_cstate = simple_strtoul(s, &s, 0); + max_usable_cstate = max_allowed_cstate; if ( *s == ',' ) max_csubstate = simple_strtoul(s + 1, NULL, 0); return 0; @@ -412,10 +415,11 @@ unsigned int cpu; printk("'%c' pressed -> printing ACPI Cx structures\n", key); - if ( max_cstate < UINT_MAX ) + if ( max_cstate() < UINT_MAX ) { - printk("max state: C%u\n", max_cstate); - if ( max_csubstate < UINT_MAX ) + printk("max state: C%u\n", max_cstate()); + if ( max_allowed_cstate <= max_usable_cstate && + max_csubstate < UINT_MAX ) printk("max sub-state: %u\n", max_csubstate); else printk("max sub-state: unlimited\n"); @@ -697,18 +701,18 @@ u32 exp = 0, pred = 0; u32 irq_traced[4] = { 0 }; - if ( max_cstate > 0 && power && + if ( max_cstate() > 0 && power && (next_state = cpuidle_current_governor->select(power)) > 0 ) { unsigned int max_state = sched_has_urgent_vcpu() ? ACPI_STATE_C1 - : max_cstate; + : max_cstate(); do { cx = &power->states[next_state]; } while ( (cx->type > max_state || cx->entry_method == ACPI_CSTATE_EM_NONE || (cx->entry_method == ACPI_CSTATE_EM_FFH && - cx->type == max_cstate && + cx->type == max_allowed_cstate && (cx->address & MWAIT_SUBSTATE_MASK) > max_csubstate)) && --next_state ); if ( next_state ) @@ -1456,7 +1460,7 @@ for ( i = 0; i < nr; ++i ) { - if ( cx[i].type > max_cstate ) + if ( cx[i].type > max_cstate() ) break; power->states[i + 1] = cx[i]; power->states[i + 1].idx = i + 1; @@ -1617,21 +1621,22 @@ void cpuidle_disable_deep_cstate(void) { - if ( max_cstate > ACPI_STATE_C1 ) + if ( max_usable_cstate > ACPI_STATE_C1 ) { if ( local_apic_timer_c2_ok ) - max_cstate = ACPI_STATE_C2; + max_usable_cstate = ACPI_STATE_C2; else - max_cstate = ACPI_STATE_C1; + max_usable_cstate = ACPI_STATE_C1; } hpet_disable_legacy_broadcast(); } -bool cpuidle_using_deep_cstate(void) +bool cpuidle_usable_deep_cstate(void) { - return xen_cpuidle && max_cstate > (local_apic_timer_c2_ok ? ACPI_STATE_C2 - : ACPI_STATE_C1); + return xen_cpuidle && + max_usable_cstate > (local_apic_timer_c2_ok ? ACPI_STATE_C2 + : ACPI_STATE_C1); } static int cf_check cpu_callback( diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/apic.c xen-4.20.3+127-gc42374a105/xen/arch/x86/apic.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/apic.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/apic.c 2026-07-28 12:08:27.000000000 +0000 @@ -1311,10 +1311,22 @@ } if ( timeout && ((expire = timeout - NOW()) > 0) ) - apic_tmict = min_t(uint64_t, (bus_scale * expire) >> BUS_SCALE_SHIFT, - UINT32_MAX); + { + unsigned long product; + bool carry; - apic_write(APIC_TMICT, (unsigned long)apic_tmict); + apic_tmict = UINT32_MAX; + asm ( "mul %[expire]\n\t" + ASM_FLAG_OUT(, "setc %[cf]") + : "=&a" (product), [cf] ASM_FLAG_OUT("=@ccc", "=qm") (carry) + : "0" ((unsigned long)bus_scale), [expire] "r" (expire) + : "rdx" ); + if ( !carry && + (product >>= BUS_SCALE_SHIFT) < apic_tmict ) + apic_tmict = product; + } + + apic_write(APIC_TMICT, apic_tmict); return apic_tmict || !timeout; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/arch.mk xen-4.20.3+127-gc42374a105/xen/arch/x86/arch.mk --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/arch.mk 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/arch.mk 2026-07-28 12:08:27.000000000 +0000 @@ -112,7 +112,7 @@ ifeq ($(XEN_BUILD_PE),y) # Check if the linker produces fixups in PE by default -efi-nr-fixups := $(shell LC_ALL=C $(OBJDUMP) -p $(efi-check).efi | grep '^[[:blank:]]*reloc[[:blank:]]*[0-9][[:blank:]].*DIR64$$' | wc -l) +efi-nr-fixups := $(strip $(shell LC_ALL=C $(OBJDUMP) -p $(efi-check).efi | grep -E '^[[:blank:]]*reloc[[:blank:]]*[0-9][[:blank:]].*DIR64$$' | wc -l)) ifeq ($(efi-nr-fixups),2) MKRELOC := : diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/boot/mkelf32.c xen-4.20.3+127-gc42374a105/xen/arch/x86/boot/mkelf32.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/boot/mkelf32.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/boot/mkelf32.c 2026-07-28 12:08:27.000000000 +0000 @@ -345,7 +345,7 @@ * the Xen image using 2M pages. To avoid running into adjacent non-RAM * regions, pad the segment to the next 2M boundary. */ - mem_siz = ((uint32_t)in64_phdr.p_memsz + (1U << 20) - 1) & (-1U << 20); + mem_siz = ((uint32_t)in64_phdr.p_memsz + (1U << 21) - 1) & (-1U << 21); note_sz = note_base = offset = 0; if ( num_phdrs > 1 ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/boot/reloc.c xen-4.20.3+127-gc42374a105/xen/arch/x86/boot/reloc.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/boot/reloc.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/boot/reloc.c 2026-07-28 12:08:27.000000000 +0000 @@ -339,7 +339,7 @@ end: #ifdef CONFIG_VIDEO - if ( video ) + if ( video && video->lfb_size ) video->orig_video_isVGA = 0x23; #endif diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/amd.c xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/amd.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/amd.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/amd.c 2026-07-28 12:08:27.000000000 +0000 @@ -982,6 +982,42 @@ wrmsrl(MSR_AMD64_DE_CFG, val | new); } +static void amd_init_fp_cfg(const struct cpuinfo_x86 *c) +{ + uint64_t val, new = 0; + + /* If virtualised, we won't have mutable access even if we can read it. */ + if ( cpu_has_hypervisor ) + return; + + /* + * On Zen1, mitigate SB-7053 / FP-DSS Floating Point Divider State + * Sampling by setting bit 9 as instructed. + */ + if ( c->x86 == 0x17 && is_zen1_uarch() ) + new |= 1 << 9; + + /* + * Avoid reading FP_CFG if we don't intend to change anything. The + * register doesn't exist on all families. + */ + if ( !new ) + return; + + rdmsrl(MSR_AMD64_FP_CFG, val); + + if ( (val & new) == new ) + return; + + /* + * FP_CFG is a Core-scoped MSR, and this write is racy. However, both + * threads calculate the new value from state which expected to be + * consistent across CPUs and unrelated to the old value, so the result + * should be consistent. + */ + wrmsrl(MSR_AMD64_FP_CFG, val | new); +} + void __init amd_init_lfence_dispatch(void) { struct cpuinfo_x86 *c = &boot_cpu_data; @@ -1014,11 +1050,25 @@ { uint64_t val, new = 0; - /* - * AMD Erratum #1485. Set bit 5, as instructed. - */ - if (!cpu_has_hypervisor && boot_cpu_data.x86 == 0x19 && is_zen4_uarch()) - new |= (1 << 5); + if (!cpu_has_hypervisor) { + /* + * AMD Erratum #1485. If SMT is enabled and STIBP disabled, + * the CPU may fetch incorrect instruction bytes. + * + * Set bit 5, as instructed. + */ + if (boot_cpu_data.x86 == 0x19 && is_zen4_uarch()) + new |= (1 << 5); + + /* + * AMD SB-7052. CPU OP Cache corruption, causing instructions + * to be executed at a higher privilege. + * + * Set bit 33, as instructed. + */ + if (boot_cpu_data.x86 == 0x17 && is_zen2_uarch()) + new |= (1UL << 33); + } /* * On hardware supporting SRSO_MSR_FIX, activate BP_SPEC_REDUCE by @@ -1055,6 +1105,7 @@ unsigned long long value; amd_init_de_cfg(c); + amd_init_fp_cfg(c); if (c == &boot_cpu_data) amd_init_lfence_dispatch(); /* Needs amd_init_de_cfg() */ diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/common.c xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/common.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/common.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/common.c 2026-07-28 12:08:27.000000000 +0000 @@ -382,7 +382,9 @@ c->x86_capability[FEATURESET_m10Ah]); if (max_subleaf >= 1) - cpuid_count(7, 1, &eax, &ebx, &ecx, + cpuid_count(7, 1, + &c->x86_capability[FEATURESET_7a1], + &ebx, &ecx, &c->x86_capability[FEATURESET_7d1]); } @@ -610,16 +612,20 @@ smp_processor_id()); } - if (system_state == SYS_STATE_resume) - return; + if (system_state == SYS_STATE_resume) { + unsigned int cpu = smp_processor_id(); + /* The BSP has this done right from enter_state(). */ + if (cpu) + mcheck_init(&cpu_data[cpu], false); + } /* * On SMP, boot_cpu_data holds the common feature set between * all CPUs; so make sure that we indicate which features are * common between the CPUs. The first time this routine gets * executed, c == &boot_cpu_data. */ - if ( c != &boot_cpu_data ) { + else if (c != &boot_cpu_data) { /* AND the already accumulated flags with these */ for ( i = 0 ; i < NCAPINTS ; i++ ) boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/intel.c xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/intel.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/intel.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/intel.c 2026-07-28 12:08:27.000000000 +0000 @@ -399,12 +399,12 @@ }; /* Serialized by the AP bringup code. */ - if ( max_cstate > 1 && (c->apicid & (c->x86_num_siblings - 1)) && + if ( max_usable_cstate > 1 && (c->apicid & (c->x86_num_siblings - 1)) && x86_match_cpu(models) ) { printk(XENLOG_WARNING "Disabling C-states C3 and C6 due to CPU errata\n"); - max_cstate = 1; + max_usable_cstate = 1; } } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/mcheck/mce.c xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/mcheck/mce.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/mcheck/mce.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/mcheck/mce.c 2026-07-28 12:08:27.000000000 +0000 @@ -854,6 +854,22 @@ return mic_index; } +/* Linux values need using when reporting CPU vendors to the outside. */ +static unsigned int xen2linux_vendor(unsigned int vendor) +{ + switch ( vendor ) + { + case X86_VENDOR_INTEL: return 0; + case X86_VENDOR_AMD: return 2; + case X86_VENDOR_CENTAUR: return 5; + case X86_VENDOR_HYGON: return 9; + case X86_VENDOR_SHANGHAI: return 10; /* X86_VENDOR_ZHAOXIN */ + default: break; + } + + return 0xff; /* X86_VENDOR_UNKNOWN */ +} + static void x86_mcinfo_apei_save( struct mcinfo_global *mc_global, struct mcinfo_bank *mc_bank) { @@ -862,7 +878,7 @@ memset(&m, 0, sizeof(struct mce)); m.cpu = mc_global->mc_coreid; - m.cpuvendor = boot_cpu_data.x86_vendor; + m.cpuvendor = xen2linux_vendor(boot_cpu_data.x86_vendor); m.cpuid = cpuid_eax(1); m.socketid = mc_global->mc_socketid; m.apicid = mc_global->mc_apicid; @@ -964,7 +980,7 @@ &xcp->mc_ncores_active, &xcp->mc_nthreads); xcp->mc_cpuid_level = c->cpuid_level; xcp->mc_family = c->x86; - xcp->mc_vendor = c->x86_vendor; + xcp->mc_vendor = xen2linux_vendor(c->x86_vendor); xcp->mc_model = c->x86_model; xcp->mc_step = c->x86_mask; xcp->mc_cache_size = c->x86_cache_size; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/microcode/amd.c xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/microcode/amd.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/microcode/amd.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/microcode/amd.c 2026-07-28 12:08:27.000000000 +0000 @@ -20,6 +20,7 @@ #include /* TODO: Fix asm/tlbflush.h breakage */ #include +#include #include #include "private.h" @@ -128,7 +129,8 @@ * the digest of the patch against a list of known provenance. */ if ( boot_cpu_data.x86 < 0x17 || boot_cpu_data.x86 > 0x1a || - entrysign_mitigiated_in_firmware || !opt_digest_check ) + is_zen6_uarch() || entrysign_mitigiated_in_firmware || + !opt_digest_check ) return true; pd = bsearch(&patch->patch_id, patch_digests, ARRAY_SIZE(patch_digests), @@ -568,7 +570,7 @@ * CPUs. Taint Xen if digest checking is turned off. */ if ( boot_cpu_data.x86 >= 0x17 && boot_cpu_data.x86 <= 0x1a && - !opt_digest_check ) + !is_zen6_uarch() && !opt_digest_check ) { printk(XENLOG_WARNING "Microcode patch additional digest checks disabled\n"); @@ -609,7 +611,8 @@ if ( boot_cpu_data.x86_vendor != X86_VENDOR_AMD || boot_cpu_data.x86 < 0x17 || - boot_cpu_data.x86 > 0x1a ) + boot_cpu_data.x86 > 0x1a || + is_zen6_uarch() ) return; /* diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/microcode/core.c xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/microcode/core.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/microcode/core.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/microcode/core.c 2026-07-28 12:08:27.000000000 +0000 @@ -749,6 +749,7 @@ void *data = NULL; size_t size; struct microcode_patch *patch; + struct cpio_data cd; int idx = opt_mod_idx; int rc; @@ -765,7 +766,6 @@ for ( idx = 0; idx < bi->nr_modules; ++idx ) { const struct boot_module *bm = &bi->mods[idx]; - struct cpio_data cd; /* Search anything unclaimed or likely to be a CPIO archive. */ if ( bm->type != BOOTMOD_UNKNOWN && @@ -834,6 +834,24 @@ idx, size); return -ENODEV; } + + /* + * If this blob appears to be a CPIO archive, try interpreting it as + * one. Otherwise treat it as a raw vendor blob. + */ + cd = find_cpio_data(ucode_ops.cpio_path, data, size); + if ( cd.data ) + { + data = cd.data; + size = cd.size; + + /* + * (Ab)use opt_scan to inform microcode_init_cache() that + * early_mod_idx refers to a CPIO archive. + */ + opt_scan = true; + } + goto found; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/mwait-idle.c xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/mwait-idle.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/cpu/mwait-idle.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/mwait-idle.c 2026-07-28 12:08:27.000000000 +0000 @@ -1043,15 +1043,16 @@ u64 before, after; u32 exp = 0, pred = 0, irq_traced[4] = { 0 }; - if (max_cstate > 0 && power && + if (max_cstate() > 0 && power && (next_state = cpuidle_current_governor->select(power)) > 0) { unsigned int max_state = sched_has_urgent_vcpu() ? ACPI_STATE_C1 - : max_cstate; + : max_cstate(); do { cx = &power->states[next_state]; - } while ((cx->type > max_state || (cx->type == max_cstate && - MWAIT_HINT2SUBSTATE(cx->address) > max_csubstate)) && + } while ((cx->type > max_state || + (cx->type == max_allowed_cstate && + MWAIT_HINT2SUBSTATE(cx->address) > max_csubstate)) && --next_state); if (!next_state) cx = NULL; @@ -1457,7 +1458,7 @@ u64 msr; /* if PC10 disabled via cmdline max_cstate=7 or shallower */ - if (max_cstate <= 7) + if (max_cstate() <= 7) return; /* if PC10 not present in CPUID.MWAIT.EDX */ @@ -1618,7 +1619,7 @@ !mwait_substates) return -ENODEV; - if (!max_cstate || !opt_mwait_idle) { + if (!max_cstate() || !opt_mwait_idle) { pr_debug(PREFIX "disabled\n"); return -EPERM; } @@ -1709,8 +1710,8 @@ hint = flg2MWAIT(cpuidle_state_table[cstate].flags); state = MWAIT_HINT2CSTATE(hint) + 1; - if (state > max_cstate) { - printk(PREFIX "max C-state %u reached\n", max_cstate); + if (state > max_cstate()) { + printk(PREFIX "max C-state %u reached\n", max_cstate()); break; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/dom0_build.c xen-4.20.3+127-gc42374a105/xen/arch/x86/dom0_build.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/dom0_build.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/dom0_build.c 2026-07-28 12:08:27.000000000 +0000 @@ -319,6 +319,18 @@ return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT); } +int __init initdom_check_parms( + const struct domain *d, const struct elf_dom_parms *parms) +{ + if ( parms->elf_notes[XEN_ELFNOTE_SUPPORTED_FEATURES].type != XEN_ENT_NONE && + is_hardware_domain(d) && !test_bit(XENFEAT_dom0, parms->f_supported) ) + { + printk("Kernel does not support Dom0 operation\n"); + return -EINVAL; + } + + return 0; +} /* * If allocation isn't specified, reserve 1/16th of available memory for diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/domain_page.c xen-4.20.3+127-gc42374a105/xen/arch/x86/domain_page.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/domain_page.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/domain_page.c 2026-07-28 12:08:27.000000000 +0000 @@ -18,48 +18,40 @@ #include #include -static DEFINE_PER_CPU(struct vcpu *, override); - static inline struct vcpu *mapcache_current_vcpu(void) { - /* In the common case we use the mapcache of the running VCPU. */ - struct vcpu *v = this_cpu(override) ?: current; - - /* - * When current isn't properly set up yet, this is equivalent to - * running in an idle vCPU (callers must check for NULL). - */ - if ( !v ) - return NULL; + struct vcpu *v = this_cpu(pgtable_vcpu); + struct vcpu *curr = current; /* - * When using efi runtime page tables, we have the equivalent of the idle - * domain's page tables but current may point at another domain's VCPU. - * Return NULL as though current is not properly set up yet. + * During early boot pgtable_vcpu is not set, callers must handle NULL. + * Non-PV domains don't have a mapcache, the directmap covers all physical + * address space. */ - if ( efi_rs_using_pgtables() ) + if ( !v || !is_pv_vcpu(v) ) return NULL; /* - * If guest_table is NULL, and we are running a paravirtualised guest, - * then it means we are running on the idle domain's page table and must - * therefore use its mapcache. + * If we are in a lazy context-switch state from a PV vCPU do a full switch + * to the idle vCPU now, otherwise an incoming FLUSH_VCPU_STATE IPI would + * change the page tables under our feet an invalidate any in-use mapcache + * entries. */ - if ( unlikely(pagetable_is_null(v->arch.guest_table)) && is_pv_vcpu(v) ) + if ( unlikely(this_cpu(curr_vcpu) != curr) ) { - /* If we really are idling, perform lazy context switch now. */ - if ( (v = idle_vcpu[smp_processor_id()]) == current ) - sync_local_execstate(); + ASSERT(curr == idle_vcpu[smp_processor_id()]); + sync_local_execstate(); /* We must now be running on the idle page table. */ ASSERT(cr3_pa(read_cr3()) == __pa(idle_pg_table)); } - return v; -} - -void __init mapcache_override_current(struct vcpu *v) -{ - this_cpu(override) = v; + /* + * At this point we can guarantee Xen is not in lazy context switch: either + * the code above will have synced the state, or an incoming + * FLUSH_VCPU_STATE IPI has done so behind our back. Use ACCESS_ONCE to + * ensure the compiler never returns the locally cached pgtable_vcpu value. + */ + return ACCESS_ONCE(this_cpu(pgtable_vcpu)); } #define mapcache_l2_entry(e) ((e) >> PAGETABLE_ORDER) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/domctl.c xen-4.20.3+127-gc42374a105/xen/arch/x86/domctl.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/domctl.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/domctl.c 2026-07-28 12:08:27.000000000 +0000 @@ -226,15 +226,24 @@ unsigned int np = domctl->u.ioport_permission.nr_ports; int allow = domctl->u.ioport_permission.allow_access; + ret = -EINVAL; if ( (fp + np) <= fp || (fp + np) > MAX_IOPORTS ) - ret = -EINVAL; - else if ( !ioports_access_permitted(currd, fp, fp + np - 1) || - xsm_ioport_permission(XSM_HOOK, d, fp, fp + np - 1, allow) ) + break; + + ret = xsm_ioport_permission(XSM_PRIV, d, fp, fp + np - 1, allow); + if ( ret ) + break; + + iocaps_double_lock(d, true); + + if ( !ioports_access_permitted(currd, fp, fp + np - 1) ) ret = -EPERM; else if ( allow ) ret = ioports_permit_access(d, fp, fp + np - 1); else ret = ioports_deny_access(d, fp, fp + np - 1); + + iocaps_double_unlock(d, true); break; } @@ -256,16 +265,20 @@ break; } - ret = -EPERM; - if ( !irq_access_permitted(currd, irq) || - xsm_irq_permission(XSM_HOOK, d, irq, flags) ) + ret = xsm_irq_permission(XSM_PRIV, d, irq, flags); + if ( ret ) break; - if ( flags ) + iocaps_double_lock(d, true); + + if ( !irq_access_permitted(currd, irq) ) + ret = -EPERM; + else if ( flags ) ret = irq_permit_access(d, irq); else ret = irq_deny_access(d, irq); + iocaps_double_unlock(d, true); break; } @@ -563,25 +576,32 @@ if ( !is_hvm_domain(d) ) break; - ret = xsm_bind_pt_irq(XSM_HOOK, d, bind); + ret = xsm_bind_pt_irq(XSM_DM_PRIV, d, bind); if ( ret ) break; irq = domain_pirq_to_irq(d, bind->machine_irq); - ret = -EPERM; - if ( irq <= 0 || !irq_access_permitted(currd, irq) ) - break; + if ( irq <= 0 ) + ret = -EPERM; - ret = -ESRCH; - if ( is_iommu_enabled(d) ) + read_lock(&currd->caps_lock); + + if ( !irq_access_permitted(currd, irq) ) + ret = -EPERM; + else if ( is_iommu_enabled(d) ) { pcidevs_lock(); ret = pt_irq_create_bind(d, bind); pcidevs_unlock(); + + if ( ret < 0 ) + printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for %pd\n", + ret, d); } - if ( ret < 0 ) - printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for dom%d\n", - ret, d->domain_id); + else + ret = -ESRCH; + + read_unlock(&currd->caps_lock); break; } @@ -594,23 +614,26 @@ if ( !is_hvm_domain(d) ) break; - ret = -EPERM; - if ( irq <= 0 || !irq_access_permitted(currd, irq) ) - break; - - ret = xsm_unbind_pt_irq(XSM_HOOK, d, bind); + ret = xsm_unbind_pt_irq(XSM_DM_PRIV, d, bind); if ( ret ) break; - if ( is_iommu_enabled(d) ) + read_lock(&currd->caps_lock); + + if ( !irq_access_permitted(currd, irq) ) + ret = -EPERM; + else if ( is_iommu_enabled(d) ) { pcidevs_lock(); ret = pt_irq_destroy_bind(d, bind); pcidevs_unlock(); + + if ( ret < 0 ) + printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for %pd\n", + ret, d); } - if ( ret < 0 ) - printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for dom%d\n", - ret, d->domain_id); + + read_unlock(&currd->caps_lock); break; } @@ -641,21 +664,22 @@ break; } - ret = -EPERM; - if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) ) - break; - - ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add); + ret = xsm_ioport_mapping(XSM_DM_PRIV, d, fmp, fmp + np - 1, add); if ( ret ) break; hvm = &d->arch.hvm; - if ( add ) + iocaps_double_lock(d, true); + + if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) ) + ret = -EPERM; + else if ( add ) { printk(XENLOG_G_INFO "ioport_map:add: dom%d gport=%x mport=%x nr=%x\n", d->domain_id, fgp, fmp, np); + write_lock(&hvm->g2m_ioport_lock); list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list) if (g2m_ioport->mport == fmp ) { @@ -677,11 +701,14 @@ g2m_ioport->np = np; list_add_tail(&g2m_ioport->list, &hvm->g2m_ioport_list); } + write_unlock(&hvm->g2m_ioport_lock); if ( !ret ) ret = ioports_permit_access(d, fmp, fmp + np - 1); if ( ret && !found && g2m_ioport ) { + write_lock(&hvm->g2m_ioport_lock); list_del(&g2m_ioport->list); + write_unlock(&hvm->g2m_ioport_lock); xfree(g2m_ioport); } } @@ -690,6 +717,8 @@ printk(XENLOG_G_INFO "ioport_map:remove: dom%d gport=%x mport=%x nr=%x\n", d->domain_id, fgp, fmp, np); + + write_lock(&hvm->g2m_ioport_lock); list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list) if ( g2m_ioport->mport == fmp ) { @@ -697,12 +726,16 @@ xfree(g2m_ioport); break; } + write_unlock(&hvm->g2m_ioport_lock); + ret = ioports_deny_access(d, fmp, fmp + np - 1); if ( ret && is_hardware_domain(currd) ) printk(XENLOG_ERR "ioport_map: error %ld denying dom%d access to [%x,%x]\n", ret, d->domain_id, fmp, fmp + np - 1); } + + iocaps_double_unlock(d, true); break; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/flushtlb.c xen-4.20.3+127-gc42374a105/xen/arch/x86/flushtlb.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/flushtlb.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/flushtlb.c 2026-07-28 12:08:27.000000000 +0000 @@ -111,7 +111,9 @@ local_irq_restore(flags); } -void switch_cr3_cr4(unsigned long cr3, unsigned long cr4) +DEFINE_PER_CPU(struct vcpu *, pgtable_vcpu); + +void switch_cr3_cr4(struct vcpu *v, unsigned long cr3, unsigned long cr4) { unsigned long flags, old_cr4; u32 t = 0; @@ -155,6 +157,7 @@ if ( (old_cr4 & X86_CR4_PCIDE) > (cr4 & X86_CR4_PCIDE) ) cr3 |= X86_CR3_NOFLUSH; write_cr3(cr3); + this_cpu(pgtable_vcpu) = v; if ( old_cr4 != cr4 ) write_cr4(cr4); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hpet.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hpet.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hpet.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hpet.c 2026-07-28 12:08:27.000000000 +0000 @@ -701,12 +701,18 @@ for ( i = 0; i < n; i++ ) { if ( hpet_events[i].msi.irq >= 0 ) - __hpet_setup_msi_irq(irq_to_desc(hpet_events[i].msi.irq)); + { + struct irq_desc *desc = irq_to_desc(hpet_events[i].msi.irq); + + cpumask_copy(desc->arch.cpu_mask, cpumask_of(smp_processor_id())); + + __hpet_setup_msi_irq(desc); + } /* set HPET Tn as oneshot */ cfg = hpet_read32(HPET_Tn_CFG(hpet_events[i].idx)); cfg &= ~(HPET_TN_LEVEL | HPET_TN_PERIODIC); - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + cfg |= HPET_TN_32BIT; if ( !(hpet_events[i].flags & HPET_EVT_LEGACY) ) cfg |= HPET_TN_FSB; hpet_write32(cfg, HPET_Tn_CFG(hpet_events[i].idx)); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/dm.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/dm.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/dm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/dm.c 2026-07-28 12:08:27.000000000 +0000 @@ -493,6 +493,12 @@ struct xen_dm_op_modified_memory *data = &op.u.modified_memory; + if ( op_args->nr_bufs != 2 ) + { + rc = -EINVAL; + break; + } + rc = modified_memory(d, op_args, data); const_op = !rc; break; @@ -568,12 +574,16 @@ rc = xenmem_add_to_physmap(d, &xatp, 0); if ( rc == 0 && data->size != xatp.size ) + { rc = xatp.size; + xatp.idx += rc; + xatp.gpfn += rc; + } if ( rc > 0 ) { data->size -= rc; - data->src_gfn += rc; - data->dst_gfn += rc; + data->src_gfn = xatp.idx; + data->dst_gfn = xatp.gpfn; const_op = false; rc = -ERESTART; } @@ -650,6 +660,9 @@ unsigned int i; int rc; + if ( !nr_bufs ) + return -ENODATA; + if ( nr_bufs > ARRAY_SIZE(args.buf) ) return -E2BIG; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/dom0_build.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/dom0_build.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/dom0_build.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/dom0_build.c 2026-07-28 12:08:27.000000000 +0000 @@ -690,6 +690,9 @@ return -EINVAL; } + if ( (rc = initdom_check_parms(d, &parms)) != 0 ) + return rc; + /* Copy the OS image and free temporary buffer. */ elf.dest_base = (void *)(parms.virt_kstart - parms.virt_base); elf.dest_size = parms.virt_kend - parms.virt_kstart; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/emulate.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/emulate.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/emulate.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/emulate.c 2026-07-28 12:08:27.000000000 +0000 @@ -159,7 +159,6 @@ hvio->mmio_insn_bytes = 0; hvio->mmio_access = (struct npfec){}; hvio->mmio_retry = false; - hvio->g2m_ioport = NULL; hvmemul_cache_disable(v); } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/hvm.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/hvm.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/hvm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/hvm.c 2026-07-28 12:08:27.000000000 +0000 @@ -601,6 +601,7 @@ spin_lock_init(&d->arch.hvm.irq_lock); spin_lock_init(&d->arch.hvm.uc_lock); spin_lock_init(&d->arch.hvm.write_map.lock); + rwlock_init(&d->arch.hvm.g2m_ioport_lock); rwlock_init(&d->arch.hvm.mmcfg_lock); INIT_LIST_HEAD(&d->arch.hvm.write_map.list); INIT_LIST_HEAD(&d->arch.hvm.g2m_ioport_list); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/io.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/io.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/io.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/io.c 2026-07-28 12:08:27.000000000 +0000 @@ -144,36 +144,56 @@ return true; } -static bool cf_check g2m_portio_accept( - const struct hvm_io_handler *handler, const ioreq_t *p) +/* NB: Returns with the lock held in the success case. */ +static const struct g2m_ioport *g2m_portio_find_and_lock(struct hvm_domain *hvm, + uint64_t addr, + uint32_t size) { - struct vcpu *curr = current; - const struct hvm_domain *hvm = &curr->domain->arch.hvm; - struct hvm_vcpu_io *hvio = &curr->arch.hvm.hvm_io; - struct g2m_ioport *g2m_ioport; - unsigned int start, end; + const struct g2m_ioport *g2m_ioport; + + read_lock(&hvm->g2m_ioport_lock); list_for_each_entry( g2m_ioport, &hvm->g2m_ioport_list, list ) { - start = g2m_ioport->gport; - end = start + g2m_ioport->np; - if ( (p->addr >= start) && (p->addr + p->size <= end) ) - { - hvio->g2m_ioport = g2m_ioport; - return 1; - } + unsigned int start = g2m_ioport->gport; + + if ( addr >= start && addr + size <= start + g2m_ioport->np ) + return g2m_ioport; } - return 0; + read_unlock(&hvm->g2m_ioport_lock); + + return NULL; +} + +static bool cf_check g2m_portio_accept( + const struct hvm_io_handler *handler, const ioreq_t *p) +{ + struct hvm_domain *hvm = ¤t->domain->arch.hvm; + const struct g2m_ioport *g2m_ioport = + g2m_portio_find_and_lock(hvm, p->addr, p->size); + + if ( !g2m_ioport ) + return false; + + read_unlock(&hvm->g2m_ioport_lock); + + return true; } static int cf_check g2m_portio_read( const struct hvm_io_handler *handler, uint64_t addr, uint32_t size, uint64_t *data) { - struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io; - const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport; - unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport; + struct hvm_domain *hvm = ¤t->domain->arch.hvm; + const struct g2m_ioport *g2m_ioport = + g2m_portio_find_and_lock(hvm, addr, size); + unsigned int mport; + + if ( !g2m_ioport ) + return X86EMUL_RETRY; + + mport = addr - g2m_ioport->gport + g2m_ioport->mport; switch ( size ) { @@ -190,6 +210,8 @@ BUG(); } + read_unlock(&hvm->g2m_ioport_lock); + return X86EMUL_OKAY; } @@ -197,9 +219,15 @@ const struct hvm_io_handler *handler, uint64_t addr, uint32_t size, uint64_t data) { - struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io; - const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport; - unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport; + struct hvm_domain *hvm = ¤t->domain->arch.hvm; + const struct g2m_ioport *g2m_ioport = + g2m_portio_find_and_lock(hvm, addr, size); + unsigned int mport; + + if ( !g2m_ioport ) + return X86EMUL_RETRY; + + mport = addr - g2m_ioport->gport + g2m_ioport->mport; switch ( size ) { @@ -216,6 +244,8 @@ BUG(); } + read_unlock(&hvm->g2m_ioport_lock); + return X86EMUL_OKAY; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/rtc.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/rtc.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/rtc.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/rtc.c 2026-07-28 12:08:27.000000000 +0000 @@ -647,13 +647,21 @@ return 0; } -static uint32_t rtc_ioport_read(RTCState *s) +static bool rtc_ioport_read(RTCState *s, uint32_t *val) { int ret; struct domain *d = vrtc_domain(s); + *val = ~0; + spin_lock(&s->lock); + if ( s->hw.cmos_index >= RTC_CMOS_SIZE ) + { + spin_unlock(&s->lock); + return false; + } + switch ( s->hw.cmos_index ) { case RTC_SECONDS: @@ -693,7 +701,9 @@ spin_unlock(&s->lock); - return ret; + *val = ret; + + return true; } static int cf_check handle_rtc_io( @@ -718,11 +728,8 @@ *val = 0xff; return X86EMUL_OKAY; } - else if ( vrtc->hw.cmos_index < RTC_CMOS_SIZE ) - { - *val = rtc_ioport_read(vrtc); + else if ( rtc_ioport_read(vrtc, val) ) return X86EMUL_OKAY; - } return X86EMUL_UNHANDLEABLE; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/intr.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/intr.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/intr.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/intr.c 2026-07-28 12:08:27.000000000 +0000 @@ -33,6 +33,12 @@ u32 general1_intercepts = vmcb_get_general1_intercepts(vmcb); intinfo_t event; + if ( vmcb->_vintr.fields.vnmi_enable ) + { + vmcb->_vintr.fields.vnmi_pending = true; + return; + } + event.raw = 0; event.v = true; event.type = X86_ET_NMI; @@ -142,6 +148,19 @@ return; intblk = hvm_interrupt_blocked(v, intack); + + /* + * When vNMI is active, NMIs can be injected by setting vnmi_pending + * and hardware will deliver them at the next appropriate opportunity. + * Consider them not blocked, to avoid trying to open an NMI Window. + * + * Correctness here relies on the fact that all vNMI capable hardware + * has vGIF, and vGIF is always activated when appropriate. + */ + if ( intblk == hvm_intblk_nmi_iret && + vmcb->_vintr.fields.vnmi_enable ) + intblk = hvm_intblk_none; + if ( intblk == hvm_intblk_svm_gif ) { ASSERT(nestedhvm_enabled(v->domain)); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/nestedhvm.h xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/nestedhvm.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/nestedhvm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/nestedhvm.h 2026-07-28 12:08:27.000000000 +0000 @@ -48,6 +48,7 @@ struct vcpu *v, unsigned int vector, int errcode); bool cf_check nsvm_vmcb_hap_enabled(struct vcpu *v); enum hvm_intblk cf_check nsvm_intr_blocked(struct vcpu *v); +void cf_check nsvm_domain_relinquish_resources(struct domain *d); /* Interrupts, vGIF */ void svm_vmexit_do_clgi(struct cpu_user_regs *regs, struct vcpu *v); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/nestedsvm.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/nestedsvm.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/nestedsvm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/nestedsvm.c 2026-07-28 12:08:27.000000000 +0000 @@ -127,8 +127,6 @@ svm->ns_merged_msrpm = NULL; } - hvm_unmap_guest_frame(nv->nv_vvmcx, 1); - nv->nv_vvmcx = NULL; if ( nv->nv_n2vmcx ) { free_vmcb(nv->nv_n2vmcx); @@ -139,6 +137,19 @@ svm->ns_iomap = NULL; } +void cf_check nsvm_domain_relinquish_resources(struct domain *d) +{ + struct vcpu *v; + struct nestedvcpu *nv; + + for_each_vcpu ( d, v ) + { + nv = &vcpu_nestedhvm(v); + hvm_unmap_guest_frame(nv->nv_vvmcx, 1); + nv->nv_vvmcx = NULL; + } +} + int cf_check nsvm_vcpu_reset(struct vcpu *v) { struct nestedsvm *svm = &vcpu_nestedsvm(v); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/svm.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/svm.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/svm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/svm.c 2026-07-28 12:08:27.000000000 +0000 @@ -545,7 +545,9 @@ if ( vmcb->int_stat.intr_shadow ) intr_shadow |= HVM_INTR_SHADOW_MOV_SS | HVM_INTR_SHADOW_STI; - if ( vmcb_get_general1_intercepts(vmcb) & GENERAL1_INTERCEPT_IRET ) + if ( vmcb->_vintr.fields.vnmi_enable + ? vmcb->_vintr.fields.vnmi_blocking + : (vmcb_get_general1_intercepts(vmcb) & GENERAL1_INTERCEPT_IRET) ) intr_shadow |= HVM_INTR_SHADOW_NMI; return intr_shadow; @@ -555,15 +557,23 @@ struct vcpu *v, unsigned int intr_shadow) { struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb; - u32 general1_intercepts = vmcb_get_general1_intercepts(vmcb); + bool block_nmi = intr_shadow & HVM_INTR_SHADOW_NMI; vmcb->int_stat.intr_shadow = !!(intr_shadow & (HVM_INTR_SHADOW_MOV_SS|HVM_INTR_SHADOW_STI)); - general1_intercepts &= ~GENERAL1_INTERCEPT_IRET; - if ( intr_shadow & HVM_INTR_SHADOW_NMI ) - general1_intercepts |= GENERAL1_INTERCEPT_IRET; - vmcb_set_general1_intercepts(vmcb, general1_intercepts); + if ( vmcb->_vintr.fields.vnmi_enable ) + vmcb->_vintr.fields.vnmi_blocking = block_nmi; + else + { + uint32_t gen1 = vmcb_get_general1_intercepts(vmcb); + + gen1 &= ~GENERAL1_INTERCEPT_IRET; + if ( block_nmi ) + gen1 |= GENERAL1_INTERCEPT_IRET; + + vmcb_set_general1_intercepts(vmcb, gen1); + } } static int cf_check svm_guest_x86_mode(struct vcpu *v) @@ -2468,6 +2478,7 @@ .nhvm_vmcx_hap_enabled = nsvm_vmcb_hap_enabled, .nhvm_intr_blocked = nsvm_intr_blocked, .nhvm_hap_walk_L1_p2m = nsvm_hap_walk_L1_p2m, + .nhvm_domain_relinquish_resources = nsvm_domain_relinquish_resources, .get_reg = svm_get_reg, .set_reg = svm_set_reg, @@ -2518,6 +2529,7 @@ P(cpu_has_tsc_ratio, "TSC Rate MSR"); P(cpu_has_svm_sss, "NPT Supervisor Shadow Stack"); P(cpu_has_svm_spec_ctrl, "MSR_SPEC_CTRL virtualisation"); + P(cpu_has_svm_vnmi, "Virtual NMI"); #undef P if ( !printed ) @@ -2549,6 +2561,7 @@ hvm_sanitize_regs_fields( regs, !(vmcb_get_efer(vmcb) & EFER_LMA) || !(vmcb->cs.l)); + v->arch.hvm.guest_cr[2] = vmcb_get_cr2(vmcb); if ( paging_mode_hap(v->domain) ) v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/vmcb.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/vmcb.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/svm/vmcb.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/svm/vmcb.c 2026-07-28 12:08:27.000000000 +0000 @@ -173,6 +173,8 @@ if ( default_xen_spec_ctrl == SPEC_CTRL_STIBP ) v->arch.msrs->spec_ctrl.raw = SPEC_CTRL_STIBP; + vmcb->_vintr.fields.vnmi_enable = cpu_has_svm_vnmi; + return 0; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/viridian/time.c xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/viridian/time.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/hvm/viridian/time.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/viridian/time.c 2026-07-28 12:08:27.000000000 +0000 @@ -155,6 +155,14 @@ printk(XENLOG_G_INFO "%pv: VIRIDIAN STIMER%u: enabled\n", v, stimerx); + if ( !vs->count ) + { + gprintk(XENLOG_ERR, "VIRIDIAN STIMER started with 0 count\n"); + ASSERT_UNREACHABLE(); + domain_crash(v->domain); + return; + } + if ( vs->config.periodic ) { /* @@ -364,7 +372,7 @@ vs->config.as_uint64 = val; - if ( !vs->config.sintx ) + if ( !vs->config.sintx || !vs->count ) vs->config.enable = 0; if ( vs->config.enable ) @@ -575,6 +583,9 @@ vs->config.as_uint64 = ctxt->stimer_config_msr[i]; vs->count = ctxt->stimer_count_msr[i]; + if ( !vs->config.sintx || !vs->count ) + /* Reject enabling with a zero sintx or count fields. */ + vs->config.enable = 0; } } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/amd.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/amd.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/amd.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/amd.h 2026-07-28 12:08:27.000000000 +0000 @@ -149,6 +149,8 @@ * For Zen3 and Zen4 (Fam19h) the heuristic is the presence of AutoIBRS, as * it's Zen4-specific. * + * For Zen5 and Zen6 (Fam1ah) the heuristic is the presence of FRED. + * * The caller is required to perform the appropriate vendor/family checks * first. */ @@ -156,6 +158,8 @@ #define is_zen2_uarch() boot_cpu_has(X86_FEATURE_AMD_STIBP) #define is_zen3_uarch() (!boot_cpu_has(X86_FEATURE_AUTO_IBRS)) #define is_zen4_uarch() boot_cpu_has(X86_FEATURE_AUTO_IBRS) +#define is_zen5_uarch() (!boot_cpu_has(X86_FEATURE_FRED)) +#define is_zen6_uarch() boot_cpu_has(X86_FEATURE_FRED) struct cpuinfo_x86; int cpu_has_amd_erratum(const struct cpuinfo_x86 *cpu, int osvw_id, ...); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/dom0_build.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/dom0_build.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/dom0_build.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/dom0_build.h 2026-07-28 12:08:27.000000000 +0000 @@ -8,6 +8,8 @@ extern unsigned int dom0_memflags; +int initdom_check_parms(const struct domain *d, + const struct elf_dom_parms *parms); unsigned long dom0_compute_nr_pages(struct domain *d, struct elf_dom_parms *parms, unsigned long initrd_len); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/domain.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/domain.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/domain.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/domain.h 2026-07-28 12:08:27.000000000 +0000 @@ -75,7 +75,6 @@ int mapcache_domain_init(struct domain *d); int mapcache_vcpu_init(struct vcpu *v); -void mapcache_override_current(struct vcpu *v); /* x86/64: toggle guest between kernel and user modes. */ void toggle_guest_mode(struct vcpu *v); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/flushtlb.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/flushtlb.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/flushtlb.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/flushtlb.h 2026-07-28 12:08:27.000000000 +0000 @@ -99,7 +99,7 @@ } /* Write pagetable base and implicitly tick the tlbflush clock. */ -void switch_cr3_cr4(unsigned long cr3, unsigned long cr4); +void switch_cr3_cr4(struct vcpu *v, unsigned long cr3, unsigned long cr4); /* flush_* flag fields: */ /* diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/domain.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/domain.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/domain.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/domain.h 2026-07-28 12:08:27.000000000 +0000 @@ -125,6 +125,7 @@ /* List of guest to machine IO ports mapping. */ struct list_head g2m_ioport_list; + rwlock_t g2m_ioport_lock; /* List of MMCFG regions trapped by Xen. */ struct list_head mmcfg_regions; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/svm/svm.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/svm/svm.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/svm/svm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/svm/svm.h 2026-07-28 12:08:27.000000000 +0000 @@ -37,6 +37,7 @@ #define SVM_FEATURE_VGIF 16 /* Virtual GIF */ #define SVM_FEATURE_SSS 19 /* NPT Supervisor Shadow Stacks */ #define SVM_FEATURE_SPEC_CTRL 20 /* MSR_SPEC_CTRL virtualisation */ +#define SVM_FEATURE_VNMI 25 /* Virtual NMI */ static inline bool cpu_has_svm_feature(unsigned int feat) { @@ -56,5 +57,6 @@ #define cpu_has_svm_vloadsave cpu_has_svm_feature(SVM_FEATURE_VLOADSAVE) #define cpu_has_svm_sss cpu_has_svm_feature(SVM_FEATURE_SSS) #define cpu_has_svm_spec_ctrl cpu_has_svm_feature(SVM_FEATURE_SPEC_CTRL) +#define cpu_has_svm_vnmi cpu_has_svm_feature(SVM_FEATURE_VNMI) #endif /* __ASM_X86_HVM_SVM_H__ */ diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/svm/vmcb.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/svm/vmcb.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/svm/vmcb.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/svm/vmcb.h 2026-07-28 12:08:27.000000000 +0000 @@ -338,13 +338,17 @@ u64 tpr: 8; u64 irq: 1; u64 vgif: 1; - u64 rsvd0: 6; + u64 : 1; + u64 vnmi_pending: 1; + u64 vnmi_blocking:1; + u64 : 3; u64 prio: 4; u64 ign_tpr: 1; u64 rsvd1: 3; u64 intr_masking: 1; u64 vgif_enable: 1; - u64 rsvd2: 6; + u64 vnmi_enable: 1; + u64 : 5; u64 vector: 8; u64 rsvd3: 24; } fields; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/vcpu.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/vcpu.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/hvm/vcpu.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/vcpu.h 2026-07-28 12:08:27.000000000 +0000 @@ -54,8 +54,6 @@ unsigned long msix_unmask_address; unsigned long msix_snoop_address; unsigned long msix_snoop_gpa; - - const struct g2m_ioport *g2m_ioport; }; struct nestedvcpu { diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/mm.h xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/mm.h --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/include/asm/mm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/mm.h 2026-07-28 12:08:27.000000000 +0000 @@ -83,25 +83,29 @@ #define PGC_state_offlined PG_mask(2, 6) #define PGC_state_free PG_mask(3, 6) #define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st) -/* Page needs to be scrubbed. */ -#define _PGC_need_scrub PG_shift(7) -#define PGC_need_scrub PG_mask(1, 7) #ifdef CONFIG_SHADOW_PAGING /* Set when a page table page has been shadowed. */ -#define _PGC_shadowed_pt PG_shift(8) -#define PGC_shadowed_pt PG_mask(1, 8) +#define _PGC_shadowed_pt PG_shift(7) +#define PGC_shadowed_pt PG_mask(1, 7) #else #define PGC_shadowed_pt 0 #endif /* Count of references to this frame. */ #if PGC_shadowed_pt -#define PGC_count_width PG_shift(8) -#else #define PGC_count_width PG_shift(7) +#else +#define PGC_count_width PG_shift(6) #endif #define PGC_count_mask ((1UL<status |= IRQ_INPROGRESS; action = desc->action; - while ( desc->status & IRQ_PENDING ) + + /* Deal with IRQ_DISABLED being set while inside the loop body. */ + while ( (desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING ) { desc->status &= ~IRQ_PENDING; spin_unlock_irq(&desc->lock); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm/p2m-pod.c xen-4.20.3+127-gc42374a105/xen/arch/x86/mm/p2m-pod.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm/p2m-pod.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/mm/p2m-pod.c 2026-07-28 12:08:27.000000000 +0000 @@ -536,12 +536,13 @@ p2m_access_t a; p2m_type_t t; unsigned int cur_order; + mfn_t mfn = p2m->get_entry(p2m, gfn_add(gfn, i), &t, &a, 0, &cur_order, + NULL); - p2m->get_entry(p2m, gfn_add(gfn, i), &t, &a, 0, &cur_order, NULL); n = 1UL << min(order, cur_order); if ( p2m_is_pod(t) ) pod += n; - else if ( p2m_is_ram(t) ) + else if ( p2m_is_ram(t) && !is_special_page(mfn_to_page(mfn)) ) ram += n; } @@ -644,6 +645,9 @@ ASSERT(mfn_valid(mfn)); page = mfn_to_page(mfn); + if ( is_special_page(page) ) + /* Do not touch special pages, let generic code handle them. */ + continue; /* This shouldn't be able to fail */ if ( p2m_set_entry(p2m, gfn_add(gfn, i), INVALID_MFN, cur_order, diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm/p2m.c xen-4.20.3+127-gc42374a105/xen/arch/x86/mm/p2m.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm/p2m.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/mm/p2m.c 2026-07-28 12:08:27.000000000 +0000 @@ -464,6 +464,11 @@ ASSERT(p2m->domain); ASSERT(p2m->domain->arch.paging.free_page); + /* + * Issue any pending flush here, in case it was deferred before. The page + * will be returned to the paging pool now. + */ + p2m_tlb_flush_sync(p2m); page_list_del(pg, &p2m->pages); p2m->domain->arch.paging.free_page(p2m->domain, pg); @@ -1979,11 +1984,9 @@ break; case XENMAPSPACE_grant_table: - rc = gnttab_map_frame(d, idx, gfn, &mfn); + rc = gnttab_map_frame_begin(d, idx, gfn, &mfn); if ( rc ) return rc; - /* Need to take care of the reference obtained in gnttab_map_frame(). */ - page = mfn_to_page(mfn); break; case XENMAPSPACE_gmfn: @@ -2065,19 +2068,28 @@ put_gfn(d, gfn_x(gfn)); put_both: - /* - * In the XENMAPSPACE_gmfn case, we took a ref of the gfn at the top. - * We also may need to transfer ownership of the page reference to our - * caller. - */ - if ( space == XENMAPSPACE_gmfn ) + switch ( space ) { + case XENMAPSPACE_gmfn: + /* + * We took a ref of the gfn at the top. We also may need to transfer + * ownership of the page reference to our caller. + */ put_gfn(d, gmfn); if ( !rc && extra.ppage ) { *extra.ppage = page; page = NULL; } + break; + + case XENMAPSPACE_grant_table: + /* + * We (gnttab_map_frame_begin()) acquired a lock and took a ref of the + * page underlying the MFN at the top. + */ + gnttab_map_frame_end(d, mfn); + break; } if ( page ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm/paging.c xen-4.20.3+127-gc42374a105/xen/arch/x86/mm/paging.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm/paging.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/mm/paging.c 2026-07-28 12:08:27.000000000 +0000 @@ -709,10 +709,6 @@ return -EBUSY; } - rc = xsm_shadow_control(XSM_HOOK, d, sc->op); - if ( rc ) - return rc; - /* Code to handle log-dirty. Note that some log dirty operations * piggy-back on shadow operations. For example, when * XEN_DOMCTL_SHADOW_OP_OFF is called, it first checks whether log dirty @@ -767,7 +763,7 @@ if ( d == NULL ) return -ESRCH; - ret = xsm_domctl(XSM_OTHER, d, op.cmd, 0 /* SSIDref not applicable */); + ret = xsm_domctl(XSM_OTHER, d, &op); if ( !ret ) { if ( domctl_lock_acquire() ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm.c xen-4.20.3+127-gc42374a105/xen/arch/x86/mm.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/mm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/mm.c 2026-07-28 12:08:27.000000000 +0000 @@ -542,7 +542,7 @@ cpu_info->pv_cr3 = __pa(this_cpu(root_pgt)); if ( new_cr4 & X86_CR4_PCIDE ) cpu_info->pv_cr3 |= get_pcid_bits(v, true); - switch_cr3_cr4(v->arch.cr3, new_cr4); + switch_cr3_cr4(v, v->arch.cr3, new_cr4); } else { @@ -550,7 +550,7 @@ cpu_info->use_pv_cr3 = false; cpu_info->xen_cr3 = 0; /* switch_cr3_cr4() serializes. */ - switch_cr3_cr4(v->arch.cr3, new_cr4); + switch_cr3_cr4(v, v->arch.cr3, new_cr4); cpu_info->pv_cr3 = 0; } } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/platform_hypercall.c xen-4.20.3+127-gc42374a105/xen/arch/x86/platform_hypercall.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/platform_hypercall.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/platform_hypercall.c 2026-07-28 12:08:27.000000000 +0000 @@ -682,10 +682,6 @@ { int cpu = op->u.cpu_ol.cpuid; - ret = xsm_resource_plug_core(XSM_HOOK); - if ( ret ) - break; - if ( cpu >= nr_cpu_ids || !cpu_present(cpu) || clocksource_is_tsc() ) { @@ -708,10 +704,6 @@ { int cpu = op->u.cpu_ol.cpuid; - ret = xsm_resource_unplug_core(XSM_HOOK); - if ( ret ) - break; - if ( cpu == 0 ) { ret = -EOPNOTSUPP; @@ -736,20 +728,12 @@ } case XENPF_cpu_hotadd: - ret = xsm_resource_plug_core(XSM_HOOK); - if ( ret ) - break; - ret = cpu_add(op->u.cpu_add.apic_id, op->u.cpu_add.acpi_id, op->u.cpu_add.pxm); break; case XENPF_mem_hotadd: - ret = xsm_resource_plug_core(XSM_HOOK); - if ( ret ) - break; - ret = memory_add(op->u.mem_add.spfn, op->u.mem_add.epfn, op->u.mem_add.pxm); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/dom0_build.c xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/dom0_build.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/dom0_build.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/dom0_build.c 2026-07-28 12:08:27.000000000 +0000 @@ -502,14 +502,8 @@ return -EINVAL; } - if ( parms.elf_notes[XEN_ELFNOTE_SUPPORTED_FEATURES].type != XEN_ENT_NONE ) - { - if ( !pv_shim && !test_bit(XENFEAT_dom0, parms.f_supported) ) - { - printk("Kernel does not support Dom0 operation\n"); - return -EINVAL; - } - } + if ( (rc = initdom_check_parms(d, &parms)) != 0 ) + return rc; nr_pages = dom0_compute_nr_pages(d, &parms, initrd_len); @@ -842,8 +836,7 @@ update_cr3(v); /* We run on dom0's page tables for the final part of the build process. */ - switch_cr3_cr4(cr3_pa(v->arch.cr3), read_cr4()); - mapcache_override_current(v); + switch_cr3_cr4(v, cr3_pa(v->arch.cr3), read_cr4()); /* Copy the OS image and free temporary buffer. */ elf.dest_base = (void*)vkern_start; @@ -852,8 +845,7 @@ rc = elf_load_binary(&elf); if ( rc < 0 ) { - mapcache_override_current(NULL); - switch_cr3_cr4(current->arch.cr3, read_cr4()); + switch_cr3_cr4(current, current->arch.cr3, read_cr4()); printk("Failed to load the kernel binary\n"); goto out; } @@ -864,8 +856,7 @@ if ( (parms.virt_hypercall < v_start) || (parms.virt_hypercall >= v_end) ) { - mapcache_override_current(NULL); - switch_cr3_cr4(current->arch.cr3, read_cr4()); + switch_cr3_cr4(current, current->arch.cr3, read_cr4()); printk("Invalid HYPERCALL_PAGE field in ELF notes.\n"); return -EINVAL; } @@ -1006,8 +997,7 @@ #endif /* Return to idle domain's page tables. */ - mapcache_override_current(NULL); - switch_cr3_cr4(current->arch.cr3, read_cr4()); + switch_cr3_cr4(current, current->arch.cr3, read_cr4()); update_domain_wallclock_time(d); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/domain.c xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/domain.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/domain.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/domain.c 2026-07-28 12:08:27.000000000 +0000 @@ -449,6 +449,8 @@ pagetable_t old_shadow; unsigned long cr3; + ASSERT(local_irq_is_enabled()); + v->arch.flags ^= TF_kernel_mode; guest_update = v->arch.flags & TF_kernel_mode; old_shadow = update_cr3(v); @@ -471,15 +473,22 @@ { cr3 &= ~X86_CR3_NOFLUSH; + local_irq_disable(); if ( unlikely(mfn_eq(pagetable_get_mfn(old_shadow), maddr_to_mfn(cr3))) ) { - cr3 = idle_vcpu[v->processor]->arch.cr3; /* Also suppress runstate/time area updates below. */ guest_update = false; + + cr3 = idle_vcpu[v->processor]->arch.cr3; + this_cpu(pgtable_vcpu) = idle_vcpu[v->processor]; } + + write_cr3(cr3); + local_irq_enable(); } - write_cr3(cr3); + else + write_cr3(cr3); if ( !pagetable_is_null(old_shadow) ) shadow_put_top_level(v->domain, old_shadow); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/emul-gate-op.c xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/emul-gate-op.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/emul-gate-op.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/emul-gate-op.c 2026-07-28 12:08:27.000000000 +0000 @@ -284,12 +284,14 @@ if ( !jump ) { unsigned int ss, esp, *stkp; + uint32_t value; int rc; #define push(item) do \ { \ + value = (item); \ --stkp; \ esp -= 4; \ - rc = __put_guest(item, stkp); \ + rc = __copy_to_guest_pv(stkp, &value, sizeof(value)); \ if ( rc ) \ { \ pv_inject_page_fault(PFEC_write_access, \ @@ -357,7 +359,7 @@ unsigned int parm; --ustkp; - rc = __get_guest(parm, ustkp); + rc = __copy_from_guest_pv(&parm, ustkp, sizeof(parm)); if ( rc ) { pv_inject_page_fault(0, (unsigned long)(ustkp + 1) - rc); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/emul-priv-op.c xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/emul-priv-op.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/emul-priv-op.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/emul-priv-op.c 2026-07-28 12:08:27.000000000 +0000 @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -971,7 +972,7 @@ return X86EMUL_OKAY; case MSR_P6_PERFCTR(0) ... MSR_P6_PERFCTR(7): - case MSR_P6_EVNTSEL(0) ... MSR_P6_EVNTSEL(3): + case MSR_P6_EVNTSEL(0) ... MSR_P6_EVNTSEL(7): case MSR_CORE_PERF_FIXED_CTR0 ... MSR_CORE_PERF_FIXED_CTR2: case MSR_CORE_PERF_FIXED_CTR_CTRL ... MSR_CORE_PERF_GLOBAL_OVF_CTRL: if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) @@ -1148,7 +1149,7 @@ break; case MSR_P6_PERFCTR(0) ... MSR_P6_PERFCTR(7): - case MSR_P6_EVNTSEL(0) ... MSR_P6_EVNTSEL(3): + case MSR_P6_EVNTSEL(0) ... MSR_P6_EVNTSEL(7): case MSR_CORE_PERF_FIXED_CTR0 ... MSR_CORE_PERF_FIXED_CTR2: case MSR_CORE_PERF_FIXED_CTR_CTRL ... MSR_CORE_PERF_GLOBAL_OVF_CTRL: if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) @@ -1382,6 +1383,54 @@ } /* + * Hardware already decoded the INT $N instruction and determined that there + * was a permission issue (i.e. the DPL violation intended to trigger #GP). + * Xen has already determined that the guest kernel has permitted this + * software interrupt. + * + * All that is needed is the instruction length, to turn the fault into a + * trap. All errors are turned back into the original #GP, as that's the + * action that really happened. + */ +void pv_emulate_sw_interrupt(struct cpu_user_regs *regs) +{ + struct vcpu *curr = current; + struct domain *currd = curr->domain; + struct priv_op_ctxt ctxt = { + .ctxt.regs = regs, + .ctxt.lma = !is_pv_32bit_domain(currd), + }; + struct x86_emulate_state *state; + uint8_t vector = regs->error_code >> 3; + unsigned int len, ar; + + if ( !pv_emul_read_descriptor(regs->cs, curr, &ctxt.cs.base, + &ctxt.cs.limit, &ar, 1) || + !(ar & _SEGMENT_S) || + !(ar & _SEGMENT_P) || + !(ar & _SEGMENT_CODE) ) + goto error; + + state = x86_decode_insn(&ctxt.ctxt, insn_fetch); + if ( IS_ERR_OR_NULL(state) ) + goto error; + + len = x86_insn_length(state, &ctxt.ctxt); + x86_emulate_free_state(state); + + /* Note: Checked slightly late to simplify 'state' handling. */ + if ( ctxt.ctxt.opcode != 0xcd /* INT $imm8 */ ) + goto error; + + regs->rip += len; + pv_inject_sw_interrupt(vector); + return; + + error: + pv_inject_hw_exception(X86_EXC_GP, regs->error_code); +} + +/* * Local variables: * mode: C * c-file-style: "BSD" diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/mm.c xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/mm.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/pv/mm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/pv/mm.c 2026-07-28 12:08:27.000000000 +0000 @@ -52,7 +52,7 @@ struct vcpu *curr = current; struct domain *currd = curr->domain; struct page_info *page; - l1_pgentry_t gl1e, *pl1e; + l1_pgentry_t gl1e, *pl1e, nl1e; unsigned long linear = curr->arch.pv.ldt_base + offset; BUG_ON(in_irq()); @@ -87,9 +87,9 @@ } pl1e = &pv_ldt_ptes(curr)[offset >> PAGE_SHIFT]; - l1e_add_flags(gl1e, _PAGE_RW); + nl1e = l1e_from_pfn(l1e_get_pfn(gl1e), __PAGE_HYPERVISOR_RW); - l1e_write(pl1e, gl1e); + l1e_write(pl1e, nl1e); return true; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/setup.c xen-4.20.3+127-gc42374a105/xen/arch/x86/setup.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/setup.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/setup.c 2026-07-28 12:08:27.000000000 +0000 @@ -904,10 +904,19 @@ if ( cpu_has_xen_shstk ) { + /* + * Immediately after enabling CET, SSP is 0 and most interrupts and + * exceptions are fatal. Like the SYSCALL/SYSENTER gaps, IST vectors + * (including NMI and #MC) are safe owing to IST switching the shstk. + */ + local_irq_disable(); + wrmsrl(MSR_PL0_SSP, (unsigned long)stack + (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8); wrmsrl(MSR_S_CET, xen_msr_s_cet_value()); asm volatile ("setssbsy" ::: "memory"); + + local_irq_enable(); } reset_stack_and_jump(init_done); @@ -2015,9 +2024,7 @@ init_idle_domain(); - this_cpu(stubs.addr) = alloc_stub_page(smp_processor_id(), - &this_cpu(stubs).mfn); - BUG_ON(!this_cpu(stubs.addr)); + init_stubs(); trap_init(); @@ -2264,9 +2271,12 @@ return; bitmap_fill(d->arch.hvm.io_bitmap, 0x10000); + + read_lock(&d->caps_lock); if ( rangeset_report_ranges(d->arch.ioport_caps, 0, 0x10000, io_bitmap_cb, d) ) BUG(); + read_unlock(&d->caps_lock); /* * We need to trap 4-byte accesses to 0xcf8 (see admin_io_okay(), diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/smpboot.c xen-4.20.3+127-gc42374a105/xen/arch/x86/smpboot.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/smpboot.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/smpboot.c 2026-07-28 12:08:27.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -330,6 +331,7 @@ set_current(idle_vcpu[cpu]); this_cpu(curr_vcpu) = idle_vcpu[cpu]; + this_cpu(pgtable_vcpu) = idle_vcpu[cpu]; rdmsrl(MSR_EFER, this_cpu(efer)); init_shadow_spec_ctrl_state(); @@ -650,41 +652,64 @@ return rc; } -#define STUB_BUF_CPU_OFFS(cpu) (((cpu) & (STUBS_PER_PAGE - 1)) * STUB_BUF_SIZE) +/* Dynamically allocated, indexed by CPU. Store physical address of stubs. */ +static paddr_t *__ro_after_init stubs; -unsigned long alloc_stub_page(unsigned int cpu, unsigned long *mfn) +static bool assign_stub_page(unsigned int cpu) { unsigned long stub_va; - struct page_info *pg; + paddr_t addr = stubs[cpu]; - BUILD_BUG_ON(STUBS_PER_PAGE & (STUBS_PER_PAGE - 1)); - - if ( *mfn ) - pg = mfn_to_page(_mfn(*mfn)); - else + if ( addr == INVALID_PADDR ) { - nodeid_t node = cpu_to_node(cpu); - unsigned int memflags = node != NUMA_NO_NODE ? MEMF_node(node) : 0; + nodeid_t nid = cpu_to_node(cpu); + + /* + * Attempt to use the same page as the previous CPU if possible, + * otherwise allocate a new one. + */ + if ( cpu && nid == cpu_to_node(cpu - 1) && + stubs[cpu - 1] != INVALID_PADDR && + PAGE_OFFSET(stubs[cpu - 1] + STUB_BUF_SIZE) ) + addr = stubs[cpu - 1] + STUB_BUF_SIZE; + else + { + struct page_info *pg = alloc_domheap_page(NULL, MEMF_node(nid)); - pg = alloc_domheap_page(NULL, memflags); - if ( !pg ) - return 0; + if ( !pg ) + return false; - unmap_domain_page(memset(__map_domain_page(pg), 0xcc, PAGE_SIZE)); + unmap_domain_page(memset(__map_domain_page(pg), 0xcc, PAGE_SIZE)); + addr = page_to_maddr(pg); + } + stubs[cpu] = addr; } stub_va = XEN_VIRT_END - FIXADDR_X_SIZE - (cpu + 1) * PAGE_SIZE; - if ( map_pages_to_xen(stub_va, page_to_mfn(pg), 1, + if ( map_pages_to_xen(stub_va, maddr_to_mfn(addr), 1, PAGE_HYPERVISOR_RX | MAP_SMALL_PAGES) ) - { - if ( !*mfn ) - free_domheap_page(pg); - stub_va = 0; - } - else if ( !*mfn ) - *mfn = mfn_x(page_to_mfn(pg)); + return false; + + per_cpu(stubs.mfn, cpu) = PFN_DOWN(addr); + per_cpu(stubs.addr, cpu) = stub_va + PAGE_OFFSET(addr); + return true; +} + +void __init init_stubs(void) +{ + const unsigned int num_cpus = num_present_cpus(); + unsigned int i; + + ASSERT(!stubs); + stubs = xvmalloc_array(typeof(*stubs), num_cpus); + if ( !stubs ) + panic("Unable to allocate stub array\n"); - return stub_va; + for ( i = 0; i < num_cpus; i++ ) + stubs[i] = INVALID_PADDR; + + if ( !assign_stub_page(0) ) + panic("Unable to initialize BSP stub region\n"); } void cpu_exit_clear(unsigned int cpu) @@ -1004,19 +1029,12 @@ { mfn_t mfn = _mfn(per_cpu(stubs.mfn, cpu)); unsigned char *stub_page = map_domain_page(mfn); - unsigned int i; - memset(stub_page + STUB_BUF_CPU_OFFS(cpu), 0xcc, STUB_BUF_SIZE); - for ( i = 0; i < STUBS_PER_PAGE; ++i ) - if ( stub_page[i * STUB_BUF_SIZE] != 0xcc ) - break; + memset(stub_page + PAGE_OFFSET(stubs[cpu]), 0xcc, STUB_BUF_SIZE); unmap_domain_page(stub_page); destroy_xen_mappings(per_cpu(stubs.addr, cpu) & PAGE_MASK, (per_cpu(stubs.addr, cpu) | ~PAGE_MASK) + 1); per_cpu(stubs.addr, cpu) = 0; - per_cpu(stubs.mfn, cpu) = 0; - if ( i == STUBS_PER_PAGE ) - free_domheap_page(mfn_to_page(mfn)); } if ( IS_ENABLED(CONFIG_PV32) ) @@ -1055,10 +1073,9 @@ static int cpu_smpboot_alloc(unsigned int cpu) { struct cpu_info *info; - unsigned int i, memflags = 0; + unsigned int memflags = 0; nodeid_t node = cpu_to_node(cpu); seg_desc_t *gdt; - unsigned long stub_page; int rc = -ENOMEM; if ( node != NUMA_NO_NODE ) @@ -1099,18 +1116,8 @@ memcpy(idt_tables[cpu], idt_table, IDT_ENTRIES * sizeof(idt_entry_t)); disable_each_ist(idt_tables[cpu]); - for ( stub_page = 0, i = cpu & ~(STUBS_PER_PAGE - 1); - i < nr_cpu_ids && i <= (cpu | (STUBS_PER_PAGE - 1)); ++i ) - if ( cpu_online(i) && cpu_to_node(i) == node ) - { - per_cpu(stubs.mfn, cpu) = per_cpu(stubs.mfn, i); - break; - } - BUG_ON(i == cpu); - stub_page = alloc_stub_page(cpu, &per_cpu(stubs.mfn, cpu)); - if ( !stub_page ) + if ( !assign_stub_page(cpu) ) goto out; - per_cpu(stubs.addr, cpu) = stub_page + STUB_BUF_CPU_OFFS(cpu); rc = setup_cpu_root_pgt(cpu); if ( rc ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/sysctl.c xen-4.20.3+127-gc42374a105/xen/arch/x86/sysctl.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/sysctl.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/sysctl.c 2026-07-28 12:08:27.000000000 +0000 @@ -117,20 +117,17 @@ { unsigned int cpu = sysctl->u.cpu_hotplug.cpu; unsigned int op = sysctl->u.cpu_hotplug.op; - bool plug; long (*fn)(void *data); void *hcpu; switch ( op ) { case XEN_SYSCTL_CPU_HOTPLUG_ONLINE: - plug = true; fn = cpu_up_helper; hcpu = _p(cpu); break; case XEN_SYSCTL_CPU_HOTPLUG_OFFLINE: - plug = false; fn = cpu_down_helper; hcpu = _p(cpu); break; @@ -150,9 +147,8 @@ if ( CONFIG_NR_CPUS <= 1 ) /* Mimic behavior of smt_up_down_helper(). */ return 0; - plug = op == XEN_SYSCTL_CPU_HOTPLUG_SMT_ENABLE; fn = smt_up_down_helper; - hcpu = _p(plug); + hcpu = _p(op == XEN_SYSCTL_CPU_HOTPLUG_SMT_ENABLE); break; default: @@ -161,10 +157,6 @@ } if ( !ret ) - ret = plug ? xsm_resource_plug_core(XSM_HOOK) - : xsm_resource_unplug_core(XSM_HOOK); - - if ( !ret ) ret = continue_hypercall_on_cpu(0, fn, hcpu); } break; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/time.c xen-4.20.3+127-gc42374a105/xen/arch/x86/time.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/time.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/time.c 2026-07-28 12:08:27.000000000 +0000 @@ -515,7 +515,7 @@ bool disable_hpet = false; if ( hpet_address && strcmp(opt_clocksource, pts->id) && - cpuidle_using_deep_cstate() ) + cpuidle_usable_deep_cstate() ) { if ( pci_conf_read16(PCI_SBDF(0, 0, 0x1f, 0), PCI_VENDOR_ID) == PCI_VENDOR_ID_INTEL ) @@ -1702,17 +1702,25 @@ else { if ( is_hvm_domain(d) && hvm_tsc_scaling_supported ) - { tsc_stamp = hvm_scale_tsc(d, t->stamp.local_tsc); - u->tsc_to_system_mul = d->arch.vtsc_to_ns.mul_frac; - u->tsc_shift = d->arch.vtsc_to_ns.shift; - } else - { tsc_stamp = t->stamp.local_tsc; + + /* + * HVM guests using the native TSC ratio should use the same per-CPU + * scaling factors as Xen. This ensures time keeping is always in sync + * between Xen and the guest. + */ + if ( tsc_stamp == t->stamp.local_tsc ) + { u->tsc_to_system_mul = t->tsc_scale.mul_frac; u->tsc_shift = t->tsc_scale.shift; } + else + { + u->tsc_to_system_mul = d->arch.vtsc_to_ns.mul_frac; + u->tsc_shift = d->arch.vtsc_to_ns.shift; + } } u->tsc_timestamp = tsc_stamp; @@ -2559,6 +2567,8 @@ /* Late init function (after interrupts are enabled). */ int __init init_xen_time(void) { + unsigned long wc; + tsc_check_writability(); open_softirq(TIME_CALIBRATE_SOFTIRQ, local_time_calibration); @@ -2576,7 +2586,8 @@ printk(XENLOG_INFO "Wallclock source: %s\n", wallclock_type_to_string()); /* NB. get_wallclock_time() can take over one second to execute. */ - do_settime(get_wallclock_time(), 0, NOW()); + wc = get_wallclock_time(); + do_settime(wc, 0, NOW()); /* Finish platform timer initialization. */ try_platform_timer_tail(); @@ -2626,7 +2637,7 @@ set_time_scale(&t->tsc_scale, tmp); t->stamp.local_tsc = boot_tsc_stamp; - cpu_khz = tmp / 1000; + cpu_khz = DIV_ROUND(tmp, 1000); printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); @@ -2647,7 +2658,7 @@ * XXX dom0 may rely on RTC interrupt delivery, so only enable * hpet_broadcast if FSB mode available or if force_hpet_broadcast. */ - if ( cpuidle_using_deep_cstate() && !boot_cpu_has(X86_FEATURE_ARAT) ) + if ( cpuidle_usable_deep_cstate() && !boot_cpu_has(X86_FEATURE_ARAT) ) { init ? hpet_broadcast_init() : hpet_broadcast_resume(); if ( !hpet_broadcast_is_available() ) @@ -2699,11 +2710,6 @@ reprogram_timer(this_cpu(timer_deadline)); } -int pit_broadcast_is_available(void) -{ - return cpuidle_using_deep_cstate(); -} - void send_timer_event(struct vcpu *v) { send_guest_vcpu_virq(v, VIRQ_TIMER); @@ -2720,7 +2726,7 @@ { cmos_utc_offset = -get_wallclock_time(); cmos_utc_offset += get_sec(); - kill_timer(&calibration_timer); + stop_timer(&calibration_timer); /* Sync platform timer stamps. */ platform_time_calibration(); @@ -2734,6 +2740,8 @@ int time_resume(void) { + unsigned long wc; + preinit_pit(); resume_platform_timer(); @@ -2745,7 +2753,8 @@ set_timer(&calibration_timer, NOW() + EPOCH); - do_settime(get_wallclock_time() + cmos_utc_offset, 0, NOW()); + wc = get_wallclock_time(); + do_settime(wc + cmos_utc_offset, 0, NOW()); update_vcpu_system_time(current); @@ -3006,7 +3015,7 @@ else if ( boot_cpu_has(X86_FEATURE_CONSTANT_TSC ) ) { printk("TSC has constant rate, "); - if ( max_cstate <= ACPI_STATE_C2 && tsc_max_warp == 0 ) + if ( max_usable_cstate <= ACPI_STATE_C2 && tsc_max_warp == 0 ) printk("no deep Cstates, passed warp test, deemed reliable, "); else printk("deep Cstates possible, so not reliable, "); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/traps.c xen-4.20.3+127-gc42374a105/xen/arch/x86/traps.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/traps.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/traps.c 2026-07-28 12:08:27.000000000 +0000 @@ -1298,8 +1298,7 @@ if ( permit_softint(TI_GET_DPL(ti), v, regs) ) { - regs->rip += 2; - pv_inject_sw_interrupt(vector); + pv_emulate_sw_interrupt(regs); return; } } diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/x86_64/mmconfig-shared.c xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/mmconfig-shared.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/x86_64/mmconfig-shared.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/mmconfig-shared.c 2026-07-28 12:08:27.000000000 +0000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -367,12 +368,15 @@ typeof(pci_mmcfg_config[0]) *cfg; int i; bool valid = true; + int year; if ((pci_mmcfg_config_num == 0) || (pci_mmcfg_config == NULL) || (pci_mmcfg_config[0].address == 0)) return 0; + dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL); + for (i = 0; i < pci_mmcfg_config_num; i++) { u64 addr, size; @@ -388,7 +392,13 @@ (unsigned int)cfg->start_bus_number, (unsigned int)cfg->end_bus_number); - if (!is_mmconf_reserved(addr, size, i, cfg) || + /* + * For firmwares prior to 2016, confirm that MMCFG is marked as + * reserved. For 2016 and later, also allow MMCFG being in a hole. + */ + if (((year < 2016 || !is_memory_hole(maddr_to_mfn(addr), + maddr_to_mfn(addr + size - 1))) && + !is_mmconf_reserved(addr, size, i, cfg)) || pci_mmcfg_arch_enable(i)) { pci_mmcfg_arch_disable(i); valid = 0; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/x86_emulate/decode.c xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_emulate/decode.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/x86_emulate/decode.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_emulate/decode.c 2026-07-28 12:08:27.000000000 +0000 @@ -775,12 +775,12 @@ break; case 0x20: case 0x22: /* mov to/from cr */ - if ( s->lock_prefix && vcpu_has_cr8_legacy() ) + if ( s->lock_prefix && vcpu_has_cr8_legacy() && s->modrm_reg == 0 ) { - s->modrm_reg += 8; + s->modrm_reg = 8; s->lock_prefix = false; } - /* fall through */ + fallthrough; case 0x21: case 0x23: /* mov to/from dr */ ASSERT(s->ea.type == OP_REG); /* Early operand adjustment ensures this. */ generate_exception_if(s->lock_prefix, X86_EXC_UD); diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/x86_emulate/x86_emulate.c xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_emulate/x86_emulate.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/x86_emulate/x86_emulate.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_emulate/x86_emulate.c 2026-07-28 12:08:27.000000000 +0000 @@ -6172,9 +6172,11 @@ ASSERT(op_bytes == n * elem_bytes); op_mask &= ~0ULL >> (64 - n); n = hweight64(op_mask); - op_bytes = n * elem_bytes; if ( n ) + { + op_bytes = n * elem_bytes; op_mask = ~0ULL >> (64 - n); + } } goto simd_zmm; diff -Nru xen-4.20.2+37-g61ff35323e/xen/arch/x86/xstate.c xen-4.20.3+127-gc42374a105/xen/arch/x86/xstate.c --- xen-4.20.2+37-g61ff35323e/xen/arch/x86/xstate.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/arch/x86/xstate.c 2026-07-28 12:08:27.000000000 +0000 @@ -542,11 +542,22 @@ return -ENOMEM; /* - * Set the memory image to default values, but don't force the context - * to be loaded from memory (i.e. keep save_area->xsave_hdr.xstate_bv - * clear). + * We're creating a vCPU, so conceptually we should be choosing the + * architectural #RESET values. + * + * However for historical reasons of configuring the external + * co-processor, FCW's #RESET state is different to what F(N)INIT and + * XSTATE consider the "initial configuration". + * + * Guests won't care about the difference; all software tends to executes + * FNINIT very early during setup. + * + * Use XSTATE's idea of initial configuration. This allows XSTATE_BV to + * remain clear and for CPUs to use the INIT optimisation where + * applicable. */ save_area->fpu_sse.fcw = FCW_DEFAULT; + save_area->fpu_sse.ftw = FXSAVE_FTW_RESET; save_area->fpu_sse.mxcsr = MXCSR_DEFAULT; v->arch.xsave_area = save_area; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/device-tree/bootfdt.c xen-4.20.3+127-gc42374a105/xen/common/device-tree/bootfdt.c --- xen-4.20.2+37-g61ff35323e/xen/common/device-tree/bootfdt.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/device-tree/bootfdt.c 2026-07-28 12:08:27.000000000 +0000 @@ -250,23 +250,28 @@ { printk("Warning: device tree node `%s' is nested too deep\n", name); - continue; } + else + { + as = depth > 0 ? + address_cells[depth - 1] : + DT_ROOT_NODE_ADDR_CELLS_DEFAULT; + ss = depth > 0 ? + size_cells[depth - 1] : + DT_ROOT_NODE_SIZE_CELLS_DEFAULT; - as = depth > 0 ? address_cells[depth-1] : DT_ROOT_NODE_ADDR_CELLS_DEFAULT; - ss = depth > 0 ? size_cells[depth-1] : DT_ROOT_NODE_SIZE_CELLS_DEFAULT; - - address_cells[depth] = device_tree_get_u32(fdt, node, - "#address-cells", as); - size_cells[depth] = device_tree_get_u32(fdt, node, - "#size-cells", ss); + address_cells[depth] = device_tree_get_u32(fdt, node, + "#address-cells", as); + size_cells[depth] = device_tree_get_u32(fdt, node, + "#size-cells", ss); - /* skip the first node */ - if ( node != first_node ) - { - ret = func(fdt, node, name, depth, as, ss, data); - if ( ret != 0 ) - return ret; + /* skip the first node */ + if ( node != first_node ) + { + ret = func(fdt, node, name, depth, as, ss, data); + if ( ret != 0 ) + return ret; + } } node = fdt_next_node(fdt, node, &depth); diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/dm.c xen-4.20.3+127-gc42374a105/xen/common/dm.c --- xen-4.20.2+37-g61ff35323e/xen/common/dm.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/dm.c 2026-07-28 12:08:27.000000000 +0000 @@ -26,6 +26,9 @@ struct dmop_args args; int rc; + if ( !nr_bufs ) + return -ENODATA; + if ( nr_bufs > ARRAY_SIZE(args.buf) ) return -E2BIG; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/domain.c xen-4.20.3+127-gc42374a105/xen/common/domain.c --- xen-4.20.2+37-g61ff35323e/xen/common/domain.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/domain.c 2026-07-28 12:08:27.000000000 +0000 @@ -316,14 +316,14 @@ set_bit(_VPF_down, &v->pause_flags); vcpu_info_reset(v); init_waitqueue_vcpu(v); + + if ( vmtrace_alloc_buffer(v) != 0 ) + goto fail_wq; } if ( sched_init_vcpu(v) != 0 ) goto fail_wq; - if ( vmtrace_alloc_buffer(v) != 0 ) - goto fail_wq; - if ( arch_vcpu_create(v) != 0 ) goto fail_sched; @@ -386,10 +386,15 @@ * may be modified after this hypercall returns if a more complex * device model is desired. */ + write_lock(&dom0->caps_lock); rangeset_swap(d->irq_caps, dom0->irq_caps); rangeset_swap(d->iomem_caps, dom0->iomem_caps); #ifdef CONFIG_X86 rangeset_swap(d->arch.ioport_caps, dom0->arch.ioport_caps); +#endif + write_unlock(&dom0->caps_lock); + +#ifdef CONFIG_X86 setup_io_bitmap(d); setup_io_bitmap(dom0); #endif @@ -446,18 +451,6 @@ } custom_param("dom0", parse_dom0_param); -static void domain_pending_scrub_free(struct domain *d) -{ - rspin_lock(&d->page_alloc_lock); - if ( d->pending_scrub ) - { - FREE_DOMHEAP_PAGES(d->pending_scrub, d->pending_scrub_order); - d->pending_scrub_order = 0; - d->pending_scrub_index = 0; - } - rspin_unlock(&d->page_alloc_lock); -} - /* * Release resources held by a domain. There may or may not be live * references to the domain, and it may or may not be fully constructed. @@ -517,9 +510,6 @@ case PROG_none: BUILD_BUG_ON(PROG_none != 0); - /* Trivial teardown, not long-running enough to need a preemption check. */ - domain_pending_scrub_free(d); - PROGRESS(gnttab_mappings): rc = gnttab_release_mappings(d); if ( rc ) @@ -562,7 +552,6 @@ { BUG_ON(!d->is_dying); BUG_ON(atomic_read(&d->refcnt) != DOMAIN_DESTROYED); - ASSERT(!d->pending_scrub); xfree(d->pbuf); @@ -733,6 +722,7 @@ rspin_lock_init_prof(d, domain_lock); rspin_lock_init_prof(d, page_alloc_lock); spin_lock_init(&d->hypercall_deadlock_mutex); + rwlock_init(&d->caps_lock); INIT_PAGE_LIST_HEAD(&d->page_list); INIT_PAGE_LIST_HEAD(&d->extra_page_list); INIT_PAGE_LIST_HEAD(&d->xenpage_list); @@ -1097,7 +1087,7 @@ d->is_dying = DOMDYING_dying; rspin_barrier(&d->domain_lock); argo_destroy(d); - vnuma_destroy(d->vnuma); + vnuma_replace(d, NULL); domain_set_outstanding_pages(d, 0); /* fallthrough */ case DOMDYING_dying: @@ -1494,15 +1484,6 @@ */ if ( new == 0 && !d->creation_finished ) { - if ( d->pending_scrub ) - { - printk(XENLOG_ERR - "%pd: cannot be started with pending unscrubbed pages, destroying\n", - d); - domain_crash(d); - domain_pending_scrub_free(d); - return -EBUSY; - } d->creation_finished = true; arch_domain_creation_finished(d); } diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/domctl.c xen-4.20.3+127-gc42374a105/xen/common/domctl.c --- xen-4.20.2+37-g61ff35323e/xen/common/domctl.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/domctl.c 2026-07-28 12:08:27.000000000 +0000 @@ -154,7 +154,7 @@ spin_unlock(¤t->domain->hypercall_deadlock_mutex); } -void vnuma_destroy(struct vnuma_info *vnuma) +static void vnuma_destroy(struct vnuma_info *vnuma) { if ( vnuma ) { @@ -166,6 +166,19 @@ } } +/* Overwrite (replace) vnuma topology for a domain. */ +void vnuma_replace(struct domain *d, struct vnuma_info *vnuma) +{ + struct vnuma_info *old; + + write_lock(&d->vnuma_rwlock); + old = d->vnuma; + d->vnuma = vnuma; + write_unlock(&d->vnuma_rwlock); + + vnuma_destroy(old); +} + /* * Allocates memory for vNUMA, **vnuma should be NULL. * Caller has to make sure that domain has max_pages @@ -279,6 +292,35 @@ return ERR_PTR(ret); } +void iocaps_double_lock(struct domain *d, bool write) +{ + struct domain *currd = current->domain; + + if ( d->domain_id > currd->domain_id ) + read_lock(&currd->caps_lock); + + if ( write ) + write_lock(&d->caps_lock); + else + read_lock(&d->caps_lock); + + if ( d->domain_id < currd->domain_id ) + read_lock(&currd->caps_lock); +} + +void iocaps_double_unlock(struct domain *d, bool write) +{ + struct domain *currd = current->domain; + + if ( d != currd ) + read_unlock(&currd->caps_lock); + + if ( write ) + write_unlock(&d->caps_lock); + else + read_unlock(&d->caps_lock); +} + long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) { long ret = 0; @@ -302,6 +344,10 @@ case XEN_DOMCTL_deassign_device: if ( op->domain == DOMID_IO ) { +#ifdef CONFIG_HAS_DEVICE_TREE + if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT ) + op->u.assign_device.u.dt.dev = NULL; +#endif d = dom_io; break; } @@ -309,6 +355,11 @@ return -ESRCH; fallthrough; case XEN_DOMCTL_test_assign_device: +#ifdef CONFIG_HAS_DEVICE_TREE + if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT ) + op->u.assign_device.u.dt.dev = NULL; + fallthrough; +#endif case XEN_DOMCTL_vm_event_op: if ( op->domain == DOMID_INVALID ) { @@ -323,9 +374,200 @@ break; } - ret = xsm_domctl(XSM_OTHER, d, op->cmd, - /* SSIDRef only applicable for cmd == createdomain */ - op->u.createdomain.ssidref); + /* Handle sub-ops not requiring the domctl lock. */ + switch ( op->cmd ) + { + case XEN_DOMCTL_getdomaininfo: + ret = xsm_getdomaininfo(XSM_XS_PRIV, d); + if ( !ret ) + { + getdomaininfo(d, &op->u.getdomaininfo); + + ASSERT(op->domain == op->u.getdomaininfo.domain); + copyback = true; + } + + goto domctl_out_unlock_domonly; + + case XEN_DOMCTL_iomem_permission: + { + unsigned long mfn = op->u.iomem_permission.first_mfn; + unsigned long nr_mfns = op->u.iomem_permission.nr_mfns; + bool allow = op->u.iomem_permission.allow_access; + + ret = -EINVAL; + if ( (mfn + nr_mfns - 1) < mfn ) /* Wrap? */ + goto domctl_out_unlock_domonly; + + ret = xsm_iomem_permission(XSM_PRIV, d, mfn, mfn + nr_mfns - 1, allow); + if ( ret ) + goto domctl_out_unlock_domonly; + + iocaps_double_lock(d, true); + + if ( !iomem_access_permitted(current->domain, + mfn, mfn + nr_mfns - 1) ) + ret = -EPERM; + else if ( allow ) + ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1); + else + ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1); + + iocaps_double_unlock(d, true); + goto domctl_out_unlock_domonly; + } + + case XEN_DOMCTL_memory_mapping: + { + unsigned long gfn = op->u.memory_mapping.first_gfn; + unsigned long mfn = op->u.memory_mapping.first_mfn; + unsigned long nr_mfns = op->u.memory_mapping.nr_mfns; + unsigned long mfn_end = mfn + nr_mfns - 1; + bool add = op->u.memory_mapping.add_mapping; + + ret = -EINVAL; + if ( mfn_end < mfn || /* Wrap? */ + ((mfn | mfn_end) >> (paddr_bits - PAGE_SHIFT)) || + (gfn + nr_mfns - 1) < gfn ) /* Wrap? */ + goto domctl_out_unlock_domonly; + + ret = xsm_iomem_mapping(XSM_DM_PRIV, d, mfn, mfn_end, add); + if ( ret || !paging_mode_translate(d) ) + goto domctl_out_unlock_domonly; + +#ifndef CONFIG_X86 /* XXX ARM!? */ + ret = -E2BIG; + /* Must break hypercall up as this could take a while. */ + if ( nr_mfns > 64 ) + goto domctl_out_unlock_domonly; +#endif + + iocaps_double_lock(d, false); + + ret = -EPERM; + if ( !iomem_access_permitted(current->domain, mfn, mfn_end) || + !iomem_access_permitted(d, mfn, mfn_end) ) + /* Nothing. */; + else if ( add ) + { + printk(XENLOG_G_DEBUG + "memory_map:add: %pd gfn=%lx mfn=%lx nr=%lx\n", + d, gfn, mfn, nr_mfns); + + ret = map_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); + if ( ret < 0 ) + printk(XENLOG_G_WARNING + "memory_map:fail: %pd gfn=%lx mfn=%lx nr=%lx ret:%ld\n", + d, gfn, mfn, nr_mfns, ret); + } + else + { + printk(XENLOG_G_DEBUG + "memory_map:remove: %pd gfn=%lx mfn=%lx nr=%lx\n", + d, gfn, mfn, nr_mfns); + + ret = unmap_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); + if ( ret < 0 && is_hardware_domain(current->domain) ) + printk(XENLOG_ERR + "memory_map: error %ld removing %pd access to [%lx,%lx]\n", + ret, d, mfn, mfn_end); + } + + iocaps_double_unlock(d, false); + goto domctl_out_unlock_domonly; + } + +#ifdef CONFIG_HAS_PIRQ + case XEN_DOMCTL_irq_permission: + { + unsigned int pirq = op->u.irq_permission.pirq, irq; + bool allow = op->u.irq_permission.allow_access; + + ret = -EINVAL; + if ( pirq >= current->domain->nr_pirqs ) + goto domctl_out_unlock_domonly; + + irq = domain_pirq_to_irq(current->domain, pirq); + + ret = -EPERM; + if ( irq ) + ret = xsm_irq_permission(XSM_PRIV, d, irq, allow); + if ( ret ) + goto domctl_out_unlock_domonly; + + iocaps_double_lock(d, true); + + if ( !irq_access_permitted(current->domain, irq) ) + ret = -EPERM; + else if ( allow ) + ret = irq_permit_access(d, irq); + else + ret = irq_deny_access(d, irq); + + iocaps_double_unlock(d, true); + goto domctl_out_unlock_domonly; + } +#endif + + case XEN_DOMCTL_set_target: + { + struct domain *e = get_domain_by_id(op->u.set_target.target); + + ret = -ESRCH; + if ( !e ) + goto domctl_out_unlock_domonly; + + if ( d == e ) + ret = -EINVAL; + else if ( !is_hvm_domain(e) ) + ret = -EOPNOTSUPP; + else + ret = xsm_set_target(XSM_PRIV, d, e); + + /* Hold reference on @e until we destroy @d. */ + if ( !ret && cmpxchgptr(&d->target, NULL, e) ) + ret = -EINVAL; + + if ( ret ) + put_domain(e); + goto domctl_out_unlock_domonly; + } + + case XEN_DOMCTL_vm_event_op: + if ( op->u.vm_event_op.op == XEN_VM_EVENT_GET_VERSION ) + { + /* No XSM check (and potentially d == NULL) here. */ + ret = vm_event_domctl(d, &op->u.vm_event_op); + if ( !ret ) + copyback = true; + goto domctl_out_unlock_domonly; + } + if ( !d ) + { + ret = -ESRCH; + goto domctl_out_unlock_domonly; + } + /* Other sub-ops handled further down. */ + break; + + case XEN_DOMCTL_get_device_group: + ret = iommu_do_domctl(op, d, u_domctl); + goto domctl_out_unlock_domonly; + + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_gsi_permission: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + ret = arch_do_domctl(op, d, u_domctl); + goto domctl_out_unlock_domonly; + + default: + /* Everything else handled further down. */ + break; + } + + ret = xsm_domctl(XSM_OTHER, d, op); if ( ret ) goto domctl_out_unlock_domonly; @@ -539,17 +781,6 @@ copyback = 1; break; - case XEN_DOMCTL_getdomaininfo: - ret = xsm_getdomaininfo(XSM_XS_PRIV, d); - if ( ret ) - break; - - getdomaininfo(d, &op->u.getdomaininfo); - - op->domain = op->u.getdomaininfo.domain; - copyback = 1; - break; - case XEN_DOMCTL_getvcpucontext: { vcpu_guest_context_u c = { .nat = NULL }; @@ -655,143 +886,10 @@ } break; -#ifdef CONFIG_HAS_PIRQ - case XEN_DOMCTL_irq_permission: - { - unsigned int pirq = op->u.irq_permission.pirq, irq; - int allow = op->u.irq_permission.allow_access; - - if ( pirq >= current->domain->nr_pirqs ) - { - ret = -EINVAL; - break; - } - irq = pirq_access_permitted(current->domain, pirq); - if ( !irq || xsm_irq_permission(XSM_HOOK, d, irq, allow) ) - ret = -EPERM; - else if ( allow ) - ret = irq_permit_access(d, irq); - else - ret = irq_deny_access(d, irq); - break; - } -#endif - - case XEN_DOMCTL_iomem_permission: - { - unsigned long mfn = op->u.iomem_permission.first_mfn; - unsigned long nr_mfns = op->u.iomem_permission.nr_mfns; - int allow = op->u.iomem_permission.allow_access; - - ret = -EINVAL; - if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */ - break; - - if ( !iomem_access_permitted(current->domain, - mfn, mfn + nr_mfns - 1) || - xsm_iomem_permission(XSM_HOOK, d, mfn, mfn + nr_mfns - 1, allow) ) - ret = -EPERM; - else if ( allow ) - ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1); - else - ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1); - break; - } - - case XEN_DOMCTL_memory_mapping: - { - unsigned long gfn = op->u.memory_mapping.first_gfn; - unsigned long mfn = op->u.memory_mapping.first_mfn; - unsigned long nr_mfns = op->u.memory_mapping.nr_mfns; - unsigned long mfn_end = mfn + nr_mfns - 1; - int add = op->u.memory_mapping.add_mapping; - - ret = -EINVAL; - if ( mfn_end < mfn || /* wrap? */ - ((mfn | mfn_end) >> (paddr_bits - PAGE_SHIFT)) || - (gfn + nr_mfns - 1) < gfn ) /* wrap? */ - break; - -#ifndef CONFIG_X86 /* XXX ARM!? */ - ret = -E2BIG; - /* Must break hypercall up as this could take a while. */ - if ( nr_mfns > 64 ) - break; -#endif - - ret = -EPERM; - if ( !iomem_access_permitted(current->domain, mfn, mfn_end) || - !iomem_access_permitted(d, mfn, mfn_end) ) - break; - - ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add); - if ( ret ) - break; - - if ( !paging_mode_translate(d) ) - break; - - if ( add ) - { - printk(XENLOG_G_DEBUG - "memory_map:add: dom%d gfn=%lx mfn=%lx nr=%lx\n", - d->domain_id, gfn, mfn, nr_mfns); - - ret = map_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); - if ( ret < 0 ) - printk(XENLOG_G_WARNING - "memory_map:fail: dom%d gfn=%lx mfn=%lx nr=%lx ret:%ld\n", - d->domain_id, gfn, mfn, nr_mfns, ret); - } - else - { - printk(XENLOG_G_DEBUG - "memory_map:remove: dom%d gfn=%lx mfn=%lx nr=%lx\n", - d->domain_id, gfn, mfn, nr_mfns); - - ret = unmap_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); - if ( ret < 0 && is_hardware_domain(current->domain) ) - printk(XENLOG_ERR - "memory_map: error %ld removing dom%d access to [%lx,%lx]\n", - ret, d->domain_id, mfn, mfn_end); - } - break; - } - case XEN_DOMCTL_settimeoffset: domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds); break; - case XEN_DOMCTL_set_target: - { - struct domain *e; - - ret = -ESRCH; - e = get_domain_by_id(op->u.set_target.target); - if ( e == NULL ) - break; - - ret = -EINVAL; - if ( (d == e) || (d->target != NULL) ) - { - put_domain(e); - break; - } - - ret = -EOPNOTSUPP; - if ( is_hvm_domain(e) ) - ret = xsm_set_target(XSM_HOOK, d, e); - if ( ret ) - { - put_domain(e); - break; - } - - /* Hold reference on @e until we destroy @d. */ - d->target = e; - break; - } - case XEN_DOMCTL_subscribe: d->suspend_evtchn = op->u.subscribe.port; break; @@ -831,12 +929,7 @@ break; } - /* overwrite vnuma topology for domain. */ - write_lock(&d->vnuma_rwlock); - vnuma_destroy(d->vnuma); - d->vnuma = vnuma; - write_unlock(&d->vnuma_rwlock); - + vnuma_replace(d, vnuma); break; } @@ -849,7 +942,6 @@ case XEN_DOMCTL_assign_device: case XEN_DOMCTL_test_assign_device: case XEN_DOMCTL_deassign_device: - case XEN_DOMCTL_get_device_group: ret = iommu_do_domctl(op, d, u_domctl); break; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/efi/boot.c xen-4.20.3+127-gc42374a105/xen/common/efi/boot.c --- xen-4.20.2+37-g61ff35323e/xen/common/efi/boot.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/efi/boot.c 2026-07-28 12:08:27.000000000 +0000 @@ -624,7 +624,8 @@ if ( esrt_ptr->FwResourceCount > available_len / sizeof(esrt_ptr->Entries[0]) ) return 0; - return esrt_ptr->FwResourceCount * sizeof(esrt_ptr->Entries[0]); + return offsetof(EFI_SYSTEM_RESOURCE_TABLE, + Entries[esrt_ptr->FwResourceCount]); } static EFI_GUID __initdata esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID; @@ -701,6 +702,16 @@ */ #include "efi-boot.h" +static void __init free_cfg(void) +{ + if ( !cfg.need_to_free ) + return; + + /* One extra byte was allocated to put a nul character there. */ + efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size + 1)); + cfg.need_to_free = false; +} + void __init noreturn blexit(const CHAR16 *str) { if ( str ) @@ -710,8 +721,7 @@ if ( !efi_bs ) efi_arch_halt(); - if ( cfg.need_to_free ) - efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); + free_cfg(); if ( kernel.need_to_free ) efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size)); if ( ramdisk.need_to_free ) @@ -773,8 +783,9 @@ { file->addr = min(1UL << (32 + PAGE_SHIFT), HYPERVISOR_VIRT_END - DIRECTMAP_VIRT_START); + /* For config files allocate an extra byte to put a NUL there. */ ret = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, - PFN_UP(size), &file->addr); + PFN_UP(size + (file == &cfg)), &file->addr); } if ( EFI_ERROR(ret) ) what = what ?: L"Allocation"; @@ -803,6 +814,9 @@ efi_arch_flush_dcache_area(file->ptr, file->size); + if ( file == &cfg ) + file->str[file->size] = 0; + return true; } @@ -818,6 +832,23 @@ file->ptr = ptr; + /* For cfg file, if necessary allocate space to put an extra NUL there. */ + if ( file == &cfg && file->size && !iscntrl(file->str[file->size - 1]) ) + { + EFI_PHYSICAL_ADDRESS addr; + EFI_STATUS ret = efi_bs->AllocatePages(AllocateMaxAddress, + EfiLoaderData, + PFN_UP(file->size + 1), &addr); + + if ( EFI_ERROR(ret) ) + return false; + + memcpy((void *)addr, ptr, file->size); + file->addr = addr; + file->need_to_free = true; + file->str[file->size] = 0; + } + handle_file_info(name, file, options); return true; @@ -846,9 +877,6 @@ else start = 0; } - if ( file->size && end[-1] ) - PrintStr(L"No newline at end of config file," - " last line will be ignored.\r\n"); } static void __init efi_init(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) @@ -1416,11 +1444,7 @@ name.s = get_value(&cfg, "global", "chain"); if ( !name.s ) break; - if ( cfg.need_to_free ) - { - efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); - cfg.need_to_free = false; - } + free_cfg(); if ( !read_file(dir_handle, s2w(&name), &cfg, NULL) ) { PrintStr(L"Chained configuration file '"); @@ -1485,11 +1509,7 @@ efi_arch_cfg_file_late(loaded_image, dir_handle, section.s); - if ( cfg.need_to_free ) - { - efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); - cfg.need_to_free = false; - } + free_cfg(); dir_handle->Close(dir_handle); diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/efi/common-stub.c xen-4.20.3+127-gc42374a105/xen/common/efi/common-stub.c --- xen-4.20.2+37-g61ff35323e/xen/common/efi/common-stub.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/efi/common-stub.c 2026-07-28 12:08:27.000000000 +0000 @@ -7,11 +7,6 @@ return false; } -bool efi_rs_using_pgtables(void) -{ - return false; -} - unsigned long efi_get_time(void) { BUG(); diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/efi/runtime.c xen-4.20.3+127-gc42374a105/xen/common/efi/runtime.c --- xen-4.20.2+37-g61ff35323e/xen/common/efi/runtime.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/efi/runtime.c 2026-07-28 12:08:27.000000000 +0000 @@ -47,7 +47,6 @@ const EFI_RUNTIME_SERVICES *__read_mostly efi_rs; #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ static DEFINE_SPINLOCK(efi_rs_lock); -static unsigned int efi_rs_on_cpu = NR_CPUS; #endif UINTN __read_mostly efi_memmap_size; @@ -90,6 +89,11 @@ if ( mfn_eq(efi_l4_mfn, INVALID_MFN) ) return state; + /* + * If in lazy idle context switch state sync now to avoid an incoming + * FLUSH_VCPU_STATE IPI changing the loaded page-tables. + */ + sync_local_execstate(); state.cr3 = read_cr3(); save_fpu_enable(); asm volatile ( "fnclex; fldcw %0" :: "m" (fcw) ); @@ -97,8 +101,6 @@ spin_lock(&efi_rs_lock); - efi_rs_on_cpu = smp_processor_id(); - /* prevent fixup_page_fault() from doing anything */ irq_enter(); @@ -113,7 +115,8 @@ lgdt(&gdt_desc); } - switch_cr3_cr4(mfn_to_maddr(efi_l4_mfn), read_cr4()); + switch_cr3_cr4(idle_vcpu[smp_processor_id()], mfn_to_maddr(efi_l4_mfn), + read_cr4()); /* * At the time of writing (2022), no UEFI firwmare is CET-IBT compatible. @@ -141,7 +144,7 @@ if ( state->msr_s_cet ) wrmsrl(MSR_S_CET, state->msr_s_cet); - switch_cr3_cr4(state->cr3, read_cr4()); + switch_cr3_cr4(curr, state->cr3, read_cr4()); if ( is_pv_vcpu(curr) && !is_idle_vcpu(curr) ) { struct desc_ptr gdt_desc = { @@ -152,18 +155,10 @@ lgdt(&gdt_desc); } irq_exit(); - efi_rs_on_cpu = NR_CPUS; spin_unlock(&efi_rs_lock); vcpu_restore_fpu_nonlazy(curr, true); } -bool efi_rs_using_pgtables(void) -{ - return !mfn_eq(efi_l4_mfn, INVALID_MFN) && - (smp_processor_id() == efi_rs_on_cpu) && - (read_cr3() == mfn_to_maddr(efi_l4_mfn)); -} - unsigned long efi_get_time(void) { EFI_TIME time; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/event_fifo.c xen-4.20.3+127-gc42374a105/xen/common/event_fifo.c --- xen-4.20.2+37-g61ff35323e/xen/common/event_fifo.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/event_fifo.c 2026-07-28 12:08:27.000000000 +0000 @@ -692,13 +692,11 @@ int evtchn_fifo_expand_array(const struct evtchn_expand_array *expand_array) { struct domain *d = current->domain; - int rc; - - if ( !d->evtchn_fifo ) - return -EOPNOTSUPP; + int rc = -EOPNOTSUPP; write_lock(&d->event_lock); - rc = add_page_to_event_array(d, expand_array->array_gfn); + if ( d->evtchn_fifo ) + rc = add_page_to_event_array(d, expand_array->array_gfn); write_unlock(&d->event_lock); return rc; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/grant_table.c xen-4.20.3+127-gc42374a105/xen/common/grant_table.c --- xen-4.20.2+37-g61ff35323e/xen/common/grant_table.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/grant_table.c 2026-07-28 12:08:27.000000000 +0000 @@ -71,6 +71,10 @@ unsigned int nr_grant_frames; /* Number of grant status frames shared with guest (for version 2) */ unsigned int nr_status_frames; + + /* Number of version 2 operations in progress. */ + atomic_t nr_v2_ops; + /* * Number of available maptrack entries. For cleanup purposes it is * important to realize that this field and @maptrack further down will @@ -933,6 +937,9 @@ { unsigned int clear_flags = act->pin ? 0 : GTF_reading; + if ( unlikely(!status) ) + return; + if ( !readonly && !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) ) clear_flags |= GTF_writing; @@ -1341,6 +1348,22 @@ grant_read_lock(rgt); + if ( unlikely(evaluate_nospec((rgt->gt_version == 1) != + (status == &shah->flags))) ) + { + /* + * After a v1 -> v2 change behind our backs "ref" may now be out of + * bounds. Recalculate it, but only for reserved entries. Others + * will have been cleared anyway by the version change. + */ + if ( ref < GNTTAB_NR_RESERVED_ENTRIES ) + status = evaluate_nospec(rgt->gt_version == 1) + ? &shah->flags + : &status_entry(rgt, ref); + else + status = NULL; + } + act = active_entry_acquire(rgt, op->ref); act->pin -= pin_incr; @@ -1584,9 +1607,8 @@ struct domain *ld, *rd = op->rd; struct grant_table *rgt; struct active_grant_entry *act; - grant_entry_header_t *sha; struct page_info *pg; - uint16_t *status; + uint16_t *status = NULL; if ( evaluate_nospec(!op->done) ) { @@ -1602,11 +1624,10 @@ grant_read_lock(rgt); act = active_entry_acquire(rgt, op->ref); - sha = shared_entry_header(rgt, op->ref); if ( evaluate_nospec(rgt->gt_version == 1) ) - status = &sha->flags; - else + status = &shared_entry_v1(rgt, op->ref).flags; + else if ( evaluate_nospec(op->ref < nr_grant_entries(rgt)) ) status = &status_entry(rgt, op->ref); pg = !is_iomem_page(act->mfn) ? mfn_to_page(op->mfn) : NULL; @@ -2195,14 +2216,14 @@ * Check that the given grant reference (rd,ref) allows 'ld' to transfer * ownership of a page frame. If so, lock down the grant entry. */ -static int +static unsigned int gnttab_prepare_for_transfer( struct domain *rd, struct domain *ld, grant_ref_t ref) { struct grant_table *rgt = rd->grant_table; uint32_t *raw_shah; union grant_combo scombo; - int retries = 0; + unsigned int retries = 0, ver; grant_read_lock(rgt); @@ -2247,8 +2268,11 @@ scombo = prev; } + ver = rgt->gt_version; + grant_read_unlock(rgt); - return 1; + + return ver; fail: grant_read_unlock(rgt); @@ -2273,7 +2297,7 @@ for ( i = 0; i < count; i++ ) { - bool okay; + unsigned int ver; int rc; if ( i && hypercall_preempt_check() ) @@ -2413,14 +2437,14 @@ * pagelist. */ nrspin_unlock(&e->page_alloc_lock); - okay = gnttab_prepare_for_transfer(e, d, gop.ref); + ver = gnttab_prepare_for_transfer(e, d, gop.ref); /* * Make sure the reference bound check in gnttab_prepare_for_transfer * is respected and speculative execution is blocked accordingly */ - if ( unlikely(!evaluate_nospec(okay)) || - unlikely(assign_pages(page, 1, e, MEMF_no_refcount)) ) + if ( unlikely(!evaluate_nospec(ver)) || + unlikely(assign_pages(page, 1, e, MEMF_no_refcount)) ) { bool drop_dom_ref; @@ -2432,7 +2456,7 @@ drop_dom_ref = !domain_adjust_tot_pages(e, -1); nrspin_unlock(&e->page_alloc_lock); - if ( okay /* i.e. e->is_dying due to the surrounding if() */ ) + if ( ver /* i.e. e->is_dying due to the surrounding if() */ ) gdprintk(XENLOG_INFO, "Transferee d%d is now dying\n", e->domain_id); @@ -2452,7 +2476,13 @@ grant_read_lock(e->grant_table); act = active_entry_acquire(e->grant_table, gop.ref); - if ( evaluate_nospec(e->grant_table->gt_version == 1) ) + if ( unlikely(evaluate_nospec(e->grant_table->gt_version != ver)) ) + { + rc = -EILSEQ; + goto release; + } + + if ( evaluate_nospec(ver == 1) ) { grant_entry_v1_t *sha = &shared_entry_v1(e->grant_table, gop.ref); @@ -2472,6 +2502,7 @@ shared_entry_header(e->grant_table, gop.ref)->flags |= GTF_transfer_completed; + release: active_entry_release(act); grant_read_unlock(e->grant_table); @@ -2500,28 +2531,27 @@ struct domain *rd, grant_ref_t gref, bool readonly) { struct grant_table *rgt = rd->grant_table; - grant_entry_header_t *sha; struct active_grant_entry *act; mfn_t mfn; - uint16_t *status; + uint16_t *status = NULL; grant_ref_t trans_gref; struct domain *td; grant_read_lock(rgt); act = active_entry_acquire(rgt, gref); - sha = shared_entry_header(rgt, gref); mfn = act->mfn; if ( evaluate_nospec(rgt->gt_version == 1) ) { - status = &sha->flags; + status = &shared_entry_v1(rgt, gref).flags; td = rd; trans_gref = gref; } else { - status = &status_entry(rgt, gref); + if ( evaluate_nospec(gref < nr_grant_entries(rgt)) ) + status = &status_entry(rgt, gref); td = (act->src_domid == rd->domain_id) ? rd : knownalive_domain_from_domid(act->src_domid); trans_gref = act->trans_gref; @@ -2540,6 +2570,9 @@ reduce_status_for_pin(rd, act, status, readonly); + if ( !act->pin && act->is_sub_page ) + atomic_dec(&rgt->nr_v2_ops); + active_entry_release(act); grant_read_unlock(rgt); @@ -2671,8 +2704,10 @@ /* * acquire_grant_for_copy() will take the lock on the remote table, - * so we have to drop the lock here and reacquire. + * so we have to drop the lock here and reacquire. Before doing so, + * record that a v2 operation is in progress. */ + atomic_inc(&rgt->nr_v2_ops); active_entry_release(act); grant_read_unlock(rgt); @@ -2686,6 +2721,7 @@ if ( rc != GNTST_okay ) { + atomic_dec(&rgt->nr_v2_ops); rcu_unlock_domain(td); reduce_status_for_pin(rd, act, status, readonly); active_entry_release(act); @@ -2722,6 +2758,8 @@ rcu_unlock_domain(td); grant_read_lock(rgt); + atomic_dec(&rgt->nr_v2_ops); + act = active_entry_acquire(rgt, gref); reduce_status_for_pin(rd, act, status, readonly); active_entry_release(act); @@ -2748,6 +2786,8 @@ */ act->is_sub_page = true; } + else + atomic_dec(&rgt->nr_v2_ops); } else if ( !old_pin || (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) ) @@ -2802,7 +2842,25 @@ act->src_domid = td->domain_id; act->trans_gref = trans_gref; act->mfn = grant_mfn; + + if ( is_sub_page ) + atomic_inc(&rgt->nr_v2_ops); + } + else if ( !mfn_eq(act->mfn, grant_mfn) || + act->src_domid != td->domain_id || + act->trans_gref != trans_gref || + (act->is_sub_page && + (!is_sub_page || + act->start != trans_page_off || + act->length != trans_length)) ) + { + put_page(*page); + *page = NULL; + rc = GNTST_general_error; + goto unlock_out_clear; } + else + ASSERT(act->domid == ldom); } else { @@ -3183,11 +3241,12 @@ if ( op.version == 2 && gt->max_version == 1 ) goto out; /* Behave as before set_version was introduced. */ + grant_write_lock(gt); + res = 0; if ( gt->gt_version == op.version ) - goto out; + goto out_unlock; - grant_write_lock(gt); /* * Make sure that the grant table isn't currently in use when we * change the version number, except for the first 8 entries which @@ -3215,7 +3274,17 @@ if ( res < 0) goto out_unlock; break; + case 2: + if ( atomic_read(>->nr_v2_ops) ) + { + gdprintk(XENLOG_WARNING, + "tried to change to grant table v1, but %d v2 operations still in progress\n", + atomic_read(>->nr_v2_ops)); + res = -EAGAIN; + goto out_unlock; + } + for ( i = 0; i < GNTTAB_NR_RESERVED_ENTRIES; i++ ) { switch ( shared_entry_v2(gt, i).hdr.flags & GTF_type_mask ) @@ -4242,7 +4311,8 @@ return rc; } -int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn) +int gnttab_map_frame_begin( + struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn) { int rc = 0; struct grant_table *gt = d->grant_table; @@ -4280,11 +4350,19 @@ put_page(pg); } - grant_write_unlock(gt); + if ( rc ) + grant_write_unlock(d->grant_table); return rc; } +void gnttab_map_frame_end(struct domain *d, mfn_t mfn) +{ + put_page(mfn_to_page(mfn)); + + grant_write_unlock(d->grant_table); +} + static void gnttab_usage_print(struct domain *rd) { int first = 1; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/irq.c xen-4.20.3+127-gc42374a105/xen/common/irq.c --- xen-4.20.2+37-g61ff35323e/xen/common/irq.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/irq.c 2026-07-28 12:08:27.000000000 +0000 @@ -54,3 +54,15 @@ { return 0; } + +void disable_irq(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if ( desc->handler->disable ) + desc->handler->disable(desc); + desc->status |= IRQ_DISABLED; + spin_unlock_irqrestore(&desc->lock, flags); +} diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/libfdt/fdt_sw.c xen-4.20.3+127-gc42374a105/xen/common/libfdt/fdt_sw.c --- xen-4.20.2+37-g61ff35323e/xen/common/libfdt/fdt_sw.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/libfdt/fdt_sw.c 2026-07-28 12:08:27.000000000 +0000 @@ -330,7 +330,8 @@ ret = fdt_property_placeholder(fdt, name, len, &ptr); if (ret) return ret; - memcpy(ptr, val, len); + if (len) + memcpy(ptr, val, len); return 0; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/llc-coloring.c xen-4.20.3+127-gc42374a105/xen/common/llc-coloring.c --- xen-4.20.2+37-g61ff35323e/xen/common/llc-coloring.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/llc-coloring.c 2026-07-28 12:08:27.000000000 +0000 @@ -76,7 +76,8 @@ else /* Single value */ end = start; - if ( start > end || (end - start) > (UINT_MAX - *num_colors) || + if ( end >= NR_LLC_COLORS || start > end || + (end - start) >= (UINT_MAX - *num_colors) || (*num_colors + (end - start)) >= max_num_colors ) return -EINVAL; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/memory.c xen-4.20.3+127-gc42374a105/xen/common/memory.c --- xen-4.20.2+37-g61ff35323e/xen/common/memory.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/memory.c 2026-07-28 12:08:27.000000000 +0000 @@ -157,73 +157,6 @@ a->nr_done = i; } -/* - * Temporary storage for a domain assigned page that's not been fully scrubbed. - * Stored pages must be domheap ones. - * - * The stashed page can be freed at any time by Xen, the caller must pass the - * order and NUMA node requirement to the fetch function to ensure the - * currently stashed page matches it's requirements. - */ -static void stash_allocation(struct domain *d, struct page_info *page, - unsigned int order, unsigned int scrub_index) -{ - rspin_lock(&d->page_alloc_lock); - - /* - * Drop the passed page in preference for the already stashed one. This - * interface is designed to be used for single-threaded domain creation. - */ - if ( d->pending_scrub || d->is_dying ) - free_domheap_pages(page, order); - else - { - d->pending_scrub_index = scrub_index; - d->pending_scrub_order = order; - d->pending_scrub = page; - } - - rspin_unlock(&d->page_alloc_lock); -} - -static struct page_info *get_stashed_allocation(struct domain *d, - unsigned int order, - nodeid_t node, - unsigned int *scrub_index) -{ - struct page_info *page = NULL; - - rspin_lock(&d->page_alloc_lock); - - /* - * If there's a pending page to scrub check if it satisfies the current - * request. If it doesn't free it and return NULL. - */ - if ( d->pending_scrub ) - { - if ( d->pending_scrub_order == order && - (node == NUMA_NO_NODE || node == page_to_nid(d->pending_scrub)) ) - { - page = d->pending_scrub; - *scrub_index = d->pending_scrub_index; - } - else - free_domheap_pages(d->pending_scrub, d->pending_scrub_order); - - /* - * The caller now owns the page or it has been freed, clear stashed - * information. Prevent concurrent usages of get_stashed_allocation() - * from returning the same page to different contexts. - */ - d->pending_scrub_index = 0; - d->pending_scrub_order = 0; - d->pending_scrub = NULL; - } - - rspin_unlock(&d->page_alloc_lock); - return page; -} - static void populate_physmap(struct memop_args *a) { struct page_info *page; @@ -340,19 +273,7 @@ } else { - unsigned int scrub_start = 0; - unsigned int memflags = - a->memflags | (d->creation_finished ? 0 - : MEMF_no_scrub); - nodeid_t node = - (a->memflags & MEMF_exact_node) ? MEMF_get_node(a->memflags) - : NUMA_NO_NODE; - - page = get_stashed_allocation(d, a->extent_order, node, - &scrub_start); - - if ( !page ) - page = alloc_domheap_pages(d, a->extent_order, memflags); + page = alloc_domheap_pages(d, a->extent_order, a->memflags); if ( unlikely(!page) ) { @@ -363,30 +284,6 @@ goto out; } - if ( memflags & MEMF_no_scrub ) - { - unsigned int dirty_cnt = 0; - - /* Check if there's anything to scrub. */ - for ( j = scrub_start; j < (1U << a->extent_order); j++ ) - { - if ( !test_and_clear_bit(_PGC_need_scrub, - &page[j].count_info) ) - continue; - - scrub_one_page(&page[j]); - - if ( (j + 1) != (1U << a->extent_order) && - !(++dirty_cnt & 0xff) && - hypercall_preempt_check() ) - { - a->preempted = 1; - stash_allocation(d, page, a->extent_order, j + 1); - goto out; - } - } - } - if ( unlikely(a->memflags & MEMF_no_tlbflush) ) { for ( j = 0; j < (1U << a->extent_order); j++ ) @@ -951,7 +848,7 @@ unsigned int start) { unsigned int done = 0; - long rc = 0; + long rc = 0, adjust = 1; union add_to_physmap_extra extra = {}; struct page_info *pages[16]; @@ -986,8 +883,25 @@ return -EOVERFLOW; } - xatp->idx += start; - xatp->gpfn += start; + /* + * Overlapping ranges need processing backwards when destination is above + * source. + */ + if ( xatp->gpfn > xatp->idx && + unlikely(xatp->gpfn < xatp->idx + xatp->size) ) + { + adjust = -1; + + /* Both fields store "next item to process". */ + xatp->idx += xatp->size - start - 1; + xatp->gpfn += xatp->size - start - 1; + } + else + { + xatp->idx += start; + xatp->gpfn += start; + } + xatp->size -= start; #ifdef CONFIG_HAS_PASSTHROUGH @@ -1005,8 +919,8 @@ if ( rc < 0 ) break; - xatp->idx++; - xatp->gpfn++; + xatp->idx += adjust; + xatp->gpfn += adjust; if ( extra.ppage ) ++extra.ppage; @@ -1029,7 +943,10 @@ this_cpu(iommu_dont_flush_iotlb) = 0; - ret = iommu_iotlb_flush(d, _dfn(xatp->idx - done), done, + if ( likely(adjust > 0) ) + adjust = done; + + ret = iommu_iotlb_flush(d, _dfn(xatp->idx - adjust), done, IOMMU_FLUSHF_modified); if ( unlikely(ret) && rc >= 0 ) rc = ret; @@ -1043,13 +960,26 @@ for ( i = 0; i < done; ++i ) put_page(pages[i]); - ret = iommu_iotlb_flush(d, _dfn(xatp->gpfn - done), done, + ret = iommu_iotlb_flush(d, _dfn(xatp->gpfn - adjust), done, IOMMU_FLUSHF_added | IOMMU_FLUSHF_modified); if ( unlikely(ret) && rc >= 0 ) rc = ret; } #endif + /* + * For internal callers (e.g. XEN_DMOP_relocate_memory handling) leave + * the GFNs from where to resume in *xatp (they're correct already when + * we worked forwards). These are the values not biased for a possible + * non-zero "start" that a subsequent invocation might use, so also do + * this updating only when incoming "start" was 0. + */ + if ( rc > 0 && !start && unlikely(adjust < 0) ) + { + xatp->idx -= xatp->size - rc - 1; + xatp->gpfn -= xatp->size - rc - 1; + } + return rc; } @@ -1872,12 +1802,24 @@ goto vnumainfo_out; } + read_lock(&d->vnuma_rwlock); + + /* + * Check d->vnuma again after re-acquiring the lock as we can race + * with domain destruction. + */ + if ( !d->vnuma ) + { + ASSERT(d->is_dying); + read_unlock(&d->vnuma_rwlock); + rc = -ESRCH; + goto vnumainfo_out; + } + /* * Check if vnuma info has changed and if the allocated arrays * are not big enough. */ - read_lock(&d->vnuma_rwlock); - if ( dom_vnodes < d->vnuma->nr_vnodes || dom_vranges < d->vnuma->nr_vmemranges || dom_vcpus < d->max_vcpus ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/monitor.c xen-4.20.3+127-gc42374a105/xen/common/monitor.c --- xen-4.20.2+37-g61ff35323e/xen/common/monitor.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/monitor.c 2026-07-28 12:08:27.000000000 +0000 @@ -30,16 +30,11 @@ int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop) { - int rc; bool requested_status = false; if ( unlikely(current->domain == d) ) /* no domain_pause() */ return -EPERM; - rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event); - if ( unlikely(rc) ) - return rc; - switch ( mop->op ) { case XEN_DOMCTL_MONITOR_OP_ENABLE: diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/numa.c xen-4.20.3+127-gc42374a105/xen/common/numa.c --- xen-4.20.2+37-g61ff35323e/xen/common/numa.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/numa.c 2026-07-28 12:08:27.000000000 +0000 @@ -403,6 +403,12 @@ if ( (epdx >> shift) >= memnodemapsize ) return 0; + /* + * Round down start address: if start is not aligned to the memnodemap + * chunk size the tail remainder might not be added. Overlaps created + * by rounding will fall into the same NUMA region. + */ + spdx = ROUNDDOWN(spdx, 1UL << shift); do { if ( memnodemap[spdx >> shift] != NUMA_NO_NODE && (!nodeids || memnodemap[spdx >> shift] != nodeids[i]) ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/page_alloc.c xen-4.20.3+127-gc42374a105/xen/common/page_alloc.c --- xen-4.20.2+37-g61ff35323e/xen/common/page_alloc.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/page_alloc.c 2026-07-28 12:08:27.000000000 +0000 @@ -169,7 +169,7 @@ /* * Flags that are preserved in assign_pages() (and only there) */ -#define PGC_preserved (PGC_extra | PGC_static | PGC_colored | PGC_need_scrub) +#define PGC_preserved (PGC_extra | PGC_static | PGC_colored) #ifndef PGT_TYPE_INFO_INITIALIZER #define PGT_TYPE_INFO_INITIALIZER 0 @@ -764,7 +764,7 @@ #endif #define SCRUB_BYTE_PATTERN (SCRUB_PATTERN & 0xff) -void scrub_one_page(const struct page_info *pg) +static void scrub_one_page(const struct page_info *pg) { if ( unlikely(pg->count_info & PGC_broken) ) return; @@ -1153,13 +1153,20 @@ next_order = cur_order = 0; + /* Attempt to grow the order (size) of the buddy as much as possible. */ while ( cur_order < head_order ) { next_order = cur_order + 1; - if ( (cur_head + (1 << next_order)) >= (head + ( 1 << head_order)) ) + /* Do not grow to next_order if it would go beyond the buddy. */ + if ( (cur_head + (1 << next_order)) > (head + (1 << head_order)) ) goto merge; + /* Do not grow to next_order if cur_head is not aligned to it. */ + if ( mfn_x(page_to_mfn(cur_head)) & (1UL << cur_order) ) + goto merge; + + /* Check for offlined pages in upper half of next_order range. */ for ( i = (1 << cur_order), pg = cur_head + (1 << cur_order ); i < (1 << next_order); i++, pg++ ) diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/sched/arinc653.c xen-4.20.3+127-gc42374a105/xen/common/sched/arinc653.c --- xen-4.20.2+37-g61ff35323e/xen/common/sched/arinc653.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/sched/arinc653.c 2026-07-28 12:08:27.000000000 +0000 @@ -418,12 +418,15 @@ if ( entry < ARINC653_MAX_DOMAINS_PER_SCHEDULE ) { - sched_priv->schedule[entry].dom_handle[0] = '\0'; + memcpy(sched_priv->schedule[entry].dom_handle, + unit->domain->handle, + sizeof(sched_priv->schedule->dom_handle)); sched_priv->schedule[entry].unit_id = unit->unit_id; sched_priv->schedule[entry].runtime = DEFAULT_TIMESLICE; sched_priv->schedule[entry].unit = unit; - sched_priv->major_frame += DEFAULT_TIMESLICE; + if ( entry ) + sched_priv->major_frame += DEFAULT_TIMESLICE; ++sched_priv->num_schedule_entries; } } @@ -548,12 +551,9 @@ /* Switch minor frame or find correct minor frame after a miss */ while ( (now >= sched_priv->next_switch_time) && - (sched_priv->sched_index < sched_priv->num_schedule_entries) ) - { - sched_priv->sched_index++; + (++sched_priv->sched_index < sched_priv->num_schedule_entries) ) sched_priv->next_switch_time += sched_priv->schedule[sched_priv->sched_index].runtime; - } /* * If we exhausted the domains in the schedule and still have time left diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/sched/core.c xen-4.20.3+127-gc42374a105/xen/common/sched/core.c --- xen-4.20.2+37-g61ff35323e/xen/common/sched/core.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/sched/core.c 2026-07-28 12:08:27.000000000 +0000 @@ -281,13 +281,18 @@ } delta = new_entry_time - v->runstate.state_entry_time; - if ( delta > 0 ) + + /* Serialization: ->schedule_lock (see ASSERT() above). */ + with_seq_write(&v->runstate_seq) { - v->runstate.time[v->runstate.state] += delta; - v->runstate.state_entry_time = new_entry_time; - } + if ( delta > 0 ) + { + v->runstate.time[v->runstate.state] += delta; + v->runstate.state_entry_time = new_entry_time; + } - v->runstate.state = new_state; + v->runstate.state = new_state; + } } void sched_guest_idle(void (*idle) (void), unsigned int cpu) @@ -307,30 +312,18 @@ void vcpu_runstate_get(const struct vcpu *v, struct vcpu_runstate_info *runstate) { - spinlock_t *lock; - s_time_t delta; - struct sched_unit *unit; - - rcu_read_lock(&sched_res_rculock); - - /* - * Be careful in case of an idle vcpu: the assignment to a unit might - * change even with the scheduling lock held, so be sure to use the - * correct unit for locking in order to avoid triggering an ASSERT() in - * the unlock function. - */ - unit = is_idle_vcpu(v) ? get_sched_res(v->processor)->sched_unit_idle - : v->sched_unit; - lock = likely(v == current) ? NULL : unit_schedule_lock_irq(unit); - memcpy(runstate, &v->runstate, sizeof(*runstate)); - delta = NOW() - runstate->state_entry_time; - if ( delta > 0 ) - runstate->time[runstate->state] += delta; + struct seqcount seq = SEQCNT_ZERO(); + const struct seqcount *s = likely(v == current) ? &seq : &v->runstate_seq; - if ( unlikely(lock != NULL) ) - unit_schedule_unlock_irq(lock, unit); + until_seq_read(s) + { + s_time_t delta; - rcu_read_unlock(&sched_res_rculock); + *runstate = v->runstate; + delta = NOW() - runstate->state_entry_time; + if ( delta > 0 ) + runstate->time[runstate->state] += delta; + } } uint64_t get_cpu_idle_time(unsigned int cpu) @@ -1682,7 +1675,7 @@ { struct vcpu *v; const struct sched_unit *unit; - int ret = 0; + int ret = 0, hret = 0; if ( vcpuaff->vcpu >= d->max_vcpus ) return -EINVAL; @@ -1720,19 +1713,17 @@ if ( vcpuaff->flags & XEN_VCPUAFFINITY_FORCE ) vcpu_temporary_affinity(v, NR_CPUS, VCPU_AFFINITY_OVERRIDE); - ret = 0; - /* * We both set a new affinity and report back to the caller what * the scheduler will be effectively using. */ if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD ) { - ret = xenctl_bitmap_to_bitmap(cpumask_bits(new_affinity), - &vcpuaff->cpumap_hard, nr_cpu_ids); - if ( !ret ) - ret = vcpu_set_hard_affinity(v, new_affinity); - if ( ret ) + hret = xenctl_bitmap_to_bitmap(cpumask_bits(new_affinity), + &vcpuaff->cpumap_hard, nr_cpu_ids); + if ( !hret ) + hret = vcpu_set_hard_affinity(v, new_affinity); + if ( hret ) goto setvcpuaffinity_out; /* @@ -1740,7 +1731,7 @@ * cpupool's online mask and the new hard affinity. */ cpumask_and(new_affinity, online, unit->cpu_hard_affinity); - ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard, new_affinity); + hret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard, new_affinity); } if ( vcpuaff->flags & XEN_VCPUAFFINITY_SOFT ) { @@ -1777,14 +1768,14 @@ else { if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD ) - ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard, - unit->cpu_hard_affinity); + hret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard, + unit->cpu_hard_affinity); if ( vcpuaff->flags & XEN_VCPUAFFINITY_SOFT ) ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_soft, unit->cpu_soft_affinity); } - return ret; + return hret ?: ret; } bool alloc_affinity_masks(struct affinity_masks *affinity) @@ -2063,10 +2054,6 @@ { long ret; - ret = xsm_domctl_scheduler_op(XSM_HOOK, d, op->cmd); - if ( ret ) - return ret; - if ( op->sched_id != dom_scheduler(d)->sched_id ) return -EINVAL; @@ -2098,10 +2085,6 @@ struct cpupool *pool; int rc; - rc = xsm_sysctl_scheduler_op(XSM_HOOK, op->cmd); - if ( rc ) - return rc; - if ( (op->cmd != XEN_SYSCTL_SCHEDOP_putinfo) && (op->cmd != XEN_SYSCTL_SCHEDOP_getinfo) ) return -EINVAL; diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/sched/rt.c xen-4.20.3+127-gc42374a105/xen/common/sched/rt.c --- xen-4.20.2+37-g61ff35323e/xen/common/sched/rt.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/sched/rt.c 2026-07-28 12:08:27.000000000 +0000 @@ -1454,7 +1454,41 @@ svc->period = period; svc->budget = budget; if ( local_sched.u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra ) + { + /* + * Turning extratime on while the vCPU is depleted + * (cur_budget <= 0) leaves cur_budget unchanged. The + * next runq_insert() on this vCPU - from + * rt_unit_wake() after a domain unpause, + * rt_context_saved() following a delayed runq add, or + * repl_timer_handler() - then places it on the run + * queue because has_extratime() is now true, even + * though cur_budget is 0. The very next rt_schedule() + * iterates the run queue from runq_pick() and trips + * the ASSERT(iter_svc->cur_budget > 0). + * + * Apply the same priority-demotion-and-refill that + * burn_budget() would have performed if the flag had + * been set when the budget ran out, clear the + * depleted state, and - if the vCPU is currently on + * the depleted queue - move it to the run queue so + * the new extratime allocation is picked up + * immediately instead of waiting for the next + * replenishment. + */ + if ( !has_extratime(svc) && svc->cur_budget <= 0 ) + { + svc->priority_level++; + svc->cur_budget = svc->budget; + __clear_bit(__RTDS_depleted, &svc->flags); + if ( unit_on_q(svc) ) + { + q_remove(svc); + runq_insert(ops, svc); + } + } __set_bit(__RTDS_extratime, &svc->flags); + } else __clear_bit(__RTDS_extratime, &svc->flags); spin_unlock_irqrestore(&prv->lock, flags); diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/sysctl.c xen-4.20.3+127-gc42374a105/xen/common/sysctl.c --- xen-4.20.2+37-g61ff35323e/xen/common/sysctl.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/sysctl.c 2026-07-28 12:08:27.000000000 +0000 @@ -42,7 +42,7 @@ if ( op->interface_version != XEN_SYSCTL_INTERFACE_VERSION ) return -EACCES; - ret = xsm_sysctl(XSM_PRIV, op->cmd); + ret = xsm_sysctl(XSM_PRIV, op); if ( ret ) return ret; @@ -59,10 +59,6 @@ switch ( op->cmd ) { case XEN_SYSCTL_readconsole: - ret = xsm_readconsole(XSM_HOOK, op->u.readconsole.clear); - if ( ret ) - break; - ret = read_console_ring(&op->u.readconsole); break; @@ -191,10 +187,6 @@ if ( op->u.page_offline.end < op->u.page_offline.start ) break; - ret = xsm_page_offline(XSM_HOOK, op->u.page_offline.cmd); - if ( ret ) - break; - ptr = status = xmalloc_array(uint32_t, (op->u.page_offline.end - op->u.page_offline.start + 1)); diff -Nru xen-4.20.2+37-g61ff35323e/xen/common/vm_event.c xen-4.20.3+127-gc42374a105/xen/common/vm_event.c --- xen-4.20.2+37-g61ff35323e/xen/common/vm_event.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/common/vm_event.c 2026-07-28 12:08:27.000000000 +0000 @@ -602,11 +602,10 @@ /* All other subops need to target a real domain. */ if ( unlikely(d == NULL) ) - return -ESRCH; - - rc = xsm_vm_event_control(XSM_PRIV, d, vec->mode, vec->op); - if ( rc ) - return rc; + { + ASSERT_UNREACHABLE(); + return -EILSEQ; + } if ( unlikely(d == current->domain) ) /* no domain_pause() */ { diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/char/ns16550.c xen-4.20.3+127-gc42374a105/xen/drivers/char/ns16550.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/char/ns16550.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/char/ns16550.c 2026-07-28 12:08:27.000000000 +0000 @@ -60,6 +60,7 @@ struct timer resume_timer; unsigned int timeout_ms; bool intr_works; + bool force_polling; bool dw_usr_bsy; #ifdef NS16550_PCI /* PCI card parameters. */ @@ -180,12 +181,38 @@ { struct serial_port *port = dev_id; struct ns16550 *uart = port->uart; + /* + * Set quite arbitrarily as 4x the time to drain the TX or fill RX FIFOs, + * set the upper bound as 5ms or the timeout_ms value, whatever is higher. + */ + const unsigned int delta = min(uart->timeout_ms * 4, + max(5u, uart->timeout_ms)); + const s_time_t timeout = NOW() + MILLISECS(delta); + ASSERT(!uart->force_polling); uart->intr_works = 1; while ( !(ns_read_reg(uart, UART_IIR) & UART_IIR_NOINT) ) { u8 lsr = ns_read_reg(uart, UART_LSR); + s_time_t now = NOW(); + + /* Break out of the loop if spending too much time. */ + if ( now > timeout ) + { + /* Disable the interrupt source - it's never shared. */ + disable_irq(irq); + + /* Disable interrupt generation on the device and arm the timer. */ + uart->force_polling = true; + ns_write_reg(uart, UART_IER, 0); + set_timer(&uart->timer, now + MILLISECS(uart->timeout_ms)); + printk(XENLOG_WARNING + "uart interrupt taking more than %ums, switched to polling\n", + delta); + + return; + } if ( (lsr & uart->lsr_mask) == uart->lsr_mask ) serial_tx_interrupt(port); @@ -213,7 +240,7 @@ struct ns16550 *uart = port->uart; const struct cpu_user_regs *old_regs; - if ( uart->intr_works ) + if ( uart->intr_works && !uart->force_polling ) return; /* Interrupts work - no more polling */ /* Mimic interrupt context. */ @@ -273,17 +300,22 @@ static void pci_serial_early_init(struct ns16550 *uart) { #ifdef NS16550_PCI - if ( uart->bar && uart->io_base >= 0x10000 ) + uint16_t cmd; + + if ( !uart->ps_bdf_enable ) + return; + + cmd = pci_conf_read16(PCI_SBDF(0, uart->ps_bdf[0], uart->ps_bdf[1], + uart->ps_bdf[2]), PCI_COMMAND); + + if ( uart->io_base >= 0x10000 ) { pci_conf_write16(PCI_SBDF(0, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2]), - PCI_COMMAND, PCI_COMMAND_MEMORY); + PCI_COMMAND, cmd | PCI_COMMAND_MEMORY); return; } - if ( !uart->ps_bdf_enable || uart->io_base >= 0x10000 ) - return; - if ( uart->pb_bdf_enable ) pci_conf_write16(PCI_SBDF(0, uart->pb_bdf[0], uart->pb_bdf[1], uart->pb_bdf[2]), @@ -297,7 +329,7 @@ uart->io_base | PCI_BASE_ADDRESS_SPACE_IO); pci_conf_write16(PCI_SBDF(0, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2]), - PCI_COMMAND, PCI_COMMAND_IO); + PCI_COMMAND, cmd | PCI_COMMAND_IO); #endif } @@ -307,6 +339,7 @@ unsigned int divisor; uart->intr_works = 0; + uart->force_polling = false; pci_serial_early_init(uart); @@ -340,9 +373,16 @@ if ( divisor ) uart->baud = uart->clock_hz / (divisor << 4); else + { + uart->baud = 115200; printk(XENLOG_ERR "Automatic baud rate determination was requested," - " but a baud rate was not set up\n"); + " but a baud rate was not set up\n" + "Setting baudrate to %u\n", uart->baud); + divisor = uart->clock_hz / (uart->baud << 4); + ns_write_reg(uart, UART_DLL, (uint8_t)divisor); + ns_write_reg(uart, UART_DLM, (uint8_t)(divisor >> 8)); + } } ns_write_reg(uart, UART_LCR, lcr); @@ -428,7 +468,7 @@ unsigned int, 1, (bits * uart->fifo_size * 1000) / uart->baud); #ifdef NS16550_PCI - if ( uart->bar || uart->ps_bdf_enable ) + if ( uart->ps_bdf_enable ) { if ( uart->param && uart->param->mmio && rangeset_add_range(mmio_ro_ranges, PFN_DOWN(uart->io_base), @@ -1320,6 +1360,7 @@ uart->ps_bdf[0] = b; uart->ps_bdf[1] = d; uart->ps_bdf[2] = f; + uart->ps_bdf_enable = true; uart->bar_idx = bar_idx; uart->bar = bar; uart->bar64 = bar_64; @@ -1448,7 +1489,7 @@ unsigned int i; param_name = strsep(&token, "="); - if ( param_name == NULL ) + if ( !param_name || !token ) return num_serial_params; /* Linear search for the parameter. */ @@ -1523,6 +1564,9 @@ { uart->data_bits = simple_strtoul(conf, &conf, 10); + if ( !*conf ) + PARSE_ERR_RET("bad DPS setting"); + uart->parity = parse_parity_char(*conf); uart->stop_bits = simple_strtoul(conf + 1, &conf, 10); @@ -1656,6 +1700,8 @@ pci_uart_config(uart, 0, uart - ns16550_com); dev_set = true; } + else + PARSE_ERR_RET("Unknown device type %s\n", param_value); break; case port_bdf: diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/cpufreq/cpufreq_ondemand.c xen-4.20.3+127-gc42374a105/xen/drivers/cpufreq/cpufreq_ondemand.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/cpufreq/cpufreq_ondemand.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/cpufreq/cpufreq_ondemand.c 2026-07-28 12:08:27.000000000 +0000 @@ -115,11 +115,12 @@ cur_ns = NOW(); total_ns = cur_ns - this_dbs_info->prev_cpu_wall; - this_dbs_info->prev_cpu_wall = NOW(); if (total_ns < MIN_DBS_INTERVAL) return; + this_dbs_info->prev_cpu_wall = cur_ns; + /* Get Idle Time */ for_each_cpu(j, policy->cpus) { uint64_t idle_ns, total_idle_ns; @@ -182,7 +183,8 @@ dbs_check_cpu(dbs_info); set_timer(&per_cpu(dbs_timer, dbs_info->cpu), - align_timer(NOW() , dbs_tuners_ins.sampling_rate)); + align_timer(NOW() + dbs_tuners_ins.sampling_rate, + dbs_tuners_ins.sampling_rate)); } static void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) @@ -397,6 +399,6 @@ (void)cmpxchg(stoppable, -1, 1); } else - set_timer(t, align_timer(now, dbs_tuners_ins.sampling_rate)); + set_timer(t, align_timer(t->expires, dbs_tuners_ins.sampling_rate)); } } diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/amd/iommu_init.c xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/amd/iommu_init.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/amd/iommu_init.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/amd/iommu_init.c 2026-07-28 12:08:27.000000000 +0000 @@ -42,18 +42,6 @@ return iommu->ht_flags & mask; } -static int __init map_iommu_mmio_region(struct amd_iommu *iommu) -{ - iommu->mmio_base = ioremap(iommu->mmio_base_phys, - IOMMU_MMIO_REGION_LENGTH); - if ( !iommu->mmio_base ) - return -ENOMEM; - - memset(iommu->mmio_base, 0, IOMMU_MMIO_REGION_LENGTH); - - return 0; -} - static void __init unmap_iommu_mmio_region(struct amd_iommu *iommu) { if ( iommu->mmio_base ) @@ -1369,11 +1357,14 @@ { int rc = alloc_ivrs_mappings(iommu->seg); - if ( !rc ) - rc = map_iommu_mmio_region(iommu); if ( rc ) return rc; + iommu->mmio_base = ioremap(iommu->mmio_base_phys, + IOMMU_MMIO_REGION_LENGTH); + if ( !iommu->mmio_base ) + return -ENOMEM; + get_iommu_features(iommu); /* @@ -1383,6 +1374,20 @@ if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode ) return -ERANGE; + /* + * Check whether the IOMMU is already enabled and unconditionally disable + * it (zero the control register) ahead of Xen setup. Needs to be + * revisited to support Preboot DMA Protection. + */ + iommu->ctrl.raw = readq(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET); + if ( iommu->ctrl.iommu_en ) + printk(XENLOG_WARNING + "AMD-Vi: IOMMU %pp enabled by firmware (ctrl %016lx)\n", + &PCI_SBDF(iommu->seg, iommu->bdf), iommu->ctrl.raw); + + iommu->ctrl.raw = 0; + writeq(0, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET); + return 0; } diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/device_tree.c xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/device_tree.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/device_tree.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/device_tree.c 2026-07-28 12:08:27.000000000 +0000 @@ -279,15 +279,15 @@ if ( (d && d->is_dying) || domctl->u.assign_device.flags ) break; - ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, - domctl->u.assign_device.u.dt.size, - &dev); - if ( ret ) - break; - - ret = xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev)); - if ( ret ) - break; + dev = domctl->u.assign_device.u.dt.dev; + if ( !dev ) + { + ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, + domctl->u.assign_device.u.dt.size, + &dev); + if ( ret ) + break; + } if ( domctl->cmd == XEN_DOMCTL_test_assign_device ) { @@ -335,15 +335,15 @@ if ( domctl->u.assign_device.flags ) break; - ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, - domctl->u.assign_device.u.dt.size, - &dev); - if ( ret ) - break; - - ret = xsm_deassign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev)); - if ( ret ) - break; + dev = domctl->u.assign_device.u.dt.dev; + if ( !dev ) + { + ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, + domctl->u.assign_device.u.dt.size, + &dev); + if ( ret ) + break; + } if ( d == dom_io ) { diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/pci.c xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/pci.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/pci.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/pci.c 2026-07-28 12:08:27.000000000 +0000 @@ -1626,7 +1626,7 @@ if ( (pdev->seg != seg) || ((b == bus) && (df == devfn)) ) continue; - if ( xsm_get_device_group(XSM_HOOK, (seg << 16) | (b << 8) | df) ) + if ( xsm_get_device_group(XSM_PRIV, (seg << 16) | (b << 8) | df) ) continue; sdev_id = iommu_call(ops, get_device_group_id, seg, b, df); @@ -1696,7 +1696,7 @@ u32 max_sdevs; XEN_GUEST_HANDLE_64(uint32) sdevs; - ret = xsm_get_device_group(XSM_HOOK, domctl->u.get_device_group.machine_sbdf); + ret = xsm_get_device_group(XSM_PRIV, domctl->u.get_device_group.machine_sbdf); if ( ret ) break; @@ -1746,10 +1746,6 @@ machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf; - ret = xsm_assign_device(XSM_HOOK, d, machine_sbdf); - if ( ret ) - break; - seg = machine_sbdf >> 16; bus = PCI_BUS(machine_sbdf); devfn = PCI_DEVFN(machine_sbdf); @@ -1791,10 +1787,6 @@ machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf; - ret = xsm_deassign_device(XSM_HOOK, d, machine_sbdf); - if ( ret ) - break; - seg = machine_sbdf >> 16; bus = PCI_BUS(machine_sbdf); devfn = PCI_DEVFN(machine_sbdf); diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/vtd/dmar.c xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/vtd/dmar.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/passthrough/vtd/dmar.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/vtd/dmar.c 2026-07-28 12:08:27.000000000 +0000 @@ -1065,7 +1065,8 @@ static int __init cf_check add_one_extra_rmrr(xen_pfn_t start, xen_ulong_t nr, u32 id, void *ctxt) { u32 sbdf_array[] = { id }; - return add_one_user_rmrr(start, start+nr, 1, sbdf_array); + + return add_one_user_rmrr(start, start + nr - 1, 1, sbdf_array); } static int __init add_extra_rmrr(void) diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/video/vesa.c xen-4.20.3+127-gc42374a105/xen/drivers/video/vesa.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/video/vesa.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/video/vesa.c 2026-07-28 12:08:27.000000000 +0000 @@ -31,8 +31,8 @@ static unsigned int __initdata font_height; static int __init cf_check parse_font_height(const char *s) { - if ( simple_strtoul(s, &s, 10) == 8 && (*s++ == 'x') ) - font_height = simple_strtoul(s, &s, 10); + if ( simple_strtoul(s, &s, 10) == 8 && (*s == 'x') ) + font_height = simple_strtoul(s + 1, &s, 10); if ( *s != '\0' ) font_height = 0; diff -Nru xen-4.20.2+37-g61ff35323e/xen/drivers/vpci/header.c xen-4.20.3+127-gc42374a105/xen/drivers/vpci/header.c --- xen-4.20.2+37-g61ff35323e/xen/drivers/vpci/header.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/drivers/vpci/header.c 2026-07-28 12:08:27.000000000 +0000 @@ -67,7 +67,7 @@ return -EPERM; } - rc = xsm_iomem_mapping(XSM_HOOK, map->d, map_mfn, m_end, map->map); + rc = xsm_iomem_mapping_vpci(XSM_HOOK, map->d, map_mfn, m_end, map->map); if ( rc ) { printk(XENLOG_G_WARNING diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/public/arch-x86/cpufeatureset.h xen-4.20.3+127-gc42374a105/xen/include/public/arch-x86/cpufeatureset.h --- xen-4.20.2+37-g61ff35323e/xen/include/public/arch-x86/cpufeatureset.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/public/arch-x86/cpufeatureset.h 2026-07-28 12:08:27.000000000 +0000 @@ -307,6 +307,7 @@ XEN_CPUFEATURE(FZRM, 10*32+10) /*A Fast Zero-length REP MOVSB */ XEN_CPUFEATURE(FSRS, 10*32+11) /*A Fast Short REP STOSB */ XEN_CPUFEATURE(FSRCS, 10*32+12) /*A Fast Short REP CMPSB/SCASB */ +XEN_CPUFEATURE(FRED, 10*32+17) /* Fast Return and Event Delivery */ XEN_CPUFEATURE(WRMSRNS, 10*32+19) /*S WRMSR Non-Serialising */ XEN_CPUFEATURE(AMX_FP16, 10*32+21) /* AMX FP16 instruction */ XEN_CPUFEATURE(AVX_IFMA, 10*32+23) /*A AVX-IFMA Instructions */ diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/public/domctl.h xen-4.20.3+127-gc42374a105/xen/include/public/domctl.h --- xen-4.20.2+37-g61ff35323e/xen/include/public/domctl.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/public/domctl.h 2026-07-28 12:08:27.000000000 +0000 @@ -567,7 +567,10 @@ } pci; struct { uint32_t size; /* Length of the path */ - XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node */ + XEN_GUEST_HANDLE_64(char) path; /* Path to the device tree node */ +#ifdef __XEN__ + struct dt_device_node *dev; /* Resolved device node of the above */ +#endif } dt; } u; }; diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/acpi.h xen-4.20.3+127-gc42374a105/xen/include/xen/acpi.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/acpi.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/acpi.h 2026-07-28 12:08:27.000000000 +0000 @@ -142,30 +142,34 @@ #ifdef CONFIG_ACPI_CSTATE /* - * max_cstate sets the highest legal C-state. - * max_cstate = 0: C0 okay, but not C1 - * max_cstate = 1: C1 okay, but not C2 - * max_cstate = 2: C2 okay, but not C3 etc. - - * max_csubstate sets the highest legal C-state sub-state. Only applies to the - * highest legal C-state. - * max_cstate = 1, max_csubstate = 0 ==> C0, C1 okay, but not C1E - * max_cstate = 1, max_csubstate = 1 ==> C0, C1 and C1E okay, but not C2 - * max_cstate = 2, max_csubstate = 0 ==> C0, C1, C1E, C2 okay, but not C3 - * max_cstate = 2, max_csubstate = 1 ==> C0, C1, C1E, C2 okay, but not C3 + * max_{allowed,usable}_cstate sets the highest allowed / usable C-state. + * max_usable_cstate, while affected by the command line, is internally driven, + * whereas max_allowed_cstate can be set from both command line and systcl. + * max_*_cstate = 0: C0 okay, but not C1 + * max_*_cstate = 1: C1 okay, but not C2 + * max_*_cstate = 2: C2 okay, but not C3 etc. + * + * max_csubstate sets the highest allowed C-state sub-state. Only applies to + * the highest allowed C-state. + * max_allowed_cstate = 1, max_csubstate = 0 ==> C0, C1 okay, but not C1E + * max_allowed_cstate = 1, max_csubstate = 1 ==> C0, C1 and C1E okay, but not C2 + * max_allowed_cstate = 2, max_csubstate = 0 ==> C0, C1, C1E, C2 okay, but not C3 + * max_allowed_cstate = 2, max_csubstate = 1 ==> C0, C1, C1E, C2 okay, but not C3 */ -extern unsigned int max_cstate; +extern unsigned int max_usable_cstate; +extern unsigned int max_allowed_cstate; extern unsigned int max_csubstate; +#define max_cstate() min(max_usable_cstate, max_allowed_cstate) + static inline unsigned int acpi_get_cstate_limit(void) { - return max_cstate; + return max_allowed_cstate; } static inline void acpi_set_cstate_limit(unsigned int new_limit) { - max_cstate = new_limit; - return; + max_allowed_cstate = new_limit; } static inline unsigned int acpi_get_csubstate_limit(void) diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/cpuidle.h xen-4.20.3+127-gc42374a105/xen/include/xen/cpuidle.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/cpuidle.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/cpuidle.h 2026-07-28 12:08:27.000000000 +0000 @@ -89,7 +89,7 @@ extern int8_t xen_cpuidle; extern struct cpuidle_governor *cpuidle_current_governor; -bool cpuidle_using_deep_cstate(void); +bool cpuidle_usable_deep_cstate(void); void cpuidle_disable_deep_cstate(void); #define CPUIDLE_DRIVER_STATE_START 1 diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/domain.h xen-4.20.3+127-gc42374a105/xen/include/xen/domain.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/domain.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/domain.h 2026-07-28 12:08:27.000000000 +0000 @@ -164,9 +164,10 @@ }; #ifndef CONFIG_PV_SHIM_EXCLUSIVE -void vnuma_destroy(struct vnuma_info *vnuma); +void vnuma_replace(struct domain *d, struct vnuma_info *vnuma); #else -static inline void vnuma_destroy(struct vnuma_info *vnuma) { ASSERT(!vnuma); } +static inline void vnuma_replace(struct domain *d, struct vnuma_info *vnuma) +{ ASSERT(!vnuma); } #endif extern bool vmtrace_available; diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/efi.h xen-4.20.3+127-gc42374a105/xen/include/xen/efi.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/efi.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/efi.h 2026-07-28 12:08:27.000000000 +0000 @@ -42,7 +42,6 @@ void efi_init_memory(void); bool efi_boot_mem_unused(unsigned long *start, unsigned long *end); -bool efi_rs_using_pgtables(void); unsigned long efi_get_time(void); void efi_halt_system(void); void efi_reset_system(bool warm); diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/grant_table.h xen-4.20.3+127-gc42374a105/xen/include/xen/grant_table.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/grant_table.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/grant_table.h 2026-07-28 12:08:27.000000000 +0000 @@ -56,8 +56,13 @@ int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref, gfn_t *gfn, uint16_t *status); -int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, - mfn_t *mfn); +/* + * These need to be used as a pair, as the first (in the success case) returns + * with a lock and page reference held which the second needs to drop. + */ +int gnttab_map_frame_begin(struct domain *d, unsigned long idx, gfn_t gfn, + mfn_t *mfn); +void gnttab_map_frame_end(struct domain *d, mfn_t mfn); unsigned int gnttab_resource_max_frames(const struct domain *d, unsigned int id); @@ -96,12 +101,14 @@ return -EINVAL; } -static inline int gnttab_map_frame(struct domain *d, unsigned long idx, - gfn_t gfn, mfn_t *mfn) +static inline int gnttab_map_frame_begin(struct domain *d, unsigned long idx, + gfn_t gfn, mfn_t *mfn) { return -EINVAL; } +static inline void gnttab_map_frame_end(struct domain *d, mfn_t mfn) {} + static inline unsigned int gnttab_resource_max_frames( const struct domain *d, unsigned int id) { diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/iocap.h xen-4.20.3+127-gc42374a105/xen/include/xen/iocap.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/iocap.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/iocap.h 2026-07-28 12:08:27.000000000 +0000 @@ -12,6 +12,9 @@ #include #include +void iocaps_double_lock(struct domain *d, bool write); +void iocaps_double_unlock(struct domain *d, bool write); + static inline int iomem_permit_access(struct domain *d, unsigned long s, unsigned long e) { diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/irq.h xen-4.20.3+127-gc42374a105/xen/include/xen/irq.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/irq.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/irq.h 2026-07-28 12:08:27.000000000 +0000 @@ -121,6 +121,7 @@ extern int request_irq(unsigned int irq, unsigned int irqflags, void (*handler)(int irq, void *dev_id), const char *devname, void *dev_id); +void disable_irq(unsigned int irq); extern const hw_irq_controller no_irq_type; void cf_check no_action(int cpl, void *dev_id); diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/mm.h xen-4.20.3+127-gc42374a105/xen/include/xen/mm.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/mm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/mm.h 2026-07-28 12:08:27.000000000 +0000 @@ -144,17 +144,6 @@ unsigned long avail_node_heap_pages(unsigned int nodeid); #define alloc_domheap_page(d,f) (alloc_domheap_pages(d,0,f)) #define free_domheap_page(p) (free_domheap_pages(p,0)) - -/* Free an allocation, and zero the pointer to it. */ -#define FREE_DOMHEAP_PAGES(p, o) do { \ - void *_ptr_ = (p); \ - (p) = NULL; \ - free_domheap_pages(_ptr_, o); \ -} while ( false ) -#define FREE_DOMHEAP_PAGE(p) FREE_DOMHEAP_PAGES(p, 0) - -void scrub_one_page(const struct page_info *pg); - unsigned int online_page(mfn_t mfn, uint32_t *status); int offline_page(mfn_t mfn, int broken, uint32_t *status); int query_page_offline(mfn_t mfn, uint32_t *status); diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/sched.h xen-4.20.3+127-gc42374a105/xen/include/xen/sched.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/sched.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/sched.h 2026-07-28 12:08:27.000000000 +0000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -192,7 +193,6 @@ struct sched_unit *sched_unit; - struct vcpu_runstate_info runstate; #ifndef CONFIG_COMPAT # define runstate_guest(v) ((v)->runstate_guest) XEN_GUEST_HANDLE(vcpu_runstate_info_t) runstate_guest; /* guest address */ @@ -204,6 +204,8 @@ } runstate_guest; /* guest address */ #endif struct guest_area runstate_guest_area; + struct vcpu_runstate_info runstate; + struct seqcount runstate_seq; unsigned int new_state; /* Has the FPU been initialised? */ @@ -528,6 +530,7 @@ #endif /* I/O capabilities (access to IRQs and memory-mapped I/O). */ + rwlock_t caps_lock; struct rangeset *iomem_caps; struct rangeset *irq_caps; @@ -646,11 +649,6 @@ unsigned int num_llc_colors; const unsigned int *llc_colors; #endif - - /* Pointer to allocated domheap page that possibly needs scrubbing. */ - struct page_info *pending_scrub; - unsigned int pending_scrub_order; - unsigned int pending_scrub_index; }; static inline struct page_list_head *page_to_list( diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/seqcount.h xen-4.20.3+127-gc42374a105/xen/include/xen/seqcount.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/seqcount.h 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/seqcount.h 2026-07-28 12:08:27.000000000 +0000 @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef XEN_SEQCOUNT_H +#define XEN_SEQCOUNT_H + +#include +#include + +#include +#include + +/* + * Sequence counters (seqcount_t) + * + * This is the raw counting mechanism, without any writer protection. + * + * Write side critical sections must be serialized (and non-preemptible). + * + * If readers can be invoked from interrupt contexts, interrupts must also + * be respectively disabled before entering the write section. + * + * This mechanism can't be used if the protected data contains pointers, + * as the writer can invalidate a pointer that a reader is following. + */ +struct seqcount { + unsigned int sequence; +}; + +/* + * SEQCNT_ZERO() - initializer for seqcount_t + * @name: Name of the struct seqcount instance + */ +#define SEQCNT_ZERO() { .sequence = 0 } + +static inline unsigned int seqprop_sequence(const struct seqcount *s) +{ + return ACCESS_ONCE(s->sequence); +} + +/* + * read_seqcount_begin() - begin a seqcount read critical section + * @s: Pointer to struct seqcount + * + * Return: count to be passed to read_seqcount_retry() + */ +static inline unsigned int _read_seqcount_begin(const struct seqcount *s) +{ + unsigned int seq; + + while ((seq = seqprop_sequence(s)) & 1) + cpu_relax(); + + smp_rmb(); + + return seq; +} + +static always_inline unsigned int read_seqcount_begin(const struct seqcount *s) +{ + unsigned int seq = _read_seqcount_begin(s); + + block_lock_speculation(); + + return seq; +} + +/* + * read_seqcount_retry() - end a seqcount read critical section + * @s: Pointer to struct seqcount + * @start: count, from read_seqcount_begin() + * + * read_seqcount_retry closes the read critical section of given struct + * seqcount. If the critical section was invalid, it must be ignored + * (and typically retried). + * + * Return: true if a read section retry is required, else false + */ +static inline bool _read_seqcount_retry(const struct seqcount *s, + unsigned int start) +{ + smp_rmb(); + return unlikely(seqprop_sequence(s) != start); +} + +static always_inline bool read_seqcount_retry(const struct seqcount *s, + unsigned int start) +{ + return lock_evaluate_nospec(_read_seqcount_retry(s, start)); +} + +/* Loops until a consistent count has been observed across the loop body. */ +#define until_seq_read(seq) \ + for ( unsigned int retry_ = 1, count_; \ + retry_ && (count_ = read_seqcount_begin(seq), true); \ + retry_ = read_seqcount_retry(seq, count_) ) + +/* + * write_seqcount_begin() - start a struct seqcount write side critical section + * @s: Pointer to struct seqcount + * + * Context: sequence counter write side sections must be serialized. + * If readers can be invoked from interrupt context, interrupts must be + * respectively disabled. + */ +static inline void write_seqcount_begin(struct seqcount *s) +{ + add_sized(&s->sequence, 1); + smp_wmb(); +} + +/* + * write_seqcount_end() - end a struct seqcount write side critical section + * @s: Pointer to seqcount + */ +static inline void write_seqcount_end(struct seqcount *s) +{ + smp_wmb(); + add_sized(&s->sequence, 1); +} + +/* + * Not really a loop, but we need write_seqcount_{begin,end}() in the correct + * position. + */ +#define with_seq_write(seq) \ + for ( bool once_ = true; \ + once_ && (write_seqcount_begin(seq), true); \ + (write_seqcount_end(seq), once_ = false) ) + +#endif /* XEN_SEQCOUNT_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xen/xvmalloc.h xen-4.20.3+127-gc42374a105/xen/include/xen/xvmalloc.h --- xen-4.20.2+37-g61ff35323e/xen/include/xen/xvmalloc.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xen/xvmalloc.h 2026-07-28 12:08:27.000000000 +0000 @@ -61,8 +61,9 @@ /* Free an allocation, and zero the pointer to it. */ #define XVFREE(p) do { \ - xvfree(p); \ + void *_ptr_ = (p); \ (p) = NULL; \ + xvfree(_ptr_); \ } while ( false ) static inline void *_xvmalloc_array( diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xsm/dummy.h xen-4.20.3+127-gc42374a105/xen/include/xsm/dummy.h --- xen-4.20.2+37-g61ff35323e/xen/include/xsm/dummy.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xsm/dummy.h 2026-07-28 12:08:27.000000000 +0000 @@ -141,56 +141,45 @@ return xsm_default_action(action, current->domain, d); } -static XSM_INLINE int cf_check xsm_domctl_scheduler_op( - XSM_DEFAULT_ARG struct domain *d, int cmd) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - -static XSM_INLINE int cf_check xsm_sysctl_scheduler_op(XSM_DEFAULT_ARG int cmd) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, NULL); -} - static XSM_INLINE int cf_check xsm_set_target( XSM_DEFAULT_ARG struct domain *d, struct domain *e) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_PRIV); return xsm_default_action(action, current->domain, NULL); } static XSM_INLINE int cf_check xsm_domctl( - XSM_DEFAULT_ARG struct domain *d, unsigned int cmd, uint32_t ssidref) + XSM_DEFAULT_ARG struct domain *d, struct xen_domctl *op) { XSM_ASSERT_ACTION(XSM_OTHER); - switch ( cmd ) + switch ( op->cmd ) { + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_device_group: + case XEN_DOMCTL_gsi_permission: + case XEN_DOMCTL_iomem_permission: case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_irq_permission: case XEN_DOMCTL_memory_mapping: - case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_set_target: case XEN_DOMCTL_unbind_pt_irq: - return xsm_default_action(XSM_DM_PRIV, current->domain, d); - case XEN_DOMCTL_getdomaininfo: - return xsm_default_action(XSM_XS_PRIV, current->domain, d); + ASSERT_UNREACHABLE(); + return -EILSEQ; + default: return xsm_default_action(XSM_PRIV, current->domain, d); } } -static XSM_INLINE int cf_check xsm_sysctl(XSM_DEFAULT_ARG int cmd) +static XSM_INLINE int cf_check xsm_sysctl( + XSM_DEFAULT_ARG const struct xen_sysctl *op) { XSM_ASSERT_ACTION(XSM_PRIV); return xsm_default_action(action, current->domain, NULL); } -static XSM_INLINE int cf_check xsm_readconsole(XSM_DEFAULT_ARG uint32_t clear) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, NULL); -} - static XSM_INLINE int cf_check xsm_alloc_security_domain(struct domain *d) { return 0; @@ -402,55 +391,11 @@ static XSM_INLINE int cf_check xsm_get_device_group( XSM_DEFAULT_ARG uint32_t machine_bdf) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_PRIV); return xsm_default_action(action, current->domain, NULL); } - -static XSM_INLINE int cf_check xsm_assign_device( - XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - -static XSM_INLINE int cf_check xsm_deassign_device( - XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - #endif /* HAS_PASSTHROUGH && HAS_PCI */ -#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE) -static XSM_INLINE int cf_check xsm_assign_dtdevice( - XSM_DEFAULT_ARG struct domain *d, const char *dtpath) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - -static XSM_INLINE int cf_check xsm_deassign_dtdevice( - XSM_DEFAULT_ARG struct domain *d, const char *dtpath) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - -#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE */ - -static XSM_INLINE int cf_check xsm_resource_plug_core(XSM_DEFAULT_VOID) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, NULL); -} - -static XSM_INLINE int cf_check xsm_resource_unplug_core(XSM_DEFAULT_VOID) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, NULL); -} - static XSM_INLINE int cf_check xsm_resource_plug_pci( XSM_DEFAULT_ARG uint32_t machine_bdf) { @@ -484,12 +429,6 @@ return xsm_default_action(action, current->domain, NULL); } -static XSM_INLINE int cf_check xsm_page_offline(XSM_DEFAULT_ARG uint32_t cmd) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, NULL); -} - static XSM_INLINE int cf_check xsm_hypfs_op(XSM_DEFAULT_VOID) { XSM_ASSERT_ACTION(XSM_PRIV); @@ -537,14 +476,14 @@ static XSM_INLINE int cf_check xsm_bind_pt_irq( XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_DM_PRIV); return xsm_default_action(action, current->domain, d); } static XSM_INLINE int cf_check xsm_unbind_pt_irq( XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_DM_PRIV); return xsm_default_action(action, current->domain, d); } @@ -558,20 +497,27 @@ static XSM_INLINE int cf_check xsm_irq_permission( XSM_DEFAULT_ARG struct domain *d, int pirq, uint8_t allow) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_PRIV); return xsm_default_action(action, current->domain, d); } static XSM_INLINE int cf_check xsm_iomem_permission( XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_PRIV); return xsm_default_action(action, current->domain, d); } static XSM_INLINE int cf_check xsm_iomem_mapping( XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow) { + XSM_ASSERT_ACTION(XSM_DM_PRIV); + return xsm_default_action(action, current->domain, d); +} + +static XSM_INLINE int cf_check xsm_iomem_mapping_vpci( + XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ XSM_ASSERT_ACTION(XSM_HOOK); return xsm_default_action(action, current->domain, d); } @@ -639,13 +585,6 @@ } } -static XSM_INLINE int cf_check xsm_vm_event_control( - XSM_DEFAULT_ARG struct domain *d, int mode, int op) -{ - XSM_ASSERT_ACTION(XSM_PRIV); - return xsm_default_action(action, current->domain, d); -} - #ifdef CONFIG_MEM_ACCESS static XSM_INLINE int cf_check xsm_mem_access(XSM_DEFAULT_ARG struct domain *d) { @@ -683,13 +622,6 @@ return xsm_default_action(action, current->domain, NULL); } -static XSM_INLINE int cf_check xsm_shadow_control( - XSM_DEFAULT_ARG struct domain *d, uint32_t op) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - static XSM_INLINE int cf_check xsm_mem_sharing_op( XSM_DEFAULT_ARG struct domain *d, struct domain *cd, int op) { @@ -754,14 +686,14 @@ static XSM_INLINE int cf_check xsm_ioport_permission( XSM_DEFAULT_ARG struct domain *d, uint32_t s, uint32_t e, uint8_t allow) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_PRIV); return xsm_default_action(action, current->domain, d); } static XSM_INLINE int cf_check xsm_ioport_mapping( XSM_DEFAULT_ARG struct domain *d, uint32_t s, uint32_t e, uint8_t allow) { - XSM_ASSERT_ACTION(XSM_HOOK); + XSM_ASSERT_ACTION(XSM_DM_PRIV); return xsm_default_action(action, current->domain, d); } diff -Nru xen-4.20.2+37-g61ff35323e/xen/include/xsm/xsm.h xen-4.20.3+127-gc42374a105/xen/include/xsm/xsm.h --- xen-4.20.2+37-g61ff35323e/xen/include/xsm/xsm.h 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/include/xsm/xsm.h 2026-07-28 12:08:27.000000000 +0000 @@ -56,12 +56,9 @@ struct xen_domctl_getdomaininfo *info); int (*domain_create)(struct domain *d, uint32_t ssidref); int (*getdomaininfo)(struct domain *d); - int (*domctl_scheduler_op)(struct domain *d, int op); - int (*sysctl_scheduler_op)(int op); int (*set_target)(struct domain *d, struct domain *e); - int (*domctl)(struct domain *d, unsigned int cmd, uint32_t ssidref); - int (*sysctl)(int cmd); - int (*readconsole)(uint32_t clear); + int (*domctl)(struct domain *d, struct xen_domctl *op); + int (*sysctl)(const struct xen_sysctl *op); int (*evtchn_unbound)(struct domain *d, struct evtchn *chn, domid_t id2); int (*evtchn_interdomain)(struct domain *d1, struct evtchn *chn1, @@ -116,29 +113,21 @@ uint8_t allow); int (*iomem_mapping)(struct domain *d, uint64_t s, uint64_t e, uint8_t allow); + int (*iomem_mapping_vpci)(struct domain *d, uint64_t s, uint64_t e, + uint8_t allow); int (*pci_config_permission)(struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access); #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI) int (*get_device_group)(uint32_t machine_bdf); - int (*assign_device)(struct domain *d, uint32_t machine_bdf); - int (*deassign_device)(struct domain *d, uint32_t machine_bdf); #endif -#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE) - int (*assign_dtdevice)(struct domain *d, const char *dtpath); - int (*deassign_dtdevice)(struct domain *d, const char *dtpath); -#endif - - int (*resource_plug_core)(void); - int (*resource_unplug_core)(void); int (*resource_plug_pci)(uint32_t machine_bdf); int (*resource_unplug_pci)(uint32_t machine_bdf); int (*resource_setup_pci)(uint32_t machine_bdf); int (*resource_setup_gsi)(int gsi); int (*resource_setup_misc)(void); - int (*page_offline)(uint32_t cmd); int (*hypfs_op)(void); long (*do_xsm_op)(XEN_GUEST_HANDLE_PARAM(void) op); @@ -151,8 +140,6 @@ int (*hvm_altp2mhvm_op)(struct domain *d, uint64_t mode, uint32_t op); int (*get_vnumainfo)(struct domain *d); - int (*vm_event_control)(struct domain *d, int mode, int op); - #ifdef CONFIG_MEM_ACCESS int (*mem_access)(struct domain *d); #endif @@ -169,7 +156,6 @@ #ifdef CONFIG_X86 int (*do_mca)(void); - int (*shadow_control)(struct domain *d, uint32_t op); int (*mem_sharing_op)(struct domain *d, struct domain *cd, int op); int (*apic)(struct domain *d, int cmd); int (*machine_memory_map)(void); @@ -230,17 +216,6 @@ return alternative_call(xsm_ops.getdomaininfo, d); } -static inline int xsm_domctl_scheduler_op( - xsm_default_t def, struct domain *d, int cmd) -{ - return alternative_call(xsm_ops.domctl_scheduler_op, d, cmd); -} - -static inline int xsm_sysctl_scheduler_op(xsm_default_t def, int cmd) -{ - return alternative_call(xsm_ops.sysctl_scheduler_op, cmd); -} - static inline int xsm_set_target( xsm_default_t def, struct domain *d, struct domain *e) { @@ -248,19 +223,14 @@ } static inline int xsm_domctl(xsm_default_t def, struct domain *d, - unsigned int cmd, uint32_t ssidref) -{ - return alternative_call(xsm_ops.domctl, d, cmd, ssidref); -} - -static inline int xsm_sysctl(xsm_default_t def, int cmd) + struct xen_domctl *op) { - return alternative_call(xsm_ops.sysctl, cmd); + return alternative_call(xsm_ops.domctl, d, op); } -static inline int xsm_readconsole(xsm_default_t def, uint32_t clear) +static inline int xsm_sysctl(xsm_default_t def, const struct xen_sysctl *op) { - return alternative_call(xsm_ops.readconsole, clear); + return alternative_call(xsm_ops.sysctl, op); } static inline int xsm_evtchn_unbound( @@ -503,6 +473,12 @@ return alternative_call(xsm_ops.iomem_mapping, d, s, e, allow); } +static inline int xsm_iomem_mapping_vpci( + xsm_default_t def, struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ + return alternative_call(xsm_ops.iomem_mapping_vpci, d, s, e, allow); +} + static inline int xsm_pci_config_permission( xsm_default_t def, struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access) @@ -515,35 +491,8 @@ { return alternative_call(xsm_ops.get_device_group, machine_bdf); } - -static inline int xsm_assign_device( - xsm_default_t def, struct domain *d, uint32_t machine_bdf) -{ - return alternative_call(xsm_ops.assign_device, d, machine_bdf); -} - -static inline int xsm_deassign_device( - xsm_default_t def, struct domain *d, uint32_t machine_bdf) -{ - return alternative_call(xsm_ops.deassign_device, d, machine_bdf); -} #endif /* HAS_PASSTHROUGH && HAS_PCI) */ -#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE) -static inline int xsm_assign_dtdevice( - xsm_default_t def, struct domain *d, const char *dtpath) -{ - return alternative_call(xsm_ops.assign_dtdevice, d, dtpath); -} - -static inline int xsm_deassign_dtdevice( - xsm_default_t def, struct domain *d, const char *dtpath) -{ - return alternative_call(xsm_ops.deassign_dtdevice, d, dtpath); -} - -#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE */ - static inline int xsm_resource_plug_pci(xsm_default_t def, uint32_t machine_bdf) { return alternative_call(xsm_ops.resource_plug_pci, machine_bdf); @@ -555,16 +504,6 @@ return alternative_call(xsm_ops.resource_unplug_pci, machine_bdf); } -static inline int xsm_resource_plug_core(xsm_default_t def) -{ - return alternative_call(xsm_ops.resource_plug_core); -} - -static inline int xsm_resource_unplug_core(xsm_default_t def) -{ - return alternative_call(xsm_ops.resource_unplug_core); -} - static inline int xsm_resource_setup_pci( xsm_default_t def, uint32_t machine_bdf) { @@ -581,11 +520,6 @@ return alternative_call(xsm_ops.resource_setup_misc); } -static inline int xsm_page_offline(xsm_default_t def, uint32_t cmd) -{ - return alternative_call(xsm_ops.page_offline, cmd); -} - static inline int xsm_hypfs_op(xsm_default_t def) { return alternative_call(xsm_ops.hypfs_op); @@ -625,12 +559,6 @@ return alternative_call(xsm_ops.get_vnumainfo, d); } -static inline int xsm_vm_event_control( - xsm_default_t def, struct domain *d, int mode, int op) -{ - return alternative_call(xsm_ops.vm_event_control, d, mode, op); -} - #ifdef CONFIG_MEM_ACCESS static inline int xsm_mem_access(xsm_default_t def, struct domain *d) { @@ -663,12 +591,6 @@ return alternative_call(xsm_ops.do_mca); } -static inline int xsm_shadow_control( - xsm_default_t def, struct domain *d, uint32_t op) -{ - return alternative_call(xsm_ops.shadow_control, d, op); -} - static inline int xsm_mem_sharing_op( xsm_default_t def, struct domain *d, struct domain *cd, int op) { diff -Nru xen-4.20.2+37-g61ff35323e/xen/tools/symbols.c xen-4.20.3+127-gc42374a105/xen/tools/symbols.c --- xen-4.20.2+37-g61ff35323e/xen/tools/symbols.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/tools/symbols.c 2026-07-28 12:08:27.000000000 +0000 @@ -63,6 +63,7 @@ unsigned char best_table[256][2]; unsigned char best_table_len[256]; +static const char *srcname = "xen-syms.S"; static void usage(void) { @@ -320,6 +321,7 @@ printf("#define ALGN .align 4\n"); printf("#endif\n"); + printf("\t.file \"%s\"\n", srcname); printf("\t.section .rodata, \"a\"\n"); printf("#ifndef SYMBOLS_ORIGIN\n"); @@ -612,6 +614,8 @@ unsorted = true; else if (strcmp(argv[i], "--sort-by-name") == 0) sort_by_name = 1; + else if (strncmp(argv[i], "--source-name=", 14) == 0) + srcname = argv[i] + 14; else if (strcmp(argv[i], "--warn-dup") == 0) warn_dup = true; else if (strcmp(argv[i], "--error-dup") == 0) diff -Nru xen-4.20.2+37-g61ff35323e/xen/xsm/dummy.c xen-4.20.3+127-gc42374a105/xen/xsm/dummy.c --- xen-4.20.2+37-g61ff35323e/xen/xsm/dummy.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/xsm/dummy.c 2026-07-28 12:08:27.000000000 +0000 @@ -18,12 +18,9 @@ .security_domaininfo = xsm_security_domaininfo, .domain_create = xsm_domain_create, .getdomaininfo = xsm_getdomaininfo, - .domctl_scheduler_op = xsm_domctl_scheduler_op, - .sysctl_scheduler_op = xsm_sysctl_scheduler_op, .set_target = xsm_set_target, .domctl = xsm_domctl, .sysctl = xsm_sysctl, - .readconsole = xsm_readconsole, .evtchn_unbound = xsm_evtchn_unbound, .evtchn_interdomain = xsm_evtchn_interdomain, @@ -72,29 +69,20 @@ .irq_permission = xsm_irq_permission, .iomem_permission = xsm_iomem_permission, .iomem_mapping = xsm_iomem_mapping, + .iomem_mapping_vpci = xsm_iomem_mapping_vpci, .pci_config_permission = xsm_pci_config_permission, .get_vnumainfo = xsm_get_vnumainfo, #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI) .get_device_group = xsm_get_device_group, - .assign_device = xsm_assign_device, - .deassign_device = xsm_deassign_device, #endif -#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE) - .assign_dtdevice = xsm_assign_dtdevice, - .deassign_dtdevice = xsm_deassign_dtdevice, -#endif - - .resource_plug_core = xsm_resource_plug_core, - .resource_unplug_core = xsm_resource_unplug_core, .resource_plug_pci = xsm_resource_plug_pci, .resource_unplug_pci = xsm_resource_unplug_pci, .resource_setup_pci = xsm_resource_setup_pci, .resource_setup_gsi = xsm_resource_setup_gsi, .resource_setup_misc = xsm_resource_setup_misc, - .page_offline = xsm_page_offline, .hypfs_op = xsm_hypfs_op, .hvm_param = xsm_hvm_param, .hvm_param_altp2mhvm = xsm_hvm_param_altp2mhvm, @@ -109,8 +97,6 @@ .remove_from_physmap = xsm_remove_from_physmap, .map_gmfn_foreign = xsm_map_gmfn_foreign, - .vm_event_control = xsm_vm_event_control, - #ifdef CONFIG_MEM_ACCESS .mem_access = xsm_mem_access, #endif @@ -126,7 +112,6 @@ .platform_op = xsm_platform_op, #ifdef CONFIG_X86 .do_mca = xsm_do_mca, - .shadow_control = xsm_shadow_control, .mem_sharing_op = xsm_mem_sharing_op, .apic = xsm_apic, .machine_memory_map = xsm_machine_memory_map, diff -Nru xen-4.20.2+37-g61ff35323e/xen/xsm/flask/avc.c xen-4.20.3+127-gc42374a105/xen/xsm/flask/avc.c --- xen-4.20.2+37-g61ff35323e/xen/xsm/flask/avc.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/xsm/flask/avc.c 2026-07-28 12:08:27.000000000 +0000 @@ -152,7 +152,8 @@ */ static void avc_dump_av(struct avc_dump_buf *buf, u16 tclass, u32 av) { - int i, i2, perm; + int i, i2; + uint32_t perm; if ( av == 0 ) { diff -Nru xen-4.20.2+37-g61ff35323e/xen/xsm/flask/hooks.c xen-4.20.3+127-gc42374a105/xen/xsm/flask/hooks.c --- xen-4.20.2+37-g61ff35323e/xen/xsm/flask/hooks.c 2026-02-12 12:58:50.000000000 +0000 +++ xen-4.20.3+127-gc42374a105/xen/xsm/flask/hooks.c 2026-07-28 12:08:27.000000000 +0000 @@ -40,10 +40,26 @@ #ifdef CONFIG_X86 #include +static int flask_shadow_control(struct domain *d, unsigned int op); #else #define pv_shim false #endif +#ifdef CONFIG_HAS_PASSTHROUGH +#ifdef CONFIG_HAS_PCI +static int flask_assign_device(struct domain *d, unsigned int machine_bdf); +static int flask_deassign_device(struct domain *d, unsigned int machine_bdf); +#endif +#ifdef CONFIG_HAS_DEVICE_TREE +static int flask_assign_dtdevice(struct domain *d, const char *dtpath); +static int flask_deassign_dtdevice(struct domain *d, const char *dtpath); +#endif +#endif /* CONFIG_HAS_PASSTHROUGH */ + +static int flask_resource_plug_core(void); +static int flask_resource_unplug_core(void); +static int flask_resource_use_core(void); + static uint32_t domain_sid(const struct domain *dom) { struct domain_security_struct *dsec = dom->ssid; @@ -609,7 +625,7 @@ return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETDOMAININFO); } -static int cf_check flask_domctl_scheduler_op(struct domain *d, int op) +static int flask_domctl_scheduler_op(struct domain *d, int op) { switch ( op ) { @@ -626,7 +642,7 @@ } } -static int cf_check flask_sysctl_scheduler_op(int op) +static int flask_sysctl_scheduler_op(unsigned int op) { switch ( op ) { @@ -665,10 +681,9 @@ return rc; } -static int cf_check flask_domctl(struct domain *d, unsigned int cmd, - uint32_t ssidref) +static int cf_check flask_domctl(struct domain *d, struct xen_domctl *op) { - switch ( cmd ) + switch ( op->cmd ) { case XEN_DOMCTL_createdomain: /* @@ -678,38 +693,23 @@ * Note that d is NULL because we haven't even allocated memory for it * this early in XEN_DOMCTL_createdomain. */ - return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL); + return avc_current_has_perm(op->u.createdomain.ssidref, SECCLASS_DOMAIN, + DOMAIN__CREATE, NULL); - /* These have individual XSM hooks (common/domctl.c) */ + /* These have individual XSM hooks and don't make it here. */ + case XEN_DOMCTL_bind_pt_irq: case XEN_DOMCTL_getdomaininfo: - case XEN_DOMCTL_scheduler_op: - case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_get_device_group: + case XEN_DOMCTL_gsi_permission: case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_irq_permission: case XEN_DOMCTL_memory_mapping: case XEN_DOMCTL_set_target: - case XEN_DOMCTL_vm_event_op: - - /* These have individual XSM hooks (arch/../domctl.c) */ - case XEN_DOMCTL_bind_pt_irq: case XEN_DOMCTL_unbind_pt_irq: -#ifdef CONFIG_X86 - /* These have individual XSM hooks (arch/x86/domctl.c) */ - case XEN_DOMCTL_shadow_op: - case XEN_DOMCTL_ioport_permission: - case XEN_DOMCTL_ioport_mapping: - case XEN_DOMCTL_gsi_permission: -#endif -#ifdef CONFIG_HAS_PASSTHROUGH - /* - * These have individual XSM hooks - * (drivers/passthrough/{pci,device_tree.c) - */ - case XEN_DOMCTL_get_device_group: - case XEN_DOMCTL_test_assign_device: - case XEN_DOMCTL_assign_device: - case XEN_DOMCTL_deassign_device: -#endif - return 0; + ASSERT_UNREACHABLE(); + return -EILSEQ; case XEN_DOMCTL_destroydomain: return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__DESTROY); @@ -740,6 +740,9 @@ case XEN_DOMCTL_setdomainhandle: return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETDOMAINHANDLE); + case XEN_DOMCTL_scheduler_op: + return flask_domctl_scheduler_op(d, op->u.scheduler_op.cmd); + case XEN_DOMCTL_set_ext_vcpucontext: case XEN_DOMCTL_set_vcpu_msrs: case XEN_DOMCTL_setvcpucontext: @@ -780,6 +783,54 @@ case XEN_DOMCTL_get_address_size: return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETADDRSIZE); +#ifdef CONFIG_X86 + case XEN_DOMCTL_shadow_op: + return flask_shadow_control(d, op->u.shadow_op.op); +#endif + +#ifdef CONFIG_HAS_PASSTHROUGH + + case XEN_DOMCTL_test_assign_device: + case XEN_DOMCTL_assign_device: + case XEN_DOMCTL_deassign_device: + switch ( op->u.assign_device.dev ) + { +#ifdef CONFIG_HAS_PCI + case XEN_DOMCTL_DEV_PCI: + return op->cmd != XEN_DOMCTL_deassign_device + ? flask_assign_device( + d, op->u.assign_device.u.pci.machine_sbdf) + : flask_deassign_device( + d, op->u.assign_device.u.pci.machine_sbdf); +#endif + +#ifdef CONFIG_HAS_DEVICE_TREE + case XEN_DOMCTL_DEV_DT: + { + struct dt_device_node *dev; + int ret = dt_find_node_by_gpath(op->u.assign_device.u.dt.path, + op->u.assign_device.u.dt.size, + &dev); + + if ( ret ) + return ret; + + op->u.assign_device.u.dt.dev = dev; + + return op->cmd != XEN_DOMCTL_deassign_device + ? flask_assign_dtdevice(d, dt_node_full_name(dev)) + : flask_deassign_dtdevice(d, dt_node_full_name(dev)); + } +#endif + + default: + /* Unknown type. */ + break; + } + return avc_unknown_permission("assign_device", op->cmd); + +#endif /* CONFIG_HAS_PASSTHROUGH */ + case XEN_DOMCTL_mem_sharing_op: return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING); @@ -787,9 +838,8 @@ return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__TRIGGER); case XEN_DOMCTL_set_access_required: - return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT); - case XEN_DOMCTL_monitor_op: + case XEN_DOMCTL_vm_event_op: return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT); case XEN_DOMCTL_debug_op: @@ -851,23 +901,19 @@ return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SET_LLC_COLORS); default: - return avc_unknown_permission("domctl", cmd); + return avc_unknown_permission("domctl", op->cmd); } } -static int cf_check flask_sysctl(int cmd) +static int cf_check flask_sysctl(const struct xen_sysctl *op) { - switch ( cmd ) + switch ( op->cmd ) { - /* These have individual XSM hooks */ case XEN_SYSCTL_readconsole: - case XEN_SYSCTL_getdomaininfolist: - case XEN_SYSCTL_page_offline_op: - case XEN_SYSCTL_scheduler_op: -#ifdef CONFIG_X86 - case XEN_SYSCTL_cpu_hotplug: -#endif - return 0; + return domain_has_xen(current->domain, + XEN__READCONSOLE | + (op->u.readconsole.clear ? XEN__CLEARCONSOLE + : 0)); case XEN_SYSCTL_tbuf_op: return domain_has_xen(current->domain, XEN__TBUFCONTROL); @@ -893,12 +939,32 @@ case XEN_SYSCTL_pm_op: return domain_has_xen(current->domain, XEN__PM_OP); + case XEN_SYSCTL_page_offline_op: + switch ( op->u.page_offline.cmd ) + { + case sysctl_page_offline: + return flask_resource_unplug_core(); + + case sysctl_page_online: + return flask_resource_plug_core(); + + case sysctl_query_page_offline: + return flask_resource_use_core(); + + default: + return avc_unknown_permission("page_offline", + op->u.page_offline.cmd); + } + case XEN_SYSCTL_lockprof_op: return domain_has_xen(current->domain, XEN__LOCKPROF); case XEN_SYSCTL_cpupool_op: return domain_has_xen(current->domain, XEN__CPUPOOL_OP); + case XEN_SYSCTL_scheduler_op: + return flask_sysctl_scheduler_op(op->u.scheduler_op.cmd); + case XEN_SYSCTL_physinfo: case XEN_SYSCTL_cputopoinfo: case XEN_SYSCTL_numainfo: @@ -906,6 +972,26 @@ case XEN_SYSCTL_get_cpu_policy: return domain_has_xen(current->domain, XEN__PHYSINFO); + case XEN_SYSCTL_getdomaininfolist: + return flask_getdomaininfo(dom_xen); + +#ifdef CONFIG_X86 + case XEN_SYSCTL_cpu_hotplug: + switch ( op->u.cpu_hotplug.op ) + { + case XEN_SYSCTL_CPU_HOTPLUG_ONLINE: + case XEN_SYSCTL_CPU_HOTPLUG_SMT_ENABLE: + return flask_resource_plug_core(); + + case XEN_SYSCTL_CPU_HOTPLUG_OFFLINE: + case XEN_SYSCTL_CPU_HOTPLUG_SMT_DISABLE: + return flask_resource_unplug_core(); + + default: + return avc_unknown_permission("cpu_hotplug", op->u.cpu_hotplug.op); + } +#endif + case XEN_SYSCTL_psr_cmt_op: return avc_current_has_perm(SECINITSID_XEN, SECCLASS_XEN2, XEN2__PSR_CMT_OP, NULL); @@ -929,20 +1015,10 @@ XEN2__COVERAGE_OP, NULL); default: - return avc_unknown_permission("sysctl", cmd); + return avc_unknown_permission("sysctl", op->cmd); } } -static int cf_check flask_readconsole(uint32_t clear) -{ - uint32_t perms = XEN__READCONSOLE; - - if ( clear ) - perms |= XEN__CLEARCONSOLE; - - return domain_has_xen(current->domain, perms); -} - static inline uint32_t resource_to_perm(uint8_t access) { if ( access ) @@ -1193,12 +1269,12 @@ } -static int cf_check flask_resource_plug_core(void) +static int flask_resource_plug_core(void) { return avc_current_has_perm(SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__PLUG, NULL); } -static int cf_check flask_resource_unplug_core(void) +static int flask_resource_unplug_core(void) { return avc_current_has_perm(SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__UNPLUG, NULL); } @@ -1271,21 +1347,6 @@ return avc_current_has_perm(SECINITSID_XEN, SECCLASS_RESOURCE, RESOURCE__SETUP, NULL); } -static inline int cf_check flask_page_offline(uint32_t cmd) -{ - switch ( cmd ) - { - case sysctl_page_offline: - return flask_resource_unplug_core(); - case sysctl_page_online: - return flask_resource_plug_core(); - case sysctl_query_page_offline: - return flask_resource_use_core(); - default: - return avc_unknown_permission("page_offline", cmd); - } -} - static inline int cf_check flask_hypfs_op(void) { return domain_has_xen(current->domain, XEN__HYPFS_OP); @@ -1356,11 +1417,6 @@ return current_has_perm(d, SECCLASS_HVM, HVM__ALTP2MHVM_OP); } -static int cf_check flask_vm_event_control(struct domain *d, int mode, int op) -{ - return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT); -} - #ifdef CONFIG_MEM_ACCESS static int cf_check flask_mem_access(struct domain *d) { @@ -1407,7 +1463,7 @@ return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL); } -static int cf_check flask_assign_device(struct domain *d, uint32_t machine_bdf) +static int flask_assign_device(struct domain *d, uint32_t machine_bdf) { uint32_t dsid, rsid; int rc = -EPERM; @@ -1437,7 +1493,7 @@ return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad); } -static int cf_check flask_deassign_device( +static int flask_deassign_device( struct domain *d, uint32_t machine_bdf) { uint32_t rsid; @@ -1469,7 +1525,7 @@ NULL); } -static int cf_check flask_assign_dtdevice(struct domain *d, const char *dtpath) +static int flask_assign_dtdevice(struct domain *d, const char *dtpath) { uint32_t dsid, rsid; int rc = -EPERM; @@ -1499,7 +1555,7 @@ return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad); } -static int cf_check flask_deassign_dtdevice( +static int flask_deassign_dtdevice( struct domain *d, const char *dtpath) { uint32_t rsid; @@ -1523,12 +1579,13 @@ switch ( op ) { #ifdef CONFIG_X86 - /* These operations have their own XSM hooks */ case XENPF_cpu_online: - case XENPF_cpu_offline: case XENPF_cpu_hotadd: case XENPF_mem_hotadd: - return 0; + return flask_resource_plug_core(); + + case XENPF_cpu_offline: + return flask_resource_unplug_core(); #endif case XENPF_settime32: @@ -1596,7 +1653,7 @@ return domain_has_xen(current->domain, XEN__MCA_OP); } -static int cf_check flask_shadow_control(struct domain *d, uint32_t op) +static int flask_shadow_control(struct domain *d, unsigned int op) { uint32_t perm; @@ -1874,12 +1931,9 @@ .security_domaininfo = flask_security_domaininfo, .domain_create = flask_domain_create, .getdomaininfo = flask_getdomaininfo, - .domctl_scheduler_op = flask_domctl_scheduler_op, - .sysctl_scheduler_op = flask_sysctl_scheduler_op, .set_target = flask_set_target, .domctl = flask_domctl, .sysctl = flask_sysctl, - .readconsole = flask_readconsole, .evtchn_unbound = flask_evtchn_unbound, .evtchn_interdomain = flask_evtchn_interdomain, @@ -1928,17 +1982,15 @@ .irq_permission = flask_irq_permission, .iomem_permission = flask_iomem_permission, .iomem_mapping = flask_iomem_mapping, + .iomem_mapping_vpci = flask_iomem_mapping, .pci_config_permission = flask_pci_config_permission, - .resource_plug_core = flask_resource_plug_core, - .resource_unplug_core = flask_resource_unplug_core, .resource_plug_pci = flask_resource_plug_pci, .resource_unplug_pci = flask_resource_unplug_pci, .resource_setup_pci = flask_resource_setup_pci, .resource_setup_gsi = flask_resource_setup_gsi, .resource_setup_misc = flask_resource_setup_misc, - .page_offline = flask_page_offline, .hypfs_op = flask_hypfs_op, .hvm_param = flask_hvm_param, .hvm_param_altp2mhvm = flask_hvm_param_altp2mhvm, @@ -1947,8 +1999,6 @@ .do_xsm_op = do_flask_op, .get_vnumainfo = flask_get_vnumainfo, - .vm_event_control = flask_vm_event_control, - #ifdef CONFIG_MEM_ACCESS .mem_access = flask_mem_access, #endif @@ -1971,19 +2021,11 @@ #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI) .get_device_group = flask_get_device_group, - .assign_device = flask_assign_device, - .deassign_device = flask_deassign_device, -#endif - -#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE) - .assign_dtdevice = flask_assign_dtdevice, - .deassign_dtdevice = flask_deassign_dtdevice, #endif .platform_op = flask_platform_op, #ifdef CONFIG_X86 .do_mca = flask_do_mca, - .shadow_control = flask_shadow_control, .mem_sharing_op = flask_mem_sharing_op, .apic = flask_apic, .machine_memory_map = flask_machine_memory_map,