Version in base suite: 4.20.3+127-gc42374a105-0+deb13u1 Base version: xen_4.20.3+127-gc42374a105-0+deb13u1 Target version: xen_4.20.4+39-gf1e1321c87-0+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/x/xen/xen_4.20.3+127-gc42374a105-0+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/x/xen/xen_4.20.4+39-gf1e1321c87-0+deb13u1.dsc debian/changelog | 32 ++++++++++++++++ tools/include/xen-tools/common-macros.h | 2 + tools/ocaml/libs/xc/xenctrl_stubs.c | 37 +++++++++++++----- tools/ocaml/xenstored/connection.ml | 4 -- tools/ocaml/xenstored/history.ml | 4 -- tools/ocaml/xenstored/process.ml | 26 ++++++++----- xen/Makefile | 2 - xen/Rules.mk | 2 - xen/arch/arm/arm64/vsysreg.c | 63 +++++++++++++++++++++++++++----- xen/arch/arm/cpufeature.c | 18 +++++++++ xen/arch/arm/domain.c | 2 - xen/arch/arm/domctl.c | 2 + xen/arch/arm/gic.c | 10 ++++- xen/arch/arm/include/asm/arm64/hsr.h | 1 xen/arch/arm/include/asm/cpregs.h | 1 xen/arch/arm/include/asm/cpufeature.h | 27 ++++++++++--- xen/arch/arm/include/asm/gic.h | 2 - xen/arch/arm/include/asm/page.h | 29 ++++++++++---- xen/arch/arm/include/asm/processor.h | 2 + xen/arch/arm/smpboot.c | 11 ++++- xen/arch/arm/traps.c | 5 ++ xen/arch/arm/vcpreg.c | 35 ++++++++++++++--- xen/arch/x86/boot/mkelf32.c | 2 - xen/arch/x86/cpu/amd.c | 7 +++ xen/arch/x86/cpu/microcode/intel.c | 42 +++++++++++++++++++++ xen/arch/x86/e820.c | 8 +++- xen/arch/x86/hvm/emulate.c | 1 xen/arch/x86/hvm/viridian/synic.c | 9 +++- xen/arch/x86/hvm/vmx/vmx.c | 30 +++++++++------ xen/arch/x86/hvm/vmx/vvmx.c | 2 + xen/arch/x86/include/asm/config.h | 23 ++++++++++- xen/arch/x86/include/asm/desc.h | 10 +++++ xen/arch/x86/include/asm/e820.h | 3 + xen/arch/x86/include/asm/hvm/vmx/vmx.h | 2 + xen/arch/x86/include/asm/perfc_defn.h | 2 - xen/arch/x86/mm.c | 45 +++++++++++++++++++++- xen/arch/x86/nmi.c | 20 ++++++---- xen/arch/x86/pci.c | 5 +- xen/arch/x86/setup.c | 11 +++-- xen/arch/x86/x86_64/asm-offsets.c | 1 xen/arch/x86/x86_64/entry.S | 7 +++ xen/arch/x86/x86_64/mmconfig_64.c | 6 ++- xen/arch/x86/x86_64/pci.c | 8 ++-- xen/arch/x86/x86_emulate/x86_emulate.c | 2 - xen/common/device-tree/bootfdt.c | 6 +++ xen/common/efi/common-stub.c | 12 ++++-- xen/common/event_fifo.c | 5 +- xen/common/grant_table.c | 45 +++++++++++++++++++--- xen/common/memory.c | 21 ---------- xen/common/page_alloc.c | 34 +++++++++-------- xen/common/radix-tree.c | 41 +++++--------------- xen/common/sched/core.c | 43 +++++++++++++++++++-- xen/common/sched/credit.c | 4 ++ xen/common/sched/rt.c | 16 +++++--- xen/drivers/passthrough/x86/hvm.c | 6 +++ xen/drivers/vpci/vpci.c | 6 ++- xen/include/public/arch-arm.h | 3 + xen/include/xen/mm.h | 2 - xen/include/xen/sched.h | 5 ++ 59 files changed, 608 insertions(+), 204 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpw6jilt7r/xen_4.20.3+127-gc42374a105-0+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpw6jilt7r/xen_4.20.4+39-gf1e1321c87-0+deb13u1.dsc: no acceptable signature found diff -Nru xen-4.20.3+127-gc42374a105/debian/changelog xen-4.20.4+39-gf1e1321c87/debian/changelog --- xen-4.20.3+127-gc42374a105/debian/changelog 2026-07-31 21:59:26.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/debian/changelog 2026-10-16 14:28:47.000000000 +0000 @@ -1,3 +1,35 @@ +xen (4.20.4+39-gf1e1321c87-0+deb13u1) trixie-security; urgency=medium + + * Update to new upstream version 4.20.4+39-gf1e1321c87, which also contains + security fixes for the following issues: + - x86: DMs may cause mem leak by IRQ binding + XSA-509 CVE-2026-62437 + - x86: improper handling of HVM emulation return codes + XSA-510 CVE-2026-79602 + - Unconditionally do TLB flushing ahead of page scrubbing + XSA-511 CVE-2026-79603 + - oxenstored: Unbounded accumulation of watches + XSA-512 CVE-2026-79604 + - x86/AMD: ineffectual Zenbleed workaround + XSA-515 CVE-2026-79608 + - x86: XPTI may break on huge-memory systems + XSA-516 CVE-2026-79609 + - grant-table: double version change race + XSA-517 CVE-2026-79610 + - VMX: VMentry failure with branch tracing and blocked states + XSA-518 CVE-2026-79611 + - Arm: multiple issues with GNTTABOP_cache_flush + XSA-519 CVE-2026-102699 CVE-2026-102702 + - gnttab: cache-flush handling may cause page reference leak + XSA-520 CVE-2026-102700 + * Note that the following XSA are not listed, because... + - XSA-513 applies to blktap which is not included in Debian + - XSA-514 only applies to Xen 4.22 + - XSA-521 applies to blktap which is not included in Debian + - XSA-522 has patches for the Linux kernel + + -- Hans van Kranenburg Fri, 16 Oct 2026 16:28:47 +0200 + 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 diff -Nru xen-4.20.3+127-gc42374a105/tools/include/xen-tools/common-macros.h xen-4.20.4+39-gf1e1321c87/tools/include/xen-tools/common-macros.h --- xen-4.20.3+127-gc42374a105/tools/include/xen-tools/common-macros.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/tools/include/xen-tools/common-macros.h 2026-10-13 13:02:22.000000000 +0000 @@ -68,6 +68,8 @@ }) #endif +#define IS_ALIGNED(val, align) (!((val) & ((align) - 1))) + #ifndef ROUNDUP #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) #endif diff -Nru xen-4.20.3+127-gc42374a105/tools/ocaml/libs/xc/xenctrl_stubs.c xen-4.20.4+39-gf1e1321c87/tools/ocaml/libs/xc/xenctrl_stubs.c --- xen-4.20.3+127-gc42374a105/tools/ocaml/libs/xc/xenctrl_stubs.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/tools/ocaml/libs/xc/xenctrl_stubs.c 2026-10-13 13:02:22.000000000 +0000 @@ -401,7 +401,8 @@ static value alloc_domaininfo(xc_domaininfo_t * info) { CAMLparam0(); - CAMLlocal5(result, tmp, arch_config, x86_arch_config, emul_list); + CAMLlocal4(result, tmp, arch_config, emul_list); + int tag = -1; int i; result = caml_alloc_tuple(17); @@ -430,7 +431,22 @@ Store_field(result, 15, tmp); -#if defined(__i386__) || defined(__x86_64__) +#if defined(__arm__) || defined(__aarch64__) + + tag = 0; /* tag ARM */ + + /* xen_arm_arch_domainconfig */ + arch_config = caml_alloc_tuple(3); + Field(arch_config, 0) = Val_int(info->arch_config.gic_version); + Field(arch_config, 1) = Val_int(info->arch_config.nr_spis); + + tmp = caml_copy_int32(info->arch_config.clock_frequency); + Field(arch_config, 2) = tmp; + +#elif defined(__i386__) || defined(__x86_64__) + + tag = 1; /* tag x86 */ + /* * emulation_flags: x86_arch_emulation_flags list; */ @@ -439,16 +455,17 @@ (info->arch_config.emulation_flags); /* xen_x86_arch_domainconfig */ - x86_arch_config = caml_alloc_tuple(1); - Store_field(x86_arch_config, 0, emul_list); + arch_config = caml_alloc_tuple(1); + Field(arch_config, 0) = emul_list; - /* arch_config: arch_domainconfig */ - arch_config = caml_alloc_small(1, 1); - - Store_field(arch_config, 0, x86_arch_config); - - Store_field(result, 16, arch_config); #endif + if (tag < 0) + caml_failwith("Unimplemented architecture in alloc_domaininfo()"); + + /* arch_config: arch_domainconfig */ + tmp = caml_alloc_small(1, tag); + Field(tmp, 0) = arch_config; + Field(result, 16) = tmp; CAMLreturn(result); } diff -Nru xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/connection.ml xen-4.20.4+39-gf1e1321c87/tools/ocaml/xenstored/connection.ml --- xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/connection.ml 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/tools/ocaml/xenstored/connection.ml 2026-10-13 13:02:22.000000000 +0000 @@ -148,13 +148,11 @@ let initial_next_tid = 1 let do_reconnect con = + (* transactions and watches handled by caller *) Xenbus.Xb.reconnect con.xb; (* dom is the same *) - Hashtbl.clear con.transactions; con.next_tid <- initial_next_tid; - Hashtbl.clear con.watches; (* anonid is the same *) - con.nb_watches <- 0; con.stat_nb_ops <- 0; (* perm is the same *) () diff -Nru xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/history.ml xen-4.20.4+39-gf1e1321c87/tools/ocaml/xenstored/history.ml --- xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/history.ml 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/tools/ocaml/xenstored/history.ml 2026-10-13 13:02:22.000000000 +0000 @@ -39,10 +39,6 @@ trim ~txn (); success -let reconnect con = - trim (); - Connection.do_reconnect con - let push (x: history_record) = let dom = x.con.Connection.dom in match dom with diff -Nru xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/process.ml xen-4.20.4+39-gf1e1321c87/tools/ocaml/xenstored/process.ml --- xen-4.20.3+127-gc42374a105/tools/ocaml/xenstored/process.ml 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/tools/ocaml/xenstored/process.ml 2026-10-13 13:02:22.000000000 +0000 @@ -345,10 +345,20 @@ in if domid = Define.domid_self || Domains.exist domains domid then "T\000" else "F\000" -(* only in xen >= 4.2 *) -let do_reset_watches con _t _domains cons _data = +let reset_watches_and_transactions cons con = Connections.del_watches cons con; - Connection.del_transactions con + Connection.del_transactions con; + History.trim () + +let do_reset_watches con _t _domains cons _data = + reset_watches_and_transactions cons con + +let do_reconnect cons con = + let domstr = Connection.get_domstr con in + info "%s requests a reconnect" domstr; + reset_watches_and_transactions cons con; + Connection.do_reconnect con; + info "%s reconnection complete" domstr (* only in >= xen3.3 *) let do_set_target con _t _domains cons data = @@ -735,9 +745,7 @@ if Connection.can_input con then Connection.do_input con else None with Xenbus.Xb.Reconnect -> - info "%s requests a reconnect" (Connection.get_domstr con); - History.reconnect con; - info "%s reconnection complete" (Connection.get_domstr con); + do_reconnect cons con; None | Invalid_argument exp | Failure exp -> error "caught exception %s" exp; @@ -760,7 +768,7 @@ write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data; Connection.incr_ops con -let do_output _store _cons _doms con = +let do_output _store cons _doms con = Connection.source_flush_watchevents con; if Connection.has_output con then ( if Connection.has_new_output con then ( @@ -775,8 +783,6 @@ try ignore (Connection.do_output con) with Xenbus.Xb.Reconnect -> - info "%s requests a reconnect" (Connection.get_domstr con); - History.reconnect con; - info "%s reconnection complete" (Connection.get_domstr con) + do_reconnect cons con ) diff -Nru xen-4.20.3+127-gc42374a105/xen/Makefile xen-4.20.4+39-gf1e1321c87/xen/Makefile --- xen-4.20.3+127-gc42374a105/xen/Makefile 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/Makefile 2026-10-13 13:02:22.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 ?= .4-pre$(XEN_VENDORVERSION) +export XEN_EXTRAVERSION ?= .5-pre$(XEN_VENDORVERSION) export XEN_FULLVERSION = $(XEN_VERSION).$(XEN_SUBVERSION)$(XEN_EXTRAVERSION) -include xen-version diff -Nru xen-4.20.3+127-gc42374a105/xen/Rules.mk xen-4.20.4+39-gf1e1321c87/xen/Rules.mk --- xen-4.20.3+127-gc42374a105/xen/Rules.mk 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/Rules.mk 2026-10-13 13:02:22.000000000 +0000 @@ -259,7 +259,7 @@ define cmd_obj_init_o $(OBJDUMP) -h $< | while read idx name sz rest; do \ case "$$name" in \ - .*.local) ;; \ + .*.local|.data.rel.ro|.data.rel.ro.*) ;; \ .text|.text.*|.data|.data.*|.bss|.bss.*) \ test $$(echo $$sz | sed 's,00*,0,') != 0 || continue; \ echo "Error: size of $<:$$name is 0x$$sz" >&2; \ diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/arm64/vsysreg.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/arm64/vsysreg.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/arm64/vsysreg.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/arm64/vsysreg.c 2026-10-13 13:02:22.000000000 +0000 @@ -229,10 +229,7 @@ */ case HSR_SYSREG_PMINTENSET_EL1: case HSR_SYSREG_PMINTENCLR_EL1: - /* - * Accessible from EL1 only, but if EL0 trap happens handle as - * undef. - */ + case HSR_SYSREG_PMMIR_EL1: return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1); case HSR_SYSREG_PMUSERENR_EL0: /* RO at EL0. RAZ/WI at EL1 */ @@ -306,8 +303,32 @@ GENERATE_TID3_INFO(ID_PFR0_EL1, pfr32, 0) GENERATE_TID3_INFO(ID_PFR1_EL1, pfr32, 1) GENERATE_TID3_INFO(ID_PFR2_EL1, pfr32, 2) - GENERATE_TID3_INFO(ID_DFR0_EL1, dbg32, 0) - GENERATE_TID3_INFO(ID_DFR1_EL1, dbg32, 1) + + case HSR_SYSREG_ID_DFR0_EL1: + { + union cpuinfo_dbg32 info_dbg32 = domain_cpuinfo.dbg32; + + if ( !is_vpmu_domain(v->domain) ) + info_dbg32.perfmon = 0; + + return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 1, + info_dbg32.bits[0]); + } + + case HSR_SYSREG_ID_DFR1_EL1: + { + union cpuinfo_dbg32 info_dbg32 = domain_cpuinfo.dbg32; + + if ( !is_vpmu_domain(v->domain) ) + { + info_dbg32.mtpmu = 0; + info_dbg32.hpmn0 = 0; + } + + return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 1, + info_dbg32.bits[1]); + } + GENERATE_TID3_INFO(ID_AFR0_EL1, aux32, 0) GENERATE_TID3_INFO(ID_MMFR0_EL1, mm32, 0) GENERATE_TID3_INFO(ID_MMFR1_EL1, mm32, 1) @@ -348,8 +369,34 @@ } GENERATE_TID3_INFO(ID_AA64PFR1_EL1, pfr64, 1) - GENERATE_TID3_INFO(ID_AA64DFR0_EL1, dbg64, 0) - GENERATE_TID3_INFO(ID_AA64DFR1_EL1, dbg64, 1) + + case HSR_SYSREG_ID_AA64DFR0_EL1: + { + union cpuinfo_dbg64 info_dbg64 = domain_cpuinfo.dbg64; + + if ( !is_vpmu_domain(v->domain) ) + { + info_dbg64.pmu_ver = 0; + info_dbg64.pmss = 0; + info_dbg64.mtpmu = 0; + info_dbg64.hpmn0 = 0; + } + + return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 1, + info_dbg64.bits[0]); + } + + case HSR_SYSREG_ID_AA64DFR1_EL1: + { + union cpuinfo_dbg64 info_dbg64 = domain_cpuinfo.dbg64; + + if ( !is_vpmu_domain(v->domain) ) + info_dbg64.pmicntr = 0; + + return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 1, + info_dbg64.bits[1]); + } + GENERATE_TID3_INFO(ID_AA64ISAR0_EL1, isa64, 0) GENERATE_TID3_INFO(ID_AA64ISAR1_EL1, isa64, 1) GENERATE_TID3_INFO(ID_AA64MMFR0_EL1, mm64, 0) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/cpufeature.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/cpufeature.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/cpufeature.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/cpufeature.c 2026-10-13 13:02:22.000000000 +0000 @@ -219,8 +219,26 @@ domain_cpuinfo.isa64.api = 0; domain_cpuinfo.isa64.gpa = 0; domain_cpuinfo.isa64.gpi = 0; + + /* Hide SPE, DPFZS, TRBE, BRBE, Trace Extensions, SPMU, ITE and EBEP */ + domain_cpuinfo.dbg64.trace_ver = 0; + domain_cpuinfo.dbg64.pms_ver = 0; + domain_cpuinfo.dbg64.dpfzs = 0; + domain_cpuinfo.dbg64.trace_filt = 0; + domain_cpuinfo.dbg64.trace_buffer = 0; + domain_cpuinfo.dbg64.ext_trc_buff = 0; + domain_cpuinfo.dbg64.brbe = 0; + domain_cpuinfo.dbg64.syspmuid = 0; + domain_cpuinfo.dbg64.spmu = 0; + domain_cpuinfo.dbg64.ite = 0; + domain_cpuinfo.dbg64.ebep = 0; #endif + /* Hide Trace Extensions for AArch32 domain */ + domain_cpuinfo.dbg32.coptrc = 0; + domain_cpuinfo.dbg32.mmaptrc = 0; + domain_cpuinfo.dbg32.tracefilt = 0; + /* Hide AMU support */ #ifdef CONFIG_ARM_64 domain_cpuinfo.pfr64.amu = 0; diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/domain.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/domain.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/domain.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/domain.c 2026-10-13 13:02:22.000000000 +0000 @@ -555,7 +555,7 @@ v->arch.hcr_el2 = get_default_hcr_flags(); v->arch.mdcr_el2 = HDCR_TDRA | HDCR_TDOSA | HDCR_TDA; - if ( !(v->domain->options & XEN_DOMCTL_CDF_vpmu) ) + if ( !is_vpmu_domain(v->domain) ) v->arch.mdcr_el2 |= HDCR_TPM | HDCR_TPMCR; if ( (rc = vcpu_vgic_init(v)) != 0 ) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/domctl.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/domctl.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/domctl.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/domctl.c 2026-10-13 13:02:22.000000000 +0000 @@ -24,6 +24,8 @@ info->flags |= XEN_DOMINF_hap; info->gpaddr_bits = p2m_ipa_bits; + + info->arch_config.gic_version = d->arch.vgic.version; } static int handle_vuart_init(struct domain *d, diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/gic.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/gic.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/gic.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/gic.c 2026-10-13 13:02:22.000000000 +0000 @@ -279,11 +279,17 @@ } /* Set up the per-CPU parts of the GIC for a secondary CPU */ -void gic_init_secondary_cpu(void) +int gic_init_secondary_cpu(void) { - gic_hw_ops->secondary_init(); + int rc = gic_hw_ops->secondary_init(); + + if ( rc ) + return rc; + /* Clear LR mask for secondary cpus */ clear_cpu_lr_mask(); + + return 0; } /* Shut down the per-CPU GIC interface */ diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/arm64/hsr.h xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/arm64/hsr.h --- xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/arm64/hsr.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/arm64/hsr.h 2026-10-13 13:02:22.000000000 +0000 @@ -84,6 +84,7 @@ #define HSR_SYSREG_FAR_EL1 HSR_SYSREG(3,0,c6, c0,0) #define HSR_SYSREG_PMINTENSET_EL1 HSR_SYSREG(3,0,c9,c14,1) #define HSR_SYSREG_PMINTENCLR_EL1 HSR_SYSREG(3,0,c9,c14,2) +#define HSR_SYSREG_PMMIR_EL1 HSR_SYSREG(3,0,c9,c14,6) #define HSR_SYSREG_MAIR_EL1 HSR_SYSREG(3,0,c10,c2,0) #define HSR_SYSREG_AMAIR_EL1 HSR_SYSREG(3,0,c10,c3,0) #define HSR_SYSREG_ICC_SGI1R_EL1 HSR_SYSREG(3,0,c12,c11,5) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/cpregs.h xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/cpregs.h --- xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/cpregs.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/cpregs.h 2026-10-13 13:02:22.000000000 +0000 @@ -244,6 +244,7 @@ #define PMINTENSET p15,0,c9,c14,1 /* Perf. Mon. Interrupt Enable Set Register */ #define PMINTENCLR p15,0,c9,c14,2 /* Perf. Mon. Interrupt Enable Clear Register */ #define PMOVSSET p15,0,c9,c14,3 /* Perf. Mon. Overflow Flag Status Set register */ +#define PMMIR p15,0,c9,c14,6 /* Perf. Mon. Machine Identification Register */ /* CP15 CR10: */ #define MAIR0 p15,0,c10,c2,0 /* Memory Attribute Indirection Register 0 AKA PRRR */ diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/cpufeature.h xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/cpufeature.h --- xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/cpufeature.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/cpufeature.h 2026-10-13 13:02:22.000000000 +0000 @@ -208,7 +208,7 @@ }; } pfr64; - union { + union cpuinfo_dbg64 { register_t bits[2]; struct { /* DFR0 */ @@ -216,19 +216,31 @@ unsigned long trace_ver:4; unsigned long pmu_ver:4; unsigned long brps:4; - unsigned long __res0:4; + unsigned long pmss:4; unsigned long wrps:4; unsigned long __res1:4; unsigned long ctx_cmps:4; unsigned long pms_ver:4; unsigned long double_lock:4; unsigned long trace_filt:4; - unsigned long __res2:4; + unsigned long trace_buffer:4; unsigned long mtpmu:4; - unsigned long __res3:12; + unsigned long brbe:4; + unsigned long ext_trc_buff:4; + unsigned long hpmn0:4; /* DFR1 */ - unsigned long __res4:64; + unsigned long syspmuid:8; + unsigned long brps1:8; + unsigned long wrps1:8; + unsigned long ctx_cmps1:8; + unsigned long spmu:4; + unsigned long pmicntr:4; + unsigned long able:4; + unsigned long ite:4; + unsigned long ebep:4; + unsigned long dpfzs:4; + unsigned long abl_cmps:8; }; } dbg64; @@ -401,7 +413,7 @@ }; } pfr32; - union { + union cpuinfo_dbg32 { register_t bits[2]; struct { /* DFR0 */ @@ -419,7 +431,8 @@ /* DFR1 */ unsigned long mtpmu:4; - unsigned long __res1:28; + unsigned long hpmn0:4; + unsigned long __res1:24; #ifdef CONFIG_ARM_64 unsigned long __res2:32; #endif diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/gic.h xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/gic.h --- xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/gic.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/gic.h 2026-10-13 13:02:22.000000000 +0000 @@ -291,7 +291,7 @@ /* Bring up the interrupt controller, and report # cpus attached */ extern void gic_init(void); /* Bring up a secondary CPU's per-CPU GIC interface */ -extern void gic_init_secondary_cpu(void); +extern int gic_init_secondary_cpu(void); /* Take down a CPU's per-CPU GIC interface */ extern void gic_disable_cpu(void); /* setup the gic virtual interface for a guest */ diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/page.h xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/page.h --- xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/page.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/page.h 2026-10-13 13:02:22.000000000 +0000 @@ -162,7 +162,7 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) { size_t cacheline_mask = dcache_line_bytes - 1; - unsigned long idx = 0; + unsigned long partial_head; if ( !size ) return 0; @@ -172,21 +172,34 @@ dsb(sy); /* So the CPU issues all writes to the range */ - if ( (uintptr_t)p & cacheline_mask ) + /* + * A cacheline only partially covered by the region has to be cleaned as + * well as invalidated, so that data living outside of the region is not + * discarded. + */ + partial_head = (uintptr_t)p & cacheline_mask; + if ( partial_head ) { - size -= dcache_line_bytes - ((uintptr_t)p & cacheline_mask); - p = (void *)((uintptr_t)p & ~cacheline_mask); + unsigned long rem = dcache_line_bytes - partial_head; + asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); - p += dcache_line_bytes; + p += rem; + + /* The region may end within this cacheline, leaving nothing to do. */ + size -= rem; + if ( size > rem ) /* underflow */ + goto done; } for ( ; size >= dcache_line_bytes; - idx += dcache_line_bytes, size -= dcache_line_bytes ) - asm volatile (__invalidate_dcache_one(0) : : "r" (p + idx)); + p += dcache_line_bytes, size -= dcache_line_bytes ) + asm volatile (__invalidate_dcache_one(0) : : "r" (p)); + /* Partial tail must be cleaned as well. */ if ( size > 0 ) - asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p + idx)); + asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); + done: dsb(sy); /* So we know the flushes happen before continuing */ return 0; diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/processor.h xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/processor.h --- xen-4.20.3+127-gc42374a105/xen/arch/arm/include/asm/processor.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/include/asm/processor.h 2026-10-13 13:02:22.000000000 +0000 @@ -513,6 +513,7 @@ /* * 543210 BIT * 00XXLL -- XX Fault Level LL + * ..00LL -- Address Size Fault LL * ..01LL -- Translation Fault LL * ..10LL -- Access Fault LL * ..11LL -- Permission Fault LL @@ -526,6 +527,7 @@ #define FSC_TYPE_OTH (_AC(0x02,U)<<4) #define FSC_TYPE_IMPL (_AC(0x03,U)<<4) +#define FSC_FLT_ADDR_SIZE (0x00) #define FSC_FLT_TRANS (0x04) #define FSC_FLT_ACCESS (0x08) #define FSC_FLT_PERM (0x0c) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/smpboot.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/smpboot.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/smpboot.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/smpboot.c 2026-10-13 13:02:22.000000000 +0000 @@ -325,6 +325,7 @@ void asmlinkage start_secondary(void) { unsigned int cpuid = init_data.cpuid; + int rc; memset(get_cpu_info(), 0, sizeof (struct cpu_info)); @@ -372,6 +373,14 @@ stop_cpu(); } + rc = gic_init_secondary_cpu(); + if ( rc ) + { + printk(XENLOG_ERR "CPU%u: Failed to initialize the GIC: %d\n", + smp_processor_id(), rc); + stop_cpu(); + } + /* * system features must be updated only if we do not stop the core or * we might disable features due to a non used core (for example when @@ -379,8 +388,6 @@ */ update_system_features(¤t_cpu_data); - gic_init_secondary_cpu(); - set_current(idle_vcpu[cpuid]); /* Run local notifiers */ diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/traps.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/traps.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/traps.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/traps.c 2026-10-13 13:02:22.000000000 +0000 @@ -307,6 +307,10 @@ switch ( fsc & 0x3f ) { + case FSC_FLT_ADDR_SIZE ... FSC_FLT_ADDR_SIZE + 3: + msg = "Address size fault"; + *level = fsc & FSC_LL_MASK; + break; case FSC_FLT_TRANS ... FSC_FLT_TRANS + 3: msg = "Translation fault"; *level = fsc & FSC_LL_MASK; @@ -363,6 +367,7 @@ switch ( level ) { case -1: return ""; + case 0: return " at level 0 or TTBR"; case 1: return " at level 1"; case 2: return " at level 2"; case 3: return " at level 3"; diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/arm/vcpreg.c xen-4.20.4+39-gf1e1321c87/xen/arch/arm/vcpreg.c --- xen-4.20.3+127-gc42374a105/xen/arch/arm/vcpreg.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/arm/vcpreg.c 2026-10-13 13:02:22.000000000 +0000 @@ -278,10 +278,7 @@ * * NB: Both MDCR_EL2.TPM and MDCR_EL2.TPMCR cause trapping of PMCR. */ - /* We could trap ID_DFR0 and tell the guest we don't support - * performance monitoring, but Linux doesn't check the ID_DFR0. - * Therefore it will read PMCR. - * + /* * We tell the guest we have 0 counters. Unfortunately we must * always support PMCCNTR (the cyle counter): we just RAZ/WI for all * PM register, which doesn't crash the kernel at least @@ -294,7 +291,7 @@ return handle_raz_wi(regs, regidx, cp32.read, hsr, 1); case HSR_CPREG32(PMINTENSET): case HSR_CPREG32(PMINTENCLR): - /* EL1 only, however MDCR_EL2.TPM==1 means EL0 may trap here also. */ + case HSR_CPREG32(PMMIR): return handle_raz_wi(regs, regidx, cp32.read, hsr, 1); case HSR_CPREG32(PMCR): case HSR_CPREG32(PMCNTENSET): @@ -323,8 +320,32 @@ GENERATE_TID3_INFO(ID_PFR0, pfr32, 0) GENERATE_TID3_INFO(ID_PFR1, pfr32, 1) GENERATE_TID3_INFO(ID_PFR2, pfr32, 2) - GENERATE_TID3_INFO(ID_DFR0, dbg32, 0) - GENERATE_TID3_INFO(ID_DFR1, dbg32, 1) + + case HSR_CPREG32(ID_DFR0): + { + union cpuinfo_dbg32 info_dbg32 = domain_cpuinfo.dbg32; + + if ( !is_vpmu_domain(v->domain) ) + info_dbg32.perfmon = 0; + + return handle_ro_read_val(regs, regidx, cp32.read, hsr, 1, + info_dbg32.bits[0]); + } + + case HSR_CPREG32(ID_DFR1): + { + union cpuinfo_dbg32 info_dbg32 = domain_cpuinfo.dbg32; + + if ( !is_vpmu_domain(v->domain) ) + { + info_dbg32.mtpmu = 0; + info_dbg32.hpmn0 = 0; + } + + return handle_ro_read_val(regs, regidx, cp32.read, hsr, 1, + info_dbg32.bits[1]); + } + GENERATE_TID3_INFO(ID_AFR0, aux32, 0) GENERATE_TID3_INFO(ID_MMFR0, mm32, 0) GENERATE_TID3_INFO(ID_MMFR1, mm32, 1) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/boot/mkelf32.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/boot/mkelf32.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/boot/mkelf32.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/boot/mkelf32.c 2026-10-13 13:02:22.000000000 +0000 @@ -360,7 +360,7 @@ (void)lseek(infd, offset, SEEK_SET); note_sz = in64_phdr.p_memsz; - note_base = in64_phdr.p_vaddr - note_base; + note_base = in64_phdr.p_vaddr - note_base + loadbase; if ( in64_phdr.p_offset < offset || in64_phdr.p_offset + in64_phdr.p_filesz > offset + dat_siz ) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/amd.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/cpu/amd.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/amd.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/cpu/amd.c 2026-10-13 13:02:22.000000000 +0000 @@ -926,7 +926,12 @@ return is_zen2_uarch(); } - return (uint8_t)curr_rev >= fixed_rev; + /* + * Zenbleed can be mitigated by disabling Floating-Point + * Mov-Elimination, but this is expensive. Only do so when we + * don't have a fix in microcode. + */ + return (uint8_t)curr_rev < fixed_rev; } void amd_init_de_cfg(const struct cpuinfo_x86 *c) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/microcode/intel.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/cpu/microcode/intel.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/cpu/microcode/intel.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/cpu/microcode/intel.c 2026-10-13 13:02:22.000000000 +0000 @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -269,6 +270,46 @@ return false; } +static bool microcode_safe_to_load(const struct microcode_patch *mc) +{ + const struct cpu_signature *cpu_sig = &this_cpu(cpu_sig); + + /* + * Treat pre-production as always safe - anyone using pre-production + * microcode knows what they are doing, and can keep any resulting pieces. + */ + if ( (int)cpu_sig->rev < 0 || mc->rev < 0 ) + return true; + + /* + * GNR98 states that Granite Rapids systems hang when loading new ucode on + * sufficiently old firmware. GNR101 retroactively states that one ucode + * had an incorrect minimum revision field, in light of discovering GNR98. + * + * Both are incomplete statements of the problem. + * + * At the time of writing (August 2026), the believed safe sequence is: + * previous -> [0x01000380...0x010003f3] -> 0x01000405 -> any later + * + * Disallow known-unsafe loads while permitting believed-safe loads. For + * GNR, this allows multi-hop loading to get up to the latest. + */ + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model == INTEL_FAM6_GRANITERAPIDS_X && + boot_cpu_data.x86_mask == 1 && (cpu_sig->pf & 0x95) && + ((cpu_sig->rev < 0x01000380 && mc->rev >= 0x01000405) || + (cpu_sig->rev < 0x01000405 && mc->rev > 0x01000405)) ) + { + printk_once(XENLOG_WARNING "microcode: Granite Rapids erratum GNR98 detected. Skipping ucode 0x%08x\n" + XENLOG_WARNING "microcode: Firmware update recommended\n", + mc->rev); + return false; + } + + return true; +} + static int cf_check intel_compare( const struct microcode_patch *old, const struct microcode_patch *new) { @@ -361,6 +402,7 @@ * one with higher revision. */ if ( microcode_fits_cpu(mc) && + microcode_safe_to_load(mc) && (!saved || compare_revisions(saved->rev, mc->rev) == NEW_UCODE) ) saved = mc; diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/e820.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/e820.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/e820.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/e820.c 2026-10-13 13:02:22.000000000 +0000 @@ -680,7 +680,13 @@ /* Set E820_RAM area (@s,@e) as RESERVED in specified e820 map. */ int __init reserve_e820_ram(struct e820map *map, uint64_t s, uint64_t e) { - return e820_change_range_type(map, s, e, E820_RAM, E820_RESERVED); + int res = e820_change_range_type(map, s, e, E820_RAM, E820_RESERVED); + + if ( !res ) + printk("Failed to convert E820 RAM %"PRIx64"-%"PRIx64" to RESERVED\n", + s, e); + + return res; } unsigned long __init init_e820(const char *str, struct e820map *raw) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/emulate.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/emulate.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/emulate.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/emulate.c 2026-10-13 13:02:22.000000000 +0000 @@ -293,6 +293,7 @@ switch ( rc ) { case X86EMUL_OKAY: + case X86EMUL_RETRY: vio->req.state = STATE_IOREQ_NONE; break; case X86EMUL_UNHANDLEABLE: diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/viridian/synic.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/viridian/synic.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/viridian/synic.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/viridian/synic.c 2026-10-13 13:02:22.000000000 +0000 @@ -157,9 +157,14 @@ if ( !(viridian_feature_mask(d) & HVMPV_synic) ) return X86EMUL_EXCEPTION; - /* Vectors must be in the range 0x10-0xff inclusive */ + /* + * Vectors must be in the range 0x10-0xff inclusive unless the vector + * is masked since Windows 11 Hyper-V (26H1) has been seen to write + * this MSR to its default value, despite not being a spec compliant + * value. + */ new.as_uint64 = val; - if ( new.vector < 0x10 ) + if ( new.vector < 0x10 && !new.masked ) return X86EMUL_EXCEPTION; /* diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/vmx/vmx.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/vmx/vmx.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/vmx/vmx.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/vmx/vmx.c 2026-10-13 13:02:22.000000000 +0000 @@ -4281,26 +4281,30 @@ * We intercept #DB unconditionally to work around CVE-2015-8104 / * XSA-156 (guest-kernel induced host DoS). * - * STI/MovSS shadows block/defer interrupts/exceptions (exact - * details are complicated and poorly documented). Debug - * exceptions delayed for any reason are stored in the - * PENDING_DBG_EXCEPTIONS field. + * Most sources of #DB accumuate status in PENDING_DBG, which are + * then dispatched in priority order prior to fetching the next + * instruction. When the #DB intercept triggers, PENDING_DBG is 0 + * with the status bits having moved into EXIT_QUALIFICATION. * - * The falling edge of PENDING_DBG causes #DB to be delivered, - * resulting in a VMExit, as #DB is intercepted. The VMCS still - * reports blocked-by-STI/MovSS. + * At any point if Blocked-by-STI/MovSS are active, extra VMEntry + * consistency checks are applied, cross-checking EFLAGS.TF, + * PENDING_DBG.BS and DEBUGCTL.BTF. These consistency checks + * apply to Activity-state-HLT too, but Xen doesn't support this. * - * The VMEntry checks when EFLAGS.TF is set don't like a VMCS in - * this state. Despite a #DB queued in VMENTRY_INTR_INFO, the - * state is rejected as DR6.BS isn't pending. Fix this up. + * The VMCS state at the point of #DB intercept does not satisfy + * the consistency checks. In the case that a SingleStep should + * be pending, fill PENDING_DBG back in to satisfy the consitency + * check. */ if ( unlikely(regs->eflags & X86_EFLAGS_TF) ) { - unsigned long int_info; + unsigned long int_info, debugctl; __vmread(GUEST_INTERRUPTIBILITY_INFO, &int_info); + __vmread(GUEST_IA32_DEBUGCTL, &debugctl); - if ( int_info & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS) ) + if ( (int_info & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS)) && + !(debugctl & IA32_DEBUGCTLMSR_BTF) ) { unsigned long pending_dbg; @@ -4564,6 +4568,8 @@ case EXIT_REASON_MWAIT_INSTRUCTION: case EXIT_REASON_MONITOR_INSTRUCTION: case EXIT_REASON_GETSEC: + case EXIT_REASON_SEAMCALL: + case EXIT_REASON_TDCALL: /* * We should never exit on GETSEC because CR4.SMXE is always 0 when * running in guest context, and the CPU checks that before getting diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/vmx/vvmx.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/vmx/vvmx.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/hvm/vmx/vvmx.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/hvm/vmx/vvmx.c 2026-10-13 13:02:22.000000000 +0000 @@ -2504,6 +2504,8 @@ case EXIT_REASON_INVEPT: case EXIT_REASON_XSETBV: case EXIT_REASON_INVVPID: + case EXIT_REASON_SEAMCALL: + case EXIT_REASON_TDCALL: /* inject to L1 */ nvcpu->nv_vmexit_pending = 1; break; diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/config.h xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/config.h --- xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/config.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/config.h 2026-10-13 13:02:22.000000000 +0000 @@ -262,11 +262,30 @@ #define GDT_LDT_VIRT_START PERDOMAIN_VIRT_SLOT(0) #define GDT_LDT_VIRT_END (GDT_LDT_VIRT_START + (GDT_LDT_MBYTES << 20)) -/* The address of a particular VCPU's GDT or LDT. */ +/* + * The address of a particular VCPU's GDT or LDT; each is the architectural + * maximum of 64k. + */ +#define GDT_VIRT_SIZE KB(64) #define GDT_VIRT_START(v) \ (PERDOMAIN_VIRT_START + ((v)->vcpu_id << GDT_LDT_VCPU_VA_SHIFT)) #define LDT_VIRT_START(v) \ - (GDT_VIRT_START(v) + (64*1024)) + (GDT_VIRT_START(v) + GDT_VIRT_SIZE) + +/* + * The vCPU's effective root page table, mapped read-only in the last + * page of its GDT: the page after Xen's reserved range, beyond the + * GDT limit Xen loads (LAST_RESERVED_GDT_BYTE), so no selector can + * reach it. "Effective" is the root page table the vCPU is meant to + * run on after any transformation: the guest's own, or its shadow + * under shadow paging. XPTI does not transform it further but copies + * from it: the exit path reads the guest-visible L4 slots from here. + * Adding a reserved GDT page would mean moving the window out of the + * GDT first; pv_map_eff_root_pt() checks the layout at build time. + */ +#define PV_EFF_ROOT_PT_PAGE (FIRST_RESERVED_GDT_PAGE + 1) +#define PV_EFF_ROOT_PT_OFFSET (PV_EFF_ROOT_PT_PAGE << PAGE_SHIFT) +#define PV_EFF_ROOT_PT(v) (GDT_VIRT_START(v) + PV_EFF_ROOT_PT_OFFSET) /* map_domain_page() map cache. The second per-domain-mapping sub-area. */ #define MAPCACHE_VCPU_ENTRIES (CONFIG_PAGING_LEVELS * CONFIG_PAGING_LEVELS) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/desc.h xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/desc.h --- xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/desc.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/desc.h 2026-10-13 13:02:22.000000000 +0000 @@ -6,6 +6,16 @@ /* * Xen reserves a memory page of GDT entries. * No guest GDT entries exist beyond the Xen reserved area. + * + * The page after the reserved area, the last of the GDT's 64k, is the + * PV effective root-table window (PV_EFF_ROOT_PT_PAGE, config.h): + * beyond the GDT limit Xen loads (LAST_RESERVED_GDT_BYTE), so no + * selector reaches it. Xen uses only a few of the reserved page's + * 512 slots, so more Xen descriptors never need another page; if one + * were needed regardless, the window would have to move out of the + * GDT first (into a per-domain sub-area of its own), as this is the + * GDT's last page. pv_map_eff_root_pt() checks the layout at build + * time. */ #define NR_RESERVED_GDT_PAGES 1 #define NR_RESERVED_GDT_BYTES (NR_RESERVED_GDT_PAGES * PAGE_SIZE) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/e820.h xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/e820.h --- xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/e820.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/e820.h 2026-10-13 13:02:22.000000000 +0000 @@ -25,7 +25,8 @@ extern int sanitize_e820_map(struct e820entry *biosmap, unsigned int *pnr_map); extern int e820_all_mapped(u64 start, u64 end, unsigned type); -extern int reserve_e820_ram(struct e820map *map, uint64_t s, uint64_t e); +extern int __must_check reserve_e820_ram( + struct e820map *map, uint64_t s, uint64_t e); extern int e820_change_range_type( struct e820map *map, uint64_t s, uint64_t e, uint32_t orig_type, uint32_t new_type); diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/vmx/vmx.h xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/hvm/vmx/vmx.h --- xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/hvm/vmx/vmx.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/hvm/vmx/vmx.h 2026-10-13 13:02:22.000000000 +0000 @@ -201,6 +201,8 @@ #define EXIT_REASON_XRSTORS 64 #define EXIT_REASON_BUS_LOCK 74 #define EXIT_REASON_NOTIFY 75 +#define EXIT_REASON_SEAMCALL 76 +#define EXIT_REASON_TDCALL 77 /* Remember to also update VMX_PERF_EXIT_REASON_SIZE! */ /* diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/perfc_defn.h xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/perfc_defn.h --- xen-4.20.3+127-gc42374a105/xen/arch/x86/include/asm/perfc_defn.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/include/asm/perfc_defn.h 2026-10-13 13:02:22.000000000 +0000 @@ -6,7 +6,7 @@ #ifdef CONFIG_HVM -#define VMX_PERF_EXIT_REASON_SIZE 76 +#define VMX_PERF_EXIT_REASON_SIZE 78 #define VMEXIT_NPF_PERFC 143 #define SVM_PERF_EXIT_REASON_SIZE (VMEXIT_NPF_PERFC + 1) PERFCOUNTER_ARRAY(vmexits, "vmexits", diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/mm.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/mm.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/mm.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/mm.c 2026-10-13 13:02:22.000000000 +0000 @@ -518,13 +518,52 @@ nrspin_unlock(&d->page_alloc_lock); } +/* + * Map @mfn read-only at v's PV_EFF_ROOT_PT() window. The window lives in + * v's per-domain area, so v need not be current; the local flush is for + * when it is, with its own page tables loaded. + */ +static void pv_map_eff_root_pt(const struct vcpu *v, mfn_t mfn) +{ + /* + * The window must lie beyond the GDT limit Xen loads, so that no + * selector reaches it, and within the GDT's 64k. + */ + BUILD_BUG_ON(PV_EFF_ROOT_PT_OFFSET <= LAST_RESERVED_GDT_BYTE); + BUILD_BUG_ON(PV_EFF_ROOT_PT_OFFSET + PAGE_SIZE > GDT_VIRT_SIZE); + + l1e_write(pv_gdt_ptes(v) + PV_EFF_ROOT_PT_PAGE, + l1e_from_mfn(mfn, __PAGE_HYPERVISOR_RO)); + flush_tlb_one_local(PV_EFF_ROOT_PT(v)); +} + +/* + * Clear the window. Its lifetime is v->arch.cr3's: make_cr3() writes it + * wherever v->arch.cr3 is set, and vcpu_destroy_pagetables() clears it where + * v->arch.cr3 is zeroed. In shadow mode both name a top-level shadow, which + * shadow_teardown() releases before that point; nothing uses either once the + * vCPU can no longer run. + */ +static void pv_unmap_eff_root_pt(const struct vcpu *v) +{ + l1e_write(pv_gdt_ptes(v) + PV_EFF_ROOT_PT_PAGE, l1e_empty()); + flush_tlb_one_local(PV_EFF_ROOT_PT(v)); +} + void make_cr3(struct vcpu *v, mfn_t mfn) { struct domain *d = v->domain; v->arch.cr3 = mfn_x(mfn) << PAGE_SHIFT; - if ( is_pv_domain(d) && d->arch.pv.pcid ) - v->arch.cr3 |= get_pcid_bits(v, false); + + if ( is_pv_domain(d) ) + { + if ( d->arch.pv.pcid ) + v->arch.cr3 |= get_pcid_bits(v, false); + + if ( d->arch.pv.xpti ) + pv_map_eff_root_pt(v, mfn); + } } void write_ptbase(struct vcpu *v) @@ -3230,6 +3269,8 @@ return rc; v->arch.cr3 = 0; + if ( is_pv_domain(v->domain) && v->domain->arch.pv.xpti ) + pv_unmap_eff_root_pt(v); /* * Get the top-level guest page; either the guest_table itself, for diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/nmi.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/nmi.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/nmi.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/nmi.c 2026-10-13 13:02:22.000000000 +0000 @@ -345,14 +345,8 @@ wrmsr(MSR_P6_EVNTSEL(0), evntsel, 0); } -static void setup_p4_watchdog(void) +static void setup_p4_watchdog(uint64_t misc_enable) { - uint64_t misc_enable; - - rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); - if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL)) - return; - nmi_perfctr_msr = MSR_P4_IQ_PERFCTR0; nmi_p4_cccr_val = P4_NMI_IQ_CCCR0; if ( boot_cpu_data.x86_num_siblings == 2 ) @@ -384,6 +378,8 @@ void setup_apic_nmi_watchdog(void) { + uint64_t misc; + if ( nmi_watchdog == NMI_NONE ) return; @@ -394,6 +390,14 @@ break; case X86_VENDOR_INTEL: + rdmsrl(MSR_IA32_MISC_ENABLE, misc); + + if ( !(misc & MSR_IA32_MISC_ENABLE_PERF_AVAIL) ) + { + printk(XENLOG_WARNING "Intel Perfmon unavailable\n"); + break; + } + switch (boot_cpu_data.x86) { case 6: setup_p6_watchdog((boot_cpu_data.x86_model < 14) @@ -401,7 +405,7 @@ : CORE_EVENT_CPU_CLOCKS_NOT_HALTED); break; case 15: - setup_p4_watchdog(); + setup_p4_watchdog(misc); break; } break; diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/pci.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/pci.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/pci.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/pci.c 2026-10-13 13:02:22.000000000 +0000 @@ -73,8 +73,9 @@ unsigned int reg, unsigned int size, uint32_t *data) { + pci_sbdf_t sbdf = PCI_SBDF(seg, bdf); struct pci_dev *pdev; - int rc = xsm_pci_config_permission(XSM_HOOK, current->domain, bdf, + int rc = xsm_pci_config_permission(XSM_HOOK, current->domain, sbdf.sbdf, reg, reg + size - 1, 1); if ( rc < 0 ) @@ -90,7 +91,7 @@ pcidevs_lock(); - pdev = pci_get_pdev(NULL, PCI_SBDF(seg, bdf)); + pdev = pci_get_pdev(NULL, sbdf); if ( pdev ) rc = pci_msi_conf_write_intercept(pdev, reg, size, data); diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/setup.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/setup.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/setup.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/setup.c 2026-10-13 13:02:22.000000000 +0000 @@ -1583,7 +1583,8 @@ { uint64_t s = bi->mods[i].start, l = bi->mods[i].size; - reserve_e820_ram(&boot_e820, s, s + PAGE_ALIGN(l)); + if ( !reserve_e820_ram(&boot_e820, s, s + PAGE_ALIGN(l)) ) + panic("Failed to reserve boot module %u in E820\n", i); } if ( !xen_phys_start ) @@ -1596,11 +1597,13 @@ /* This needs to remain in sync with remove_xen_ranges(). */ if ( efi_boot_mem_unused(&eb_start, &eb_end) ) { - reserve_e820_ram(&boot_e820, __pa(_stext), __pa(eb_start)); - reserve_e820_ram(&boot_e820, __pa(eb_end), __pa(__2M_rwdata_end)); + if ( !reserve_e820_ram(&boot_e820, __pa(_stext), __pa(eb_start)) || + !reserve_e820_ram(&boot_e820, __pa(eb_end), __pa(__2M_rwdata_end)) ) + panic("Failed to reserve Xen in E820\n"); } else - reserve_e820_ram(&boot_e820, __pa(_stext), __pa(__2M_rwdata_end)); + if ( !reserve_e820_ram(&boot_e820, __pa(_stext), __pa(__2M_rwdata_end)) ) + panic("Failed to reserve Xen in E820\n"); /* Late kexec reservation (dynamic start address). */ kexec_reserve_area(); diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/asm-offsets.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/asm-offsets.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/asm-offsets.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/asm-offsets.c 2026-10-13 13:02:22.000000000 +0000 @@ -80,6 +80,7 @@ #undef OFFSET_EF + OFFSET(VCPU_id, struct vcpu, vcpu_id); OFFSET(VCPU_processor, struct vcpu, processor); OFFSET(VCPU_domain, struct vcpu, domain); OFFSET(VCPU_vcpu_info, struct vcpu, vcpu_info_area.map); diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/entry.S xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/entry.S --- xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/entry.S 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/entry.S 2026-10-13 13:02:22.000000000 +0000 @@ -170,9 +170,14 @@ movabs $PADDR_MASK & PAGE_MASK, %rsi movabs $DIRECTMAP_VIRT_START, %rcx and %rsi, %rdi - and %r9, %rsi add %rcx, %rdi + + /* Effective root page table is mapped at PV_EFF_ROOT_PT(v) */ + mov VCPU_id(%rbx), %esi + shl $GDT_LDT_VCPU_VA_SHIFT, %rsi + movabs $GDT_LDT_VIRT_START + PV_EFF_ROOT_PT_OFFSET, %rcx add %rcx, %rsi + mov $ROOT_PAGETABLE_FIRST_XEN_SLOT, %ecx mov root_table_offset(SH_LINEAR_PT_VIRT_START)*8(%rsi), %r8 mov %r8, root_table_offset(SH_LINEAR_PT_VIRT_START)*8(%rdi) diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/mmconfig_64.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/mmconfig_64.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/mmconfig_64.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/mmconfig_64.c 2026-10-13 13:02:22.000000000 +0000 @@ -61,7 +61,8 @@ char __iomem *addr; /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ - if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) { + if (unlikely((bus > 255) || (devfn > 255) || + (reg + len > PCI_CFG_SPACE_EXP_SIZE))) { err: *value = -1; return -EINVAL; } @@ -91,7 +92,8 @@ char __iomem *addr; /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ - if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) + if (unlikely((bus > 255) || (devfn > 255) || + (reg + len > PCI_CFG_SPACE_EXP_SIZE))) return -EINVAL; addr = pci_dev_base(seg, bus, devfn); diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/pci.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/pci.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_64/pci.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_64/pci.c 2026-10-13 13:02:22.000000000 +0000 @@ -26,7 +26,7 @@ uint16_t pci_conf_read16(pci_sbdf_t sbdf, unsigned int reg) { - if ( sbdf.seg || reg > 255 ) + if ( sbdf.seg || reg > 255 || !IS_ALIGNED(reg, 2) ) { uint32_t value; @@ -39,7 +39,7 @@ uint32_t pci_conf_read32(pci_sbdf_t sbdf, unsigned int reg) { - if ( sbdf.seg || reg > 255 ) + if ( sbdf.seg || reg > 255 || !IS_ALIGNED(reg, 4) ) { uint32_t value; @@ -60,7 +60,7 @@ void pci_conf_write16(pci_sbdf_t sbdf, unsigned int reg, uint16_t data) { - if ( sbdf.seg || reg > 255 ) + if ( sbdf.seg || reg > 255 || !IS_ALIGNED(reg, 2) ) pci_mmcfg_write(sbdf.seg, sbdf.bus, sbdf.devfn, reg, 2, data); else pci_conf_write(PCI_CONF_ADDRESS(sbdf, reg), reg & 2, 2, data); @@ -68,7 +68,7 @@ void pci_conf_write32(pci_sbdf_t sbdf, unsigned int reg, uint32_t data) { - if ( sbdf.seg || reg > 255 ) + if ( sbdf.seg || reg > 255 || !IS_ALIGNED(reg, 4) ) pci_mmcfg_write(sbdf.seg, sbdf.bus, sbdf.devfn, reg, 4, data); else pci_conf_write(PCI_CONF_ADDRESS(sbdf, reg), 0, 4, data); diff -Nru xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_emulate/x86_emulate.c xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_emulate/x86_emulate.c --- xen-4.20.3+127-gc42374a105/xen/arch/x86/x86_emulate/x86_emulate.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/arch/x86/x86_emulate/x86_emulate.c 2026-10-13 13:02:22.000000000 +0000 @@ -2459,8 +2459,8 @@ else { generate_exception_if(!n, X86_EXC_DE); - _regs.al = _regs.al % n; _regs.ah = _regs.al / n; + _regs.al = _regs.al % n; } _regs.eflags &= ~(X86_EFLAGS_SF | X86_EFLAGS_ZF | X86_EFLAGS_PF); _regs.eflags |= !_regs.al ? X86_EFLAGS_ZF : 0; diff -Nru xen-4.20.3+127-gc42374a105/xen/common/device-tree/bootfdt.c xen-4.20.4+39-gf1e1321c87/xen/common/device-tree/bootfdt.c --- xen-4.20.3+127-gc42374a105/xen/common/device-tree/bootfdt.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/device-tree/bootfdt.c 2026-10-13 13:02:22.000000000 +0000 @@ -471,6 +471,12 @@ /* No "xen,static-mem" present. */ return 0; + if ( !IS_ENABLED(CONFIG_STATIC_MEMORY) ) + { + printk("CONFIG_STATIC_MEMORY must be enabled for parsing xen,static-mem\n"); + return -EINVAL; + } + return device_tree_get_meminfo(fdt, node, "xen,static-mem", address_cells, size_cells, bootinfo_get_reserved_mem(), MEMBANK_STATIC_DOMAIN); diff -Nru xen-4.20.3+127-gc42374a105/xen/common/efi/common-stub.c xen-4.20.4+39-gf1e1321c87/xen/common/efi/common-stub.c --- xen-4.20.3+127-gc42374a105/xen/common/efi/common-stub.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/efi/common-stub.c 2026-10-13 13:02:22.000000000 +0000 @@ -28,10 +28,14 @@ #ifdef CONFIG_COMPAT -int efi_compat_get_info(uint32_t idx, union compat_pf_efi_info *) - __attribute__((__alias__("efi_get_info"))); +int efi_compat_get_info(uint32_t idx, union compat_pf_efi_info *info) +{ + return -ENOSYS; +} -int efi_compat_runtime_call(struct compat_pf_efi_runtime_call *) - __attribute__((__alias__("efi_runtime_call"))); +int efi_compat_runtime_call(struct compat_pf_efi_runtime_call *op) +{ + return -ENOSYS; +} #endif diff -Nru xen-4.20.3+127-gc42374a105/xen/common/event_fifo.c xen-4.20.4+39-gf1e1321c87/xen/common/event_fifo.c --- xen-4.20.3+127-gc42374a105/xen/common/event_fifo.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/event_fifo.c 2026-10-13 13:02:22.000000000 +0000 @@ -71,11 +71,10 @@ */ smp_rmb(); - p = array_index_nospec(port / EVTCHN_FIFO_EVENT_WORDS_PER_PAGE, - d->evtchn_fifo->num_evtchns); + p = array_index_nospec(port, d->evtchn_fifo->num_evtchns); w = port % EVTCHN_FIFO_EVENT_WORDS_PER_PAGE; - return d->evtchn_fifo->event_array[p] + w; + return d->evtchn_fifo->event_array[p / EVTCHN_FIFO_EVENT_WORDS_PER_PAGE] + w; } static void cf_check evtchn_fifo_init(struct domain *d, struct evtchn *evtchn) diff -Nru xen-4.20.3+127-gc42374a105/xen/common/grant_table.c xen-4.20.4+39-gf1e1321c87/xen/common/grant_table.c --- xen-4.20.3+127-gc42374a105/xen/common/grant_table.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/grant_table.c 2026-10-13 13:02:22.000000000 +0000 @@ -983,6 +983,13 @@ return ERR_PTR(-EINVAL); } +static bool grant_map_is_ro(struct active_grant_entry *act) +{ + ASSERT(spin_is_locked(&act->lock)); + + return (act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) == 0; +} + union maptrack_node { struct { /* Radix tree slot pointers use two of the bits. */ @@ -1348,13 +1355,19 @@ 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. While after a v2 -> v1 -> v2 change "ref" would still be + * suitably bounded, the underlying status page may have moved. + */ + if ( evaluate_nospec(rgt->gt_version == 1 + ? status != &shah->flags + : (ref >= nr_grant_entries(rgt) || + status != &status_entry(rgt, ref))) ) { /* - * 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. + * Recalculate status, but only for reserved entries. Others will + * have been cleared anyway by the version change(s). */ if ( ref < GNTTAB_NR_RESERVED_ENTRIES ) status = evaluate_nospec(rgt->gt_version == 1) @@ -3589,7 +3602,7 @@ return 0; } -static int _cache_flush(const gnttab_cache_flush_t *cflush, grant_ref_t *cur_ref) +static int _cache_flush(gnttab_cache_flush_t *cflush, grant_ref_t *cur_ref) { struct domain *d, *owner; struct page_info *page; @@ -3624,6 +3637,8 @@ owner = page_get_owner_and_reference(page); if ( !owner || !owner->grant_table ) { + if ( owner ) + put_page(page); rcu_unlock_domain(d); return -EPERM; } @@ -3640,6 +3655,24 @@ put_page(page); return act ? PTR_ERR(act) : 1; } + + /* + * If the grant mapping is read-only, it must be cleaned as well as + * invalidated. Invalidation without cleaning may modify memory the + * granter is expecting not to change. + * + * It is highly unlikely but legal to have multiple grant mappings of + * differing read-only-ness. If a read-write grant mapping is found + * first, then it's fine to invalidate without clean. + * + * If a read-only grant mapping is found first, a later read-write + * mapping could be missed. Assume that the read-only mapping is the + * only mapping. The cost is a clean of up to 4k, while the saving is + * not requiring the search of grant maps to be exhaustive in order to + * spot a corner-case expected not to exist in practice. + */ + if ( grant_map_is_ro(act) ) + cflush->op |= GNTTAB_CACHE_CLEAN; } v = map_domain_page(mfn); diff -Nru xen-4.20.3+127-gc42374a105/xen/common/memory.c xen-4.20.4+39-gf1e1321c87/xen/common/memory.c --- xen-4.20.3+127-gc42374a105/xen/common/memory.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/memory.c 2026-10-13 13:02:22.000000000 +0000 @@ -163,8 +163,6 @@ unsigned int i, j; xen_pfn_t gpfn; struct domain *d = a->domain, *curr_d = current->domain; - bool need_tlbflush = false; - uint32_t tlbflush_timestamp = 0; if ( !guest_handle_subrange_okay(a->extent_list, a->nr_done, a->nr_extents-1) ) @@ -177,15 +175,6 @@ if ( unlikely(!d->creation_finished) ) { /* - * With MEMF_no_tlbflush set, alloc_heap_pages() will ignore - * TLB-flushes. After VM creation, this is a security issue (it can - * make pages accessible to guest B, when guest A may still have a - * cached mapping to them). So we do this only during domain creation, - * when the domain itself has not yet been unpaused for the first - * time. - */ - a->memflags |= MEMF_no_tlbflush; - /* * With MEMF_no_icache_flush, alloc_heap_pages() will skip * performing icache flushes. We do it only before domain * creation as once the domain is running there is a danger of @@ -284,13 +273,6 @@ goto out; } - if ( unlikely(a->memflags & MEMF_no_tlbflush) ) - { - for ( j = 0; j < (1U << a->extent_order); j++ ) - accumulate_tlbflush(&need_tlbflush, &page[j], - &tlbflush_timestamp); - } - mfn = page_to_mfn(page); } @@ -305,9 +287,6 @@ } out: - if ( need_tlbflush ) - filtered_flush_tlb_mask(tlbflush_timestamp); - if ( a->memflags & MEMF_no_icache_flush ) invalidate_icache(); diff -Nru xen-4.20.3+127-gc42374a105/xen/common/page_alloc.c xen-4.20.4+39-gf1e1321c87/xen/common/page_alloc.c --- xen-4.20.3+127-gc42374a105/xen/common/page_alloc.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/page_alloc.c 2026-10-13 13:02:22.000000000 +0000 @@ -1068,15 +1068,17 @@ /* Preserve PGC_need_scrub so we can check it after lock is dropped. */ pg[i].count_info = PGC_state_inuse | (pg[i].count_info & PGC_need_scrub); - if ( !(memflags & MEMF_no_tlbflush) ) - accumulate_tlbflush(&need_tlbflush, &pg[i], - &tlbflush_timestamp); + accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_timestamp); init_free_page_fields(&pg[i]); } spin_unlock(&heap_lock); + /* Flush ahead of scrubbing: ensure no PV domain has a stale TLB entry. */ + if ( need_tlbflush ) + filtered_flush_tlb_mask(tlbflush_timestamp); + if ( first_dirty != INVALID_DIRTY_IDX || (scrub_debug && !(memflags & MEMF_no_scrub)) ) { @@ -1101,9 +1103,6 @@ } } - if ( need_tlbflush ) - filtered_flush_tlb_mask(tlbflush_timestamp); - /* * Ensure cache and RAM are consistent for platforms where the guest * can control its own visibility of/through the cache. @@ -1357,6 +1356,13 @@ { if ( test_bit(_PGC_need_scrub, &pg[i].count_info) ) { + bool need_tlbflush = false; + uint32_t tlbflush_ts = 0; + + accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_ts); + if ( need_tlbflush ) + filtered_flush_tlb_mask(tlbflush_ts); + scrub_one_page(&pg[i]); /* * We can modify count_info without holding heap @@ -2040,7 +2046,7 @@ uint32_t tlbflush_timestamp = 0; bool need_scrub; - if ( memflags & ~(MEMF_no_refcount | MEMF_no_owner | MEMF_no_tlbflush | + if ( memflags & ~(MEMF_no_refcount | MEMF_no_owner | MEMF_no_icache_flush | MEMF_no_scrub) ) return NULL; @@ -2069,13 +2075,16 @@ free_colored_pages[color]--; page_list_del(pg, color_heap(color)); - if ( !(memflags & MEMF_no_tlbflush) ) - accumulate_tlbflush(&need_tlbflush, pg, &tlbflush_timestamp); + accumulate_tlbflush(&need_tlbflush, pg, &tlbflush_timestamp); init_free_page_fields(pg); spin_unlock(&heap_lock); + /* Flush ahead of scrubbing: ensure no PV domain has a stale TLB entry. */ + if ( need_tlbflush ) + filtered_flush_tlb_mask(tlbflush_timestamp); + if ( !(memflags & MEMF_no_scrub) ) { if ( need_scrub ) @@ -2084,9 +2093,6 @@ check_one_page(pg); } - if ( need_tlbflush ) - filtered_flush_tlb_mask(tlbflush_timestamp); - flush_page_to_ram(mfn_x(page_to_mfn(pg)), !(memflags & MEMF_no_icache_flush)); @@ -2999,9 +3005,7 @@ goto out_err; } - if ( !(memflags & MEMF_no_tlbflush) ) - accumulate_tlbflush(&need_tlbflush, &pg[i], - &tlbflush_timestamp); + accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_timestamp); /* * Preserve flag PGC_static and change page state diff -Nru xen-4.20.3+127-gc42374a105/xen/common/radix-tree.c xen-4.20.4+39-gf1e1321c87/xen/common/radix-tree.c --- xen-4.20.3+127-gc42374a105/xen/common/radix-tree.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/radix-tree.c 2026-10-13 13:02:22.000000000 +0000 @@ -32,12 +32,6 @@ #define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \ RADIX_TREE_MAP_SHIFT)) -/* - * The height_to_maxindex array needs to be one deeper than the maximum - * path as height 0 holds only 1 entry. - */ -static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH + 1] __read_mostly; - static inline void *ptr_to_indirect(void *ptr) { return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR); @@ -82,7 +76,16 @@ */ static inline unsigned long radix_tree_maxindex(unsigned int height) { - return height_to_maxindex[height]; + unsigned int width = height * RADIX_TREE_MAP_SHIFT; + int shift = RADIX_TREE_INDEX_BITS - width; + + if (shift < 0) + return ~0UL; + + if (shift >= BITS_PER_LONG) + return 0UL; + + return ~0UL >> shift; } /* @@ -707,27 +710,3 @@ { *root = (struct radix_tree_root)RADIX_TREE_INIT(); } - -static __init unsigned long __maxindex(unsigned int height) -{ - unsigned int width = height * RADIX_TREE_MAP_SHIFT; - int shift = RADIX_TREE_INDEX_BITS - width; - - if (shift < 0) - return ~0UL; - if (shift >= BITS_PER_LONG) - return 0UL; - return ~0UL >> shift; -} - -static int __init cf_check radix_tree_init_maxindex(void) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) - height_to_maxindex[i] = __maxindex(i); - - return 0; -} -/* pre-SMP just so it runs before 'normal' initcalls */ -presmp_initcall(radix_tree_init_maxindex); diff -Nru xen-4.20.3+127-gc42374a105/xen/common/sched/core.c xen-4.20.4+39-gf1e1321c87/xen/common/sched/core.c --- xen-4.20.3+127-gc42374a105/xen/common/sched/core.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/sched/core.c 2026-10-13 13:02:22.000000000 +0000 @@ -565,7 +565,7 @@ unit->priv = sched_alloc_udata(dom_scheduler(d), unit, d->sched_priv); if ( unit->priv == NULL ) { - sched_free_unit(unit, v); + sched_destroy_vcpu(v); rcu_read_unlock(&sched_res_rculock); return 1; } @@ -722,6 +722,38 @@ for ( unit_idx = 0; unit_idx < n_units; unit_idx++ ) { + /* + * A vcpu slot can be missing if creation failed partway + * through. A dying domain is being torn down regardless, so + * skip the unit -- but a domain that isn't dying still needs + * every vcpu it has schedulable, so fail instead of silently + * dropping some of them. + */ + bool vcpu_failed = false; + + for ( unsigned int i = 0; + i < gran && unit_idx * gran + i < d->max_vcpus; i++ ) + { + if ( !d->vcpu[unit_idx * gran + i] ) + { + vcpu_failed = true; + break; + } + } + + if ( vcpu_failed ) + { + if ( !d->is_dying ) + { + sched_move_domain_cleanup(c->sched, new_units, domdata); + rcu_read_unlock(&sched_res_rculock); + + return -EINVAL; + } + + continue; + } + unit = sched_alloc_unit_mem(); if ( unit ) { @@ -846,8 +878,11 @@ { rcu_read_lock(&sched_res_rculock); - sched_remove_unit(vcpu_scheduler(v), unit); - sched_free_udata(vcpu_scheduler(v), unit->priv); + if ( unit->priv ) + { + sched_remove_unit(vcpu_scheduler(v), unit); + sched_free_udata(vcpu_scheduler(v), unit->priv); + } sched_free_unit(unit, v); rcu_read_unlock(&sched_res_rculock); @@ -3412,7 +3447,7 @@ } else { - sched = &operations; + sched = &sched_idle_ops; cpus = &cpupool_free_cpus; } diff -Nru xen-4.20.3+127-gc42374a105/xen/common/sched/credit.c xen-4.20.4+39-gf1e1321c87/xen/common/sched/credit.c --- xen-4.20.3+127-gc42374a105/xen/common/sched/credit.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/sched/credit.c 2026-10-13 13:02:22.000000000 +0000 @@ -1587,6 +1587,10 @@ struct csched_pcpu *spc = CSCHED_PCPU(cpu); struct csched_private *prv = CSCHED_PRIV(sr->scheduler); + /* Handle race of timer disabling vs. firing when switching scheduler. */ + if ( !spc ) + return; + spc->tick++; /* diff -Nru xen-4.20.3+127-gc42374a105/xen/common/sched/rt.c xen-4.20.4+39-gf1e1321c87/xen/common/sched/rt.c --- xen-4.20.3+127-gc42374a105/xen/common/sched/rt.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/common/sched/rt.c 2026-10-13 13:02:22.000000000 +0000 @@ -750,10 +750,16 @@ return &prv->lock; } -static void move_repl_timer(struct rt_private *prv, unsigned int old_cpu) +static void move_repl_timer(const struct scheduler *ops, unsigned int old_cpu) { - cpumask_t *online = get_sched_res(old_cpu)->cpupool->res_valid; - unsigned int new_cpu = cpumask_cycle(old_cpu, online); + struct rt_private *prv = rt_priv(ops); + /* + * Use the cpupool of the scheduler: the one of the scheduling resource + * is already cleared when this is called from rt_deinit_pdata(). + */ + const struct cpupool *c = ops->cpupool; + unsigned int new_cpu = c ? cpumask_cycle(old_cpu, c->res_valid) + : nr_cpu_ids; /* * Make sure the timer run on one of the cpus that are still available @@ -780,7 +786,7 @@ spin_lock_irqsave(&prv->lock, flags); if ( prv->repl_timer.cpu == cpu ) - move_repl_timer(prv, cpu); + move_repl_timer(ops, cpu); spin_unlock_irqrestore(&prv->lock, flags); } @@ -798,7 +804,7 @@ if ( prv->repl_timer.status != TIMER_STATUS_invalid && prv->repl_timer.status != TIMER_STATUS_killed && !cpumask_test_cpu(old_cpu, sr->cpupool->res_valid) ) - move_repl_timer(prv, old_cpu); + move_repl_timer(ops, old_cpu); spin_unlock_irqrestore(&prv->lock, flags); } diff -Nru xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/x86/hvm.c xen-4.20.4+39-gf1e1321c87/xen/drivers/passthrough/x86/hvm.c --- xen-4.20.3+127-gc42374a105/xen/drivers/passthrough/x86/hvm.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/drivers/passthrough/x86/hvm.c 2026-10-13 13:02:22.000000000 +0000 @@ -231,6 +231,12 @@ restart: write_lock(&d->event_lock); + if ( d->is_dying ) + { + write_unlock(&d->event_lock); + return -ESRCH; + } + hvm_irq_dpci = domain_get_irq_dpci(d); if ( !hvm_irq_dpci && !is_hardware_domain(d) ) { diff -Nru xen-4.20.3+127-gc42374a105/xen/drivers/vpci/vpci.c xen-4.20.4+39-gf1e1321c87/xen/drivers/vpci/vpci.c --- xen-4.20.3+127-gc42374a105/xen/drivers/vpci/vpci.c 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/drivers/vpci/vpci.c 2026-10-13 13:02:22.000000000 +0000 @@ -633,6 +633,8 @@ /* Helper function to check an access size and alignment on vpci space. */ bool vpci_access_allowed(unsigned int reg, unsigned int len) { + const struct domain *currd = current->domain; + /* Check access size. */ if ( len != 1 && len != 2 && len != 4 && len != 8 ) return false; @@ -643,8 +645,8 @@ return false; #endif - /* Check that access is size aligned. */ - if ( (reg & (len - 1)) ) + /* Refuse unaligned accesses for non-hardware domains. */ + if ( !is_hardware_domain(currd) && !IS_ALIGNED(reg, len) ) return false; return true; diff -Nru xen-4.20.3+127-gc42374a105/xen/include/public/arch-arm.h xen-4.20.4+39-gf1e1321c87/xen/include/public/arch-arm.h --- xen-4.20.3+127-gc42374a105/xen/include/public/arch-arm.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/include/public/arch-arm.h 2026-10-13 13:02:22.000000000 +0000 @@ -408,7 +408,8 @@ * zImage kernels on aarch32. */ #define PSR_GUEST32_INIT (PSR_Z|PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC) -#define PSR_GUEST64_INIT (PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_EL1h) +#define PSR_GUEST64_INIT \ + (PSR_DBG_MASK|PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_EL1h) #define SCTLR_GUEST_INIT xen_mk_ullong(0x00c50078) diff -Nru xen-4.20.3+127-gc42374a105/xen/include/xen/mm.h xen-4.20.4+39-gf1e1321c87/xen/include/xen/mm.h --- xen-4.20.3+127-gc42374a105/xen/include/xen/mm.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/include/xen/mm.h 2026-10-13 13:02:22.000000000 +0000 @@ -202,8 +202,6 @@ #define MEMF_exact_node (1U<<_MEMF_exact_node) #define _MEMF_no_owner 5 #define MEMF_no_owner (1U<<_MEMF_no_owner) -#define _MEMF_no_tlbflush 6 -#define MEMF_no_tlbflush (1U<<_MEMF_no_tlbflush) #define _MEMF_no_icache_flush 7 #define MEMF_no_icache_flush (1U<<_MEMF_no_icache_flush) #define _MEMF_no_scrub 8 diff -Nru xen-4.20.3+127-gc42374a105/xen/include/xen/sched.h xen-4.20.4+39-gf1e1321c87/xen/include/xen/sched.h --- xen-4.20.3+127-gc42374a105/xen/include/xen/sched.h 2026-07-28 12:08:27.000000000 +0000 +++ xen-4.20.4+39-gf1e1321c87/xen/include/xen/sched.h 2026-10-13 13:02:22.000000000 +0000 @@ -1215,6 +1215,11 @@ return evaluate_nospec(d->options & XEN_DOMCTL_CDF_iommu); } +static inline bool is_vpmu_domain(const struct domain *d) +{ + return d->options & XEN_DOMCTL_CDF_vpmu; +} + #ifdef CONFIG_MEM_PAGING # define mem_paging_enabled(d) vm_event_check_ring((d)->vm_event_paging) #else