diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b9ba49225..d098e7c5ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ Notable changes to Xen will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [4.20.1](https://xenbits.xenproject.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.20.1) + +### Added + - On x86: + - Option to attempt to fixup p2m page-faults on PVH dom0. + ## [4.20.0](https://xenbits.xenproject.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.20.0) - 2025-03-05 ### Changed diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 9bbd00baef..83bb69cfb8 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -822,7 +822,8 @@ Specify the bit width of the DMA heap. ### dom0 = List of [ pv | pvh, shadow=, verbose=, - cpuid-faulting=, msr-relaxed= ] (x86) + cpuid-faulting=, msr-relaxed=, + pf-fixup= ] (x86) = List of [ sve= ] (Arm64) @@ -883,6 +884,19 @@ Controls for how dom0 is constructed on x86 systems. If using this option is necessary to fix an issue, please report a bug. +* The `pf-fixup` boolean is only applicable when using a PVH dom0 and + defaults to false. + + When running dom0 in PVH mode the dom0 kernel has no way to map MMIO + regions into its physical memory map, such mode relies on Xen dom0 builder + populating the physical memory map with all MMIO regions that dom0 should + access. However Xen doesn't have a complete picture of the host memory + map, due to not being able to process ACPI dynamic tables. + + The `pf-fixup` option allows Xen to attempt to add missing MMIO regions + to the dom0 physical memory map in response to page-faults generated by + dom0 trying to access unpopulated entries in the memory map. + Enables features on dom0 on Arm systems. * The `sve` integer parameter enables Arm SVE usage for Dom0 and sets the diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index e8f5bf5447..3b9681dc91 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -286,6 +287,10 @@ int __init parse_arch_dom0_param(const char *s, const char *e) opt_dom0_cpuid_faulting = val; else if ( (val = parse_boolean("msr-relaxed", s, e)) >= 0 ) opt_dom0_msr_relaxed = val; +#ifdef CONFIG_HVM + else if ( (val = parse_boolean("pf-fixup", s, e)) >= 0 ) + opt_dom0_pf_fixup = val; +#endif else return -EINVAL; diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index 08b9493e6d..3cd7f2e22f 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -10,12 +10,15 @@ */ #include +#include #include #include #include #include #include #include + +#include #include #include #include @@ -161,6 +164,36 @@ void hvmemul_cancel(struct vcpu *v) hvmemul_cache_disable(v); } +bool __ro_after_init opt_dom0_pf_fixup; +static int hwdom_fixup_p2m(paddr_t addr) +{ + unsigned long gfn = paddr_to_pfn(addr); + struct domain *currd = current->domain; + p2m_type_t type; + mfn_t mfn; + int rc; + + ASSERT(is_hardware_domain(currd)); + ASSERT(!altp2m_active(currd)); + + /* + * Fixups are only applied for MMIO holes, and rely on the hardware domain + * having identity mappings for non RAM regions (gfn == mfn). + */ + if ( !iomem_access_permitted(currd, gfn, gfn) || + !is_memory_hole(_mfn(gfn), _mfn(gfn)) ) + return -EPERM; + + mfn = get_gfn(currd, gfn, &type); + if ( !mfn_eq(mfn, INVALID_MFN) || !p2m_is_hole(type) ) + rc = mfn_eq(mfn, _mfn(gfn)) ? -EEXIST : -ENOTEMPTY; + else + rc = set_mmio_p2m_entry(currd, _gfn(gfn), _mfn(gfn), 0); + put_gfn(currd, gfn); + + return rc; +} + static int hvmemul_do_io( bool is_mmio, paddr_t addr, unsigned long *reps, unsigned int size, uint8_t dir, bool df, bool data_is_addr, uintptr_t data) @@ -338,8 +371,45 @@ static int hvmemul_do_io( if ( !s ) { if ( is_mmio && is_hardware_domain(currd) ) - gdprintk(XENLOG_DEBUG, "unhandled memory %s %#lx size %u\n", - dir ? "read from" : "write to", addr, size); + { + /* + * PVH dom0 is likely missing MMIO mappings on the p2m, due to + * the incomplete information Xen has about the memory layout. + * + * Either print a message to note dom0 attempted to access an + * unpopulated GPA, or try to fixup the p2m by creating an + * identity mapping for the faulting GPA. + */ + if ( opt_dom0_pf_fixup ) + { + int inner_rc = hwdom_fixup_p2m(addr); + + if ( !inner_rc || inner_rc == -EEXIST ) + { + if ( !inner_rc ) + gdprintk(XENLOG_DEBUG, + "fixup p2m mapping for page %lx added\n", + paddr_to_pfn(addr)); + else + gprintk(XENLOG_INFO, + "fixup p2m mapping for page %lx already present\n", + paddr_to_pfn(addr)); + + rc = X86EMUL_RETRY; + vio->req.state = STATE_IOREQ_NONE; + break; + } + + gprintk(XENLOG_WARNING, + "unable to fixup memory %s %#lx size %u: %d\n", + dir ? "read from" : "write to", addr, size, + inner_rc); + } + else + gdprintk(XENLOG_DEBUG, + "unhandled memory %s %#lx size %u\n", + dir ? "read from" : "write to", addr, size); + } rc = hvm_process_io_intercept(&null_handler, &p); vio->req.state = STATE_IOREQ_NONE; } diff --git a/xen/arch/x86/include/asm/hvm/emulate.h b/xen/arch/x86/include/asm/hvm/emulate.h index 45b03e4e37..d61eacfaa7 100644 --- a/xen/arch/x86/include/asm/hvm/emulate.h +++ b/xen/arch/x86/include/asm/hvm/emulate.h @@ -148,6 +148,9 @@ static inline void hvmemul_write_cache(const struct vcpu *v, paddr_t gpa, void hvm_dump_emulation_state(const char *loglvl, const char *prefix, struct hvm_emulate_ctxt *hvmemul_ctxt, int rc); +/* For PVH dom0: signal whether to attempt fixup of p2m page-faults. */ +extern bool opt_dom0_pf_fixup; + #endif /* __ASM_X86_HVM_EMULATE_H__ */ /*