docs/misc/xen-command-line.pandoc | 16 +++++-
xen/arch/x86/dom0_build.c | 5 ++
xen/arch/x86/hvm/emulate.c | 74 +++++++++++++++++++++++++-
xen/arch/x86/include/asm/hvm/emulate.h | 3 ++
5 files changed, 105 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1de1d1eca17f..e5e6ab3a8902 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,16 @@ 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.21.0 UNRELEASED](https://xenbits.xenproject.org/gitweb/?p=xen.git;a=shortlog;h=staging) - TBD
+
+### Changed
+
+### Added
+ - On x86:
+ - Option to attempt to fixup p2m page-faults on PVH dom0.
+
+### Removed
+
## [4.20.0
UNRELEASED](https://xenbits.xenproject.org/gitweb/?p=xen.git;a=shortlog;h=staging)
- TBD
### Changed
diff --git a/docs/misc/xen-command-line.pandoc
b/docs/misc/xen-command-line.pandoc
index 9bbd00baef91..83bb69cfb852 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=<bool>, verbose=<bool>,
- cpuid-faulting=<bool>, msr-relaxed=<bool> ] (x86)
+ cpuid-faulting=<bool>, msr-relaxed=<bool>,
+ pf-fixup=<bool> ] (x86)
= List of [ sve=<integer> ] (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 2fe6b449149e..11c20b9ab0a4 100644
--- a/xen/arch/x86/dom0_build.c
+++ b/xen/arch/x86/dom0_build.c
@@ -16,6 +16,7 @@
#include <asm/dom0_build.h>
#include <asm/guest.h>
#include <asm/hpet.h>
+#include <asm/hvm/emulate.h>
#include <asm/io-ports.h>
#include <asm/io_apic.h>
#include <asm/p2m.h>
@@ -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 08b9493e6d88..3cd7f2e22f26 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -10,12 +10,15 @@
*/
#include <xen/init.h>
+#include <xen/iocap.h>
#include <xen/ioreq.h>
#include <xen/lib.h>
#include <xen/sched.h>
#include <xen/paging.h>
#include <xen/trace.h>
#include <xen/vm_event.h>
+
+#include <asm/altp2m.h>
#include <asm/event.h>
#include <asm/i387.h>
#include <asm/xstate.h>
@@ -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 760ce5e77cce..d17c025a1d45 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__ */
/*