VMRUN ignores bits 11:0 of MSRPM_BASE_PA (APM volume 2, 24593 Rev. 3.44,
section 15.11 "MSR Intercepts"). On L1's VMRUN of L2,
nsvm_vmrun_permissionmap() copies the MSR permission map which L1 set up
for L2 from MSRPM_BASE_PA exactly as L1 wrote it. With any of those bits
set, the copy starts at the wrong offset, so both the map L0 runs L2 with
and the intercept check on #VMEXIT use the wrong bits: L1 can miss
intercepts it set or see ones it didn't, and the copy may run into the
following page, giving a spurious VMEXIT_INVALID if that isn't RAM.
Mask the address before copying.
Fixes: 9a779e4fc1 ("Implement SVM specific part for Nested Virtualization")
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Stephen Cheng <stephen.cheng@citrix.com>
Reviewed-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
This function just returns vcpu_nestedhvm(v).nv_guestmode and would
be better inlined to improve codegen.
Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
Acked-by: Jan Beulich <jbeulich@suse.com>
The comment in p2m_set_pte_flags() quotes the spec at length to describe
the two A/D bits schemes, and its TODO mixes two things: why A/D are preset
today (OpenSBI delegates the resulting page faults to a lower privilege
mode, so Xen would take them with no handler) and what remains to be done.
Summarize the two schemes as a short list. The reason for presetting A/D is
not future work, so move it out of the TODO, next to the schemes. The TODO
now keeps only the later work, handling these page faults instead of
presetting A/D, which only concerns Svade as A/D page faults cannot happen
otherwise.
Also note that presetting the A/D bits is harmless when the device
tree advertises both Svade and Svadu and the platform uses hardware
A/D updating.
No functional change.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Baptiste Le Duc <baptiste.le-duc@vates.tech>
Reviewed-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
do_trap() consulted the exception table only for CAUSE_ILLEGAL_INSTRUCTION,
which covers csr_read_safe() but not a probing access faulting with a page
fault cause: it would reach do_unexpected_trap() instead of its fixup.
There is no such access yet, the A/D update scheme probe will be the first.
Move the lookup ahead of the cause switch, and only do it for exceptions
taken in Xen context. Both other cases must skip it:
- Traps taken from the guest: sepc is then a guest address, which the
guest can point at an address listed in the exception table, making Xen
act on an entry fully under guest control. Entries are matched by exact
address, so this needs no more than a numerical collision.
- Interrupts: an interrupt taken at an address listed in the table would
otherwise be "fixed up" as if the access itself had faulted, silently
skipping it.
Returning early skips check_for_pcpu_work(), which is correct: that only
runs for traps taken from the guest.
Cache the "trap came from the guest" test in a local as it is now used
three times.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
[Baptiste: drop the parts depending on the vAPLIC/vIMSIC series, adapt
the commit message]
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Baptiste Le Duc <baptiste.le-duc@vates.tech>
Reviewed-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Xen does not handle page faults caused by clear A/D bits, so it presets
them when creating PTEs. pt_update_entry() does so, but three places build
leaf PTEs directly without going through it: setup_initial_mapping() (the
boot page tables), check_pgtbl_mode_support() (the temporary root entry
used to probe SATP mode support) and arch_pmap_map() (the fixmap).
On implementations that fault on clear A/D bits (Svade), all three fault
on first access. For check_pgtbl_mode_support(), the fault is raised by the
instruction fetch right after the SATP write, before any trap handler is
set.
Add PTE_ACCESSED and PTE_DIRTY to PAGE_HYPERVISOR_RO, and build
PAGE_HYPERVISOR_RW and PAGE_HYPERVISOR_RX on top of it. PTE_DIRTY is set in
all cases for consistency with pt_update_entry() which sets it at runtime.
This fixes arch_pmap_map() for free, since it already builds its PTE from
PAGE_HYPERVISOR_RW. Switch setup_initial_mapping() to use these macros for
its default, text and rodata permissions, and check_pgtbl_mode_support() to
use PAGE_HYPERVISOR_RX for its temporary root entry. The latter drops
PTE_WRITABLE, going from RWX to RX, but this is harmless, as that entry
only has to make the current instruction stream fetchable between the two
CSR_SATP writes, and nothing writes through it.
Drop the now-redundant PTE_LEAF_DEFAULT, since converting the last
open-coded site above leaves it with no user outside page.h itself.
pte_is_table() and pte_is_mapping() both assert that a PTE doesn't use one
of the two reserved encodings, (V=1, W=1, R=0) and (V=1, X=1, W=1, R=0), by
masking it with PAGE_HYPERVISOR_RW. Now that PAGE_HYPERVISOR_RW also
carries A and D, a reserved PTE with A or D set would no longer be caught.
Mask with the V, R and W bits explicitly instead, and factor the check out
into pte_has_reserved_rwx().
Fixes: e66003e7be ("xen/riscv: introduce setup_initial_pages")
Fixes: f89e1a1702 ("xen/riscv: introduce asm/pmap.h header")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Baptiste Le Duc <baptiste.le-duc@vates.tech>
Reviewed-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Tested-by: Zhang Zheng <zhangzheng@iscas.ac.cn>
Acked-by: Jan Beulich <jbeulich@suse.com>
Use pte_is_valid() instead of open-coding the PTE_VALID check.
No functional change.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Baptiste Le Duc <baptiste.le-duc@vates.tech>
Reviewed-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
On SVM, L1 flushes what is cached from its nested page tables by setting
TLB_CONTROL or using a new ASID on VMRUN. Either sets nv_flushp2m, which
p2m_get_nestedp2m_locked() handles by only dropping nv_p2m. Since np2ms
are shared between vCPUs, the lookup then finds the np2m for the same
N_CR3 and reuses it as is, so L2 keeps the mappings from before L1 changed
its NPT.
The obvious fix, flushing nv_p2m (the np2m this vCPU used last) before
dropping it, is not enough. It covers a vCPU re-entering the same N_CR3,
but not one entering an N_CR3 whose np2m another vCPU filled: on its
first VMRUN (nv_p2m is NULL), with an ASID new to it, or when switching
N_CR3.
Instead, flush the np2m for the incoming N_CR3 before reusing it, as
nested VMX does via np2m_flush_base() on INVEPT.
Fixes: 6df4b481b0 ("x86/np2m: implement sharing of np2m between vCPUs")
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Stephen Cheng <stephen.cheng@citrix.com>
Reviewed-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
The S bit of an INVALIDATE_IOTLB_PAGES command selects between the two
sizes the command can name: cleared, the invalidation covers 4 Kbytes;
set, it covers the range encoded by the first zero bit of the address,
counting from bit 12. invalidate_iotlb_pages() builds that encoding
whenever it is given a non-zero order or the all-pages address, and then
passes the field's mask where set_field_in_reg_u32() expects the shift.
The correct mask is 1 and the shift is 0. When mask (1) is passed for
both, the value is shifted out of the field it was to occupy and the
bit is left clear. i.e. (x << 1) & 1 is always 0.
An endpoint holding translations of its own is therefore told to drop one
page where it should have dropped a range. The rest of the range is
kept in its cache after the page tables backing it have changed.
Pass the shift, as the sibling INVALIDATE_IOMMU_PAGES builder does.
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Reviewed-by: Xenia Ragiadakou <xenia.ragiadakou@amd.com>
[ Reword commit message. ]
Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
The hide pattern .xen-syms.[013] leaves pass 2 visible. On x86
LAST_LINKING_PASS is 2, so that is the final link. On Arm
LAST_LINKING_PASS is 3 and the final image is .xen-syms.3. Pass 2 is
usually only a symlink, so Eclair saw no program link and reported every
translation unit as unreachable.
During analysis preparation, read LAST_LINKING_PASS from the architecture
makefile and the pass numbers from the foreach list in
xen/scripts/Makefile.link. Hide every pass except that one. An earlier
pass that is a real link stays hidden. The generator runs from
generate_ecl.sh, together with the other ECLAIR configuration scripts.
Fixes: a401b5c9dc ("Eclair: re-enable scanning of the (almost) final linking step")
Signed-off-by: Dmytro Prokopchuk <dmytro_prokopchuk1@epam.com>
Acked-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
I was asked to explain the comment beside STI in the svm_asm_do_resume() and,
in trying to do so, things unravelled.
The original fix inherited from KVM prevented the guests INTR_SHADOW being
changed from 0 to 1. This avoid undue delay to interrupts, but it caused the
value to get changed from 1 to 0 if the guest was in an INTR_SHADOW.
Whether this matters for IDT guests is unknown; it depends on what else VMRUN
can do beside event injection and still write back the wrong value. This does
matter for FRED guests, as INTR_SHADOW is exposed architecturally in the FRED
frame via the STB field.
Fixes: c989ff614f ("x86/svm: Separate STI and VMRUN instructions in svm_asm_do_resume()")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
In virtual-8086 mode with IOPL < 3, INT n raises #GP(0). INT1, INT3
and INTO are not affected. They are delivered normally.
svm_emul_swint_injection() applies the check to all of them, so an ICEBP
raises #GP instead of #DB. It also reports the IDT entry in the #GP
error code instead of 0.
Move the check earier prior to setting up ec, and limit it to INT n only.
Fixes: 897d59a426 ("x86/svm: Introduce svm_emul_swint_injection()")
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This is overly agressive. The APM says:
The hypervisor must clear the entire VMCB field to 0 for a guest, under the
following circumstances:
* The hypervisor executes the guest on a different CPU core than one used
the last time that guest was executed.
Clear the cleanbits only when the VMCB is used on a different pCPU rather than
on every context switch to the vCPU.
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
... as building and interpreting Ocaml objects in C is rather fragile.
For C producing objects for Ocaml to consume, one trick to check validity is
Gc.compact() which forces a major sweep, walking all objects. If this doesn't
segfault, then we at least got the pointer <-> integer aspects right.
For now, start with a very simple version call. (Re)introduce
tools/ocaml/tests and add test-ocaml-bindings which is installed into
$(DESTDIR)$(LIBEXEC)/tests to be picked up automatically with the other dom0
tests.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Andrii Sultanov <andriy.sultanov@vates.tech>
... rather than editing them after the fact.
This capability exists from Ocaml 4.05 which is also our minimum supported
version.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Andrii Sultanov <andriy.sultanov@vates.tech>
psci_init_0_2() stores the value returned by PSCI_VERSION in the global
psci_ver before checking that Xen supports it. When the firmware reports
a version other than 0.2 or 1.x, the function prints "Unrecognized PSCI
version" and returns -EOPNOTSUPP, but psci_ver keeps the rejected value
and psci_cpu_on_nr stays 0.
psci_init() then tries the PSCI 0.1 fallback, which overwrites psci_ver
on success. When the fallback fails as well (the /psci node is not
compatible with "arm,psci", it has no "cpu_on" property, or Xen boots
with ACPI), psci_init() returns an error that smp_init_cpus() ignores,
and psci_ver still holds the rejected version. All the users of
psci_ver then consider PSCI as available:
- on arm64, smp_psci_init() installs call_psci_cpu_on() as the method
to bring up the secondary CPUs;
- on arm32, platform_cpu_up() calls call_psci_cpu_on() instead of the
platform specific cpu_up() callback;
- call_psci_cpu_off(), call_psci_system_off() and
call_psci_system_reset() issue their PSCI calls.
As a result, Xen brings up each secondary CPU with an SMC using function
ID 0. An SMCCC compliant firmware refuses it, and Xen reports "Failed to
bring up CPU<n> (error -1)" for each secondary CPU.
Fix it by setting psci_ver back to 0 before returning the error.
Fixes: 4d3d72c014 ("xen/arm: Initial support for PSCI-0.2")
Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
This part of the comment is actually about VCPUOP_register_runstate_phys_area
and not VCPUOP_register_runstate_memory_area.
Fixes: d5df44275e ("domain: introduce GADDR based runstate area registration alternative")
Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
Acked-by: Jan Beulich <jbeulich@suse.com>
On Arm, the hardware domain does not use the P2M pool. Its P2M pages are
allocated directly from the heap, without any limit. However, when the
hardware domain is created using dom0less, we still allocate a P2M pool
for it, either of the default size or the one given in
xen,domain-p2m-mem-mb. This memory is never used and is simply wasted.
The same applies when the pool size is set for the hardware domain using
XEN_DOMCTL_set_paging_mempool_size.
Don't create the pool for a hardware domain. Make the get/set paging
mempool domctls return -EOPNOTSUPP, skip the pool teardown and reject
xen,domain-p2m-mem-mb for a hardware domain in dom0less.
The dom0less check is Arm specific, because on RISC-V the hardware domain
does use the P2M pool.
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
The DT dma-noncoherent property describes the bus coherency of the
device represented by the node. On an ITS subnode, that is memory
accessed by that ITS. Add GICV3_QUIRK_MEM_NC_NS to the corresponding
host_its and use it when programming GITS_CBASER and GITS_BASER<n>.
On the top-level GIC node, the property describes the Redistributor side
of the LPI path. Collect it in gicv3_lpi_init_host_lpis() and apply it
only to the host LPI policy used when allocating the property and
pending tables and when programming GICR_PROPBASER and GICR_PENDBASER.
Mark the function init-only because firmware attributes are collected
only during boot.
Do not inherit the property between parent and child nodes: ITS-node
non-coherency does not change the global host LPI policy, and GIC-node
non-coherency does not change per-ITS quirk_flags.
ACPI is unchanged; this patch only consumes the DT dma-noncoherent
property.
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
ITS quirks are matched only by IIDR and mask fields stored in each table
entry. That is too coarse when the same GIC IP block appears on several
platforms but a workaround is valid only for some of them.
Replace the fixed IIDR fields with a generic match(hw_its, data)
callback and an opaque data pointer. Add an IIDR matcher as a reusable
building block and use it from the R-Car Gen4 matcher after checking the
Renesas machine compatibles.
This intentionally narrows the R-Car Gen4 quirk. Previously every ITS
with IIDR 0x0201743b matched. Now it matches only a DT-discovered ITS on
an r8a779f0 or r8a779g0 machine. ACPI-discovered ITSes and the same IIDR
on other platforms no longer match.
Keep first-match semantics explicit. Use BUG_ON() if a non-sentinel
entry has no matcher or the IIDR matcher receives no data. A broken
entry must stop Xen in both debug and release builds, as skipping a
required workaround could cause a failure later. Place the matcher data
and table in init-only read-only sections.
The matched entry still supplies separate ITS and LPI flags; this patch
only changes how the entry is selected.
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
ITS quirks can impose restrictions on memory accessed by the ITS itself
and on shared host LPI/Redistributor state. These scopes are not
identical, so a single global ITS quirk state makes the host LPI policy
depend implicitly on the quirks seen while initializing host ITSes.
Add per-ITS quirk_flags to struct host_its and keep a separate
host_lpi_flags state in the LPI code. The quirk table now records the
ITS-private and host LPI scopes explicitly through its_flags and
lpi_flags. The R-Car Gen4 quirk applies the same memory restrictions to
both scopes, preserving the existing R-Car memory policy without relying
on an implicit aggregation step.
This also removes the assumption that all host ITSes must expose the
same quirk state. ITS-derived host LPI restrictions are accumulated only
from quirk entries that explicitly set lpi_flags.
Use per-ITS quirk_flags for GITS_CBASER, GITS_BASER<n>, and ITT
allocations. Use host_lpi_flags when allocating the property and pending
tables and when programming GICR_PROPBASER and GICR_PENDBASER.
Memory-related quirk bits are named GICV3_QUIRK_MEM_* and are translated
by shared gicv3_mem_get_*() helpers.
Collect both scopes during the ITS preparation pass, before host LPI
state is allocated. Keep init-only annotations and includes in the
implementation files rather than the public header.
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
The boot CPU pending table must use the memory attributes selected by
ITS quirks. gicv3_lpi_init_host_lpis() is therefore called after
gicv3_its_init(). However, gicv3_its_init() also programs and enables
each ITS before host LPI state is allocated. No ITS commands are
submitted at that point, but this ordering relies on that implementation
detail.
Split per-ITS initialization into preparation and activation phases.
First map and disable every ITS and collect its quirks. Then initialize
host LPI state. Only after that, allocate and program the ITS tables and
command queue, and enable each ITS.
The subsequent gicv3_cpu_init() sequence remains unchanged: it programs
the Redistributor LPI tables, enables LPIs, and then submits the first
MAPC and SYNC commands.
Drop the now unreachable stub for gicv3_lpi_init_host_lpis().
Suggested-by: Julien Grall <julien@xen.org>
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
When the removal spans several ranges, the last one is trimmed by
setting its start to e + 1, and destroyed if that leaves it empty. For
e == ~0UL, e + 1 wraps to 0, so the range is kept as [0, end] and the
removal adds everything below it.
This is hit by pv_shim_shutdown(), whose iomem_deny_access(d, 0, ~0UL)
on resume turns the guest's grant frame permissions into [0, highest
grant frame]. arch_iommu_hwdom_init() can hit it too, for a PVH
hardware domain with an E820 entry above its 48-bit iomem_caps.
Destroy the range when it ends within [s, e] instead.
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Acked-by: Roger Pau Monné <roger@xenproject.org>
Per the IVMD Flags definition, bit 1 is IR and bit 2 is IW, matching
ACPI_IVMD_READ and ACPI_IVMD_WRITE. parse_ivmd_block() takes iw from
the former and ir from the latter, so a unity range firmware declares
read-only is mapped write-only, and vice versa.
Ranges with both permissions, including Xen's own, are unaffected.
Fixes: e941abd7ca ("ACPI: eliminate duplicate IVRS definitions")
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
Acked-by: Roger Pau Monné <roger@xenproject.org>
hvmemul_write_cr() updates guest_cr[2] but, unlike every other writer of
it, doesn't call hvm_update_guest_cr(). On SVM, CR2 is loaded from
the VMCB, so the emulated write never reaches the guest, and the next
VMExit overwrites guest_cr[2] with the stale VMCB value.
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Acked-by: Roger Pau Monné <roger@xenproject.org>
stub_xc_domain_create() fails unconditionally with "Unhandled: ARM" for
the ARM variant of arch_domainconfig, so no OCaml toolstack (e.g.
xenopsd) can create an ARM domain.
To fix this, convert the two fields of xen_arm_arch_domainconfig,
gic_version and nr_spis, into the corresponding fields of struct
xen_arch_domainconfig and reject values that do not fit, as is already
done for other parameters. The remaining fields (sve_vl, tee_type,
arm_sci_type and v8r_el1_msa) aren't exposed to OCaml yet, so they stay
zero.
Also add a BUILD_BUG_ON() on the size of the createdomain struct, just
like the x86 case, to catch future ABI changes.
Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
Signed-off-by: Julian Vetter <julian.vetter@vates.tech>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Between writing MSR_S_CET.SHSTK_EN and establishing SSP using RSTORSSP or
SETSSBSY, there must not be any CALL or RET instructions.
Building Xen with -fno-early-inlining causes wrmsr() to become out-of-line,
and thus suffers #DF during boot.
Make the MSR and shstk helpers always_inline. They ought to have been this
way all along.
Fixes: b60ab42db2 ("x86/shstk: Activate Supervisor Shadow Stacks")
Fixes: 3037d8b7eb ("x86/boot: Use RSTORSSP to establish SSP")
Reported-by: Stefano Stabellini <sstabellini@kernel.org>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
Reviewed-by: Roger Pau Monné <roger@xenproject.org>
If the memory region to be mapped does not start at the page boundary
and its end spans over the page boundary, map_range_to_domain() passes
a number of pages that is short by one to map_regions_p2mt(). Domain's
attempt to access memory within that page will fail. Fix it by calculating
the number of pages to be mapped taking into account the start offset.
Fixes: 88c10b0d6e ("arch/arm: let map_mmio_regions() use start and count")
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Acked-by: Julien Grall <julien@xen.org>
Per the binding (docs/misc/arm/device-tree/guest.txt), region 0 for
mapping grant table is large enough to map the whole grant table. Xen
never checks that this holds:
- enhanced dom0less domUs are given GUEST_GNTTAB_SIZE (4096 frames),
while their limit comes from the max_grant_frames DT property or, if
absent, from the gnttab_max_frames command line option or default,
neither of which is bounded by the region size,
- a dom0less hardware domain is given gnttab_dom0_frames() frames,
while the max_grant_frames DT property can raise its limit above
that.
A guest growing its grant table past the end of the region ends up
mapping grant frames over whatever follows it in its address space,
e.g. the magic pages at GUEST_MAGIC_BASE for a domU.
Validate that the configured max frames can actually fit in the region
Xen exposes in make_hypervisor_node().
Fix find_gnttab_region() logic of setting the gnttab_size for hardware
domain to allow the max frames up until the size of the text section.
Otherwise, the DT setting would only allow to shrink it from the
default.
Fixes: 79eb2871f2 ("xen/arm: configure dom0less domain for enabling xenstore after boot")
Fixes: df68a4cb7e ("xen/arm: Add capabilities to dom0less")
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
The device tree Xen builds for dom0/hwdom or for a dom0less domain is
only ever consumed by the guest, so a mistake in it surfaces as an
obscure failure inside the domain, far away from the code which
produced the tree.
Add device_tree_dump(). The output follows dtc's format so that a dump
can be diffed against the source DTS or fed back to dtc; the value
formatting heuristics are ported from dtc's utilfdt_print_data() for
that reason. The walk itself goes through libfdt rather than decoding
the tag stream by hand as dtc's fdtdump does.
Dumping a whole tree is only useful while debugging and costs both code
size and a lot of console output, so it is put under its own option,
CONFIG_DEVICE_TREE_DUMP. It is separate from CONFIG_DEVICE_TREE_DEBUG
because the generated tree is often all that is needed, without the rest
of the device tree debug messages.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
arch_sanitise_domain_config() validates the configuration requested by
the toolstack, and should not fill anything in. The config struct passed
to createdomain is supposed to be pure input. ARM used to abuse this
(GIC_NATIVE resolution, now removed) to smuggle output back to the
toolstack. Making the parameter const stops that type of abuse from
happening on any architecture.
The x86 implementation turned out to have its own instance of the same
issue. It set XEN_DOMCTL_CDF_oos_off into config->flags for non-HVM
guests. Since The sanitisation runs before the function domain_create()
copies config->flags into d->options, this relied on mutating the
toolstack's config to take effect. Move the default onto d->options
directly in arch_domain_create() (which runs after d->options is
populated), where all the remaining domain options are resolved. This
has the same effect and no mutation of the input config is required.
ARM, PPC and RISC-V need no equivalent change, Their implementations
were already read-only.
Signed-off-by: Julian Vetter <julian.vetter@vates.tech>
Reviewed-by: Jan Beulich <jbeulich@suse.com> # x86
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Baptiste Le Duc <baptiste.le-duc@vates.tech> # riscv
The xen_arch_domainconfig.clock_frequency value is populated in
domain_vtimer_init() during XEN_DOMCTL_createdomain from the global
timer_dt_clock_frequency, which comes from the host's DT timer node and
has nothing to do with the domain being created. Like now removed
GIC_NATIVE resolution, this is a host-wide system property being
smuggled out through a domain-creation IN struct.
Expose it instead as a new arm_clock_frequency_hz field in
XEN_SYSCTL_physinfo, populated via arch_do_physinfo(), and mirroring how
the GIC capability bits were already moved there.
Rather than making the field dependant on DT boot, make Xen always
report the timer frequency, either via the DT "clock-frequency" node, or
directly via CNTFRQ_EL0. preinit_xen_time() already computes cpu_khz for
every boot path. The renamed timer_clock_frequency_hz now captures
whichever of the two produced that value, in full Hz precision, instead
of only recording the DT case. So, ACPI guests get a real value too,
allowing to drop the special case.
The DT "clock-frequency" property exists because firmware might leave
CNTFRQ_EL0 wrong, and since CNTFRQ_EL0 cannot be trapped the only fix is
to replicate the correct value into the guest DT. To keep that signal, a
new XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ capability bit records whether
arm_clock_frequency_hz came from the DT property. Then libxl only emits
a "clock-frequency" property into the guest timer node when that bit is
set. A guest whose CNTFRQ_EL0 is already correct keeps an unmodified
timer node, exactly as before.
Although the CNTFRQ_EL0 register is 64 bits wide, and some current timer
implementations run at 1GHz, a 32bit value is sufficient to store the
timer value, because it only mirrors the DT 'clock-frequency' property,
which the bindings define as a single 32-bit cell.
In struct xen_sysctl_physinfo the new field just reuses the former pad
word, so sysctl consumers are unaffected. struct xen_arch_domainconfig
however loses clock_frequency from its middle, which shrinks the struct
and shifts every field after it, so bump XEN_DOMCTL_INTERFACE_VERSION.
The xen_arch_domainconfig parameter passed to domain_vtimer_init() is no
longer needed, so drop that parameter entirely. libxl now fetches the
frequency via libxl_get_physinfo() in libxl__arch_domain_save_config()
instead of reading it back out of the createdomain reply. The OCaml
xen_arch_domainconfig mirror drops the field too.
Signed-off-by: Julian Vetter <julian.vetter@vates.tech>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Anthony PERARD <anthony.perard@vates.tech>
Now that the toolstack always resolves a concrete GIC_V2 or GIC_V3
before calling createdomain, nothing on the Xen side needs to resolve
GIC_NATIVE either:
* A new gic_domctl_hw_version() helper returns the
XEN_DOMCTL_CONFIG_GIC_* value matching the host's gic_hw_version().
* arch_sanitise_domain_config() uses it to validate the requested
version against the hardware, rather than resolving GIC_NATIVE and
writing the result back into config->arch.gic_version. A guest must
use the host's GIC version, except that a GICv3 host with the GICv2
compatibility mode enabled may also run GICv2 guests. This is the
same information that XEN_SYSCTL_physinfo reports to the toolstack.
* create_dom0() and arch_parse_dom0less_node(), which both always want
a vGIC that exactly matches the hardware, use the same helper instead
of GIC_NATIVE.
With nothing left resolving or relying on it, drop
XEN_DOMCTL_CONFIG_GIC_NATIVE from the public ABI. Every caller must now
request a concrete GIC_V2 or GIC_V3.
This is an incompatible change for any toolstack still passing 0
(formerly GIC_NATIVE) expecting Xen to auto-select a version. Add a
CHANGELOG.md entry, noting that available GIC versions can be queried
via XEN_SYSCTL_physinfo.
Signed-off-by: Julian Vetter <julian.vetter@vates.tech>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
XEN_DOMCTL_CONFIG_GIC_NATIVE lets the toolstack ask Xen to silently
resolve the domain's GIC version to whatever the host hardware has. Xen
then writes the resolved value back into the same in/out
xen_arch_domainconfig the toolstack used as input, which is the kind of
API abuse we're trying to get rid of. The struct passed to createdomain
should only be an input parameter.
Move the "pick the best available GIC version" decision to the
toolstack, using the XEN_SYSCTL_PHYSCAP_ARM_GIC_V2/V3 capability bits
already exposed via XEN_SYSCTL_physinfo:
* libxl__arch_domain_build_info_setdefault() resolves the GIC version
against those bits before the config is built. An unspecified version
becomes v3 if available, else v2, else fails. An explicitly requested
v2/v3 is validated against the same bits, so a version the host
cannot provide is directly rejected in the toolstack.
* The Python xc.domain_create() binding does the same via a call to
xc_physinfo().
* libxl__arch_domain_prepare_config() therefore only ever sees a
concrete v2/v3 request and just validates it. The GIC_NATIVE case is
dropped since setdefault() always resolves it first.
LIBXL_GIC_VERSION_DEFAULT keeps its name and value: xl.cfg still accepts
"default" as the C<gic_version> keyword, and setdefault() resolves it to
a concrete v2/v3 before anything else can observe it.
This guarantees no toolstack path can still produce
XEN_DOMCTL_CONFIG_GIC_NATIVE, in preparation for removing it from the
Xen side and from the ABI entirely.
Signed-off-by: Julian Vetter <julian.vetter@vates.tech>
Acked-by: Michal Orzel <michal.orzel@amd.com>
Acked-by: Anthony PERARD <anthony.perard@vates.tech>
In preparation to simplify the domain creation logic surrounding GIC
version.
On a GICv3 host, also report support for GICv2-compatible guests when
the hardware's vGICv2 compatibility mode is enabled, rather than just
the native GIC version.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Julian Vetter <julian.vetter@vates.tech>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Include PCI IDs of UART ports on Intel RPL - PTL. Based on Linux driver
and hwdata, they all share the same parameters.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
There's a potential 32bit left-shift (when size is 4) to a 32bit value,
which would trigger UB and tickle UBSAN the wrong way. Shifting right an
all-ones mask fixes the issue.
Fixes: 4609fc8eb0 ("x86/hvm: Improve error information in handle_pio()")
Signed-off-by: Alejandro Vallejo <alejandro.garciavallejo@amd.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
As of the referenced commit v won't be returned from the function anymore.
Yet that was the sole reason for it to not be pointer-to-const. curr,
which was introduced by that change, had no reason to be pointer-to-non-
const from the start.
Amends: 622c9a5ba9 ("x86/mm: accurately track which vCPU page-tables are loaded")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Roger Pau Monné <roger@xenproject.org>
memcpy_to_guest_ring() bounds the copy against the ring size with
if ( len + offset > XEN_ARGO_MAX_RING_SIZE )
where len and offset are unsigned int. offset is masked below
PAGE_SIZE just above, but a len close to UINT_MAX makes len + offset
wrap below XEN_ARGO_MAX_RING_SIZE and pass the check. The head_len
computation in the loop wraps the same way, so the copy length is no
longer bounded.
All current callers bound len via iov_count(), so this is not
reachable in practice.
No functional change for in-range inputs.
Signed-off-by: Weiqi Wang <weiqi.wang-2@postgrad.manchester.ac.uk>
Acked-by: Jan Beulich <jbeulich@suse.com>
MISRA C Rule 10.1 states: "Operands shall not be of an inappropriate
essential type".
bar_write() and guest_mem_bar_write() added the boolean 'hi' to a
pointer difference when printing the ignored BAR index. These handlers
are registered only for the memory BAR registers, so print
(reg - PCI_BASE_ADDRESS_0) / 4 instead. The expression has type
unsigned int, so use %u.
No functional changes.
Suggested-by: Roger Pau Monné <roger.pau@citrix.com>
Signed-off-by: Dmytro Prokopchuk <dmytro_prokopchuk1@epam.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger@xenproject.org>
Due to a typo the state record for a watch specifying a depth is
written only partially. Instead of using the correct length of the
xs_state_watch_ext structure only the length of the xs_state_watch
structure was used when writing the data.
Fix that by using the correct length.
This is XSA-514 / CVE-2026-79607
Fixes: db98de120c ("tools/xenstored: add depth information to watches")
Reported-by: Andrii Sultanov <andriy.sultanov@vates.tech>
Signed-off-by: Juergen Gross <jgross@suse.com>
Grants can be offered read-only by the owning domain. While a domain mapping
a RO grant may have a need to invalidate the cache, it must not modify the
other-guests data while doing so. Force-upgrade to a clean operation in this
case.
This is CVE-2026-102702, part of XSA-519.
Fixes: 18e8d22fe7 ("introduce GNTTABOP_cache_flush")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
When the start address is not cacheline aligned, the bytes covered by
the first, partial cacheline are subtracted from 'size'. Nothing checks
that the region actually extends beyond that cacheline, so if it does
not, the unsigned subtraction underflows and the loop that follows walks
practically the entire address space.
For example, with a 64-byte cacheline, p = 0x40000001 and size = 1:
p & cacheline_mask -> 1, so the partial head is taken
size -= 64 - 1 -> 1 - 63 underflows to 0xffffffffffffffc2
Instead of a single "dc civac" at 0x40000000, the loop then runs
288230376151711743 times, issuing "dc ivac" from 0x40000040 upwards.
Invalidating without cleaning discards dirty cachelines, so this
corrupts whatever is mapped along the way until Xen takes a data abort.
Moreover, _cache_flush() in common/grant_table.c, reachable from a guest
via GNTTABOP_cache_flush, bounds 'offset' and 'length' against the page
size but requires no alignment, so GNTTAB_CACHE_INVAL with offset = 1
and length = 1 is enough to trigger this. Note that the page may belong
to a different domain (the d != owner path), so the data being discarded
is not necessarily the caller's own.
The subtraction dates back to the fix for XSA-437, so this is a regression
in that change.
Fix this by detecting the underflow instead of letting it happen: if the
region ends inside the first cacheline, there is nothing left to flush
and the function bails out right after cleaning it. Partially covered
cachelines are still cleaned as well as invalidated, so that data outside
of the region is not discarded.
Additionally, drop 'idx' and advance 'p' directly instead. It simplifies
the logic while using fewer variables and less arithmetic.
Note that the partial head is now cleaned using the unaligned start of the
region instead of the start of its cacheline. This is permitted by the
architecture; the Arm ARM (DDI 0487) states:
"When a DC instruction requires an address argument this takes the form
of a 64-bit register that holds the VA argument. No alignment
restrictions apply for this address."
The same applies on Arm32.
Also, switch the asm() in the loop to asm_inline, like the neighbouring
ones: the wrapper expands to a single instruction with a trailing
semicolon, which GCC counts as two statements, overestimating the size
of the function when deciding whether to inline it.
This is CVE-2026-102699, part of XSA-519.
Fixes: 9a216e92de ("xen/arm: page: Handle cache flush of an element at the top of the address space")
Signed-off-by: Leonid Komarianskyi <leonid_komarianskyi@epam.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Julien Grall <julien@xen.org>
The consistency checks in effect when Blocked-by-STI/MovSS are active includes
DEBUGCTL.BTF too. Take this into account when editing PENDING_DBG.BS.
This ends up narrowing the cases where PENDING_DBG is modified. Rework the
comment to be more precise.
This is XSA-518 / CVE-2026-79611.
Fixes: 1d3eb82598 ("x86/vtx: Work around SingleStep + STI/MovSS VMEntry failures")
Reported-by: Teddy Astie <teddy.astie@vates.tech>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
A v1 -> v2 change isn't the only scenario where "status" may go stale in
map_grant_ref(). Across a v2 -> v1 -> v2 change the status pages would
have been freed and re-populated, possibly changing the pages used for the
array. Check the pointer against the expected version-dependent value.
This is XSA-517 / CVE-2026-79610.
Fixes: 96dfeb4177 ("gnttab: cope with version changes racing other operations")
Assisted-by: Claude
Reported-by: Teddy Astie <teddy.astie@vates.tech>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
For XPTI enabled VMs, restore_all_guest() copies most of the active L4
pagetable into the per-CPU root_pgt. The L4 is read via the
directmap.
Unfortunately, there was no accounting for the fact that PV guests
have short directmaps. For an L4 living beyond the 5T boundary (3.5T
for CONFIG_BIGMEM), Xen will copy arbitrary data from guest-controlled
virtual address space into the per-CPU root_pgt, instead of the
intended L4.
Xen has per-domain mappings for the LDT and GDT, with two pages
reserved for Xen's use in the GDT but only one in use. Reuse GDT page
15 to map the effective L4. The GDT limit keeps implicit accesses out
of this page.
We update this mapping in make_cr3(), the only place a non-empty value
of v->arch.cr3 is written into a guest's vcpu struct, for two reasons.
First is reference counting: this makes it easier to argue that the
reference for v->arch.cr3 itself covers the reference for the mapping.
Secondly, this guarantees that all updates, even updates made in
shadow mode, result in an update to the mapping. During live
migration, it's possible for guest_get_eff_kern_l1e() to result in a
modified value of v->arch.cr3 (sketch below); placing the mapping
update at make_cr3() catches this, while other candidate locations
like write_ptbase() and toggle_guest_mode() don't.
Note that we introduce the idea of an "effective L4" here, to mean
"guest L4 after any transformations": XPTI copies either the actual
guest L4 if not shadowed, or the shadow L4 (transformed) if shadowed.
Sketch: guest_get_eff_kern_l1e() has a pair of toggle_guest_pt() calls
which happen if the guest is in user mode. During live migration, a
log-dirty clean will do a domain_pause and then call
shadow_blow_tables(), unpinning the shadow of the guest user root
pagetable. After execution resumes, the first toggle_guest_pt() could
then cause that page to become unshadowed. The second
toggle_guest_pt() would then re-shadow it, possibly with a different
backing shadow page.
This is XSA-516 / CVE-2026-79609.
Fixes: 5784de3e20 ("x86: Meltdown band-aid against malicious 64-bit PV guests")
Assisted-by: Claude Code:claude-fable-5-1
Signed-off-by: George Dunlap <gwd@xenproject.org>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
The identified commit inverted the condition under which Xen chooses
to set the Zenbleed chickenbit.
Undo that, and leave a better comment explaining why.
Found by AI review of the referenced commit.
This is XSA-515 / CVE-2026-79608.
Fixes: d0c75dc4c0 ("x86/amd: Fix race editing DE_CFG")
Assisted-by: Sashiko + Opus 5.0
Reported-by: George Dunlap <dunlapg@umich.edu>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Error path of failed sidtab_map() leaves global sidtab in shutdown state and
from that point system is unable to allocate new SIDs in sidtab_context_to_sid().
To restore sidtab state new function sidtab_cancel_shutdown() is introduced,
which only resets shutdown flag, rewinding effect of sidtab_shutdown().
Signed-off-by: Sergiy Kibrik <Sergiy_Kibrik@epam.com>
Acked-by: Daniel P. Smith <dpsmith@apertussoutions.com>
We already have two instances of this, and we're about to gain a third.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: George Dunlap <gwd@xenproject.org>
As of the referenced commit there's no reason to open-code the loop
anymore. With that replaced by a single call, there's then also no point
in using the local "mfn" in this code.
Amends: 5260e8fb93 ("xen: re-define assign_pages and introduce a new function assign_page")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: George Dunlap <gwd@xenproject.org>