### 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)
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
*/
#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>
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)
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;
}