This feature exposed through `dom0-iommu=no-dma` prevents the devices of default context to have access to domain's memory. This basically enforces DMA protection by default. The domain will need to prepare a specific IOMMU context to do DMA.
This feature needs the guest to provide a PV-IOMMU driver. Signed-off-by Teddy Astie <[email protected]> --- docs/misc/xen-command-line.pandoc | 16 +++++++++++++++- xen/arch/x86/x86_64/mm.c | 3 ++- xen/common/pv-iommu.c | 3 +++ xen/drivers/passthrough/iommu.c | 13 +++++++++++++ xen/drivers/passthrough/x86/iommu.c | 4 ++++ xen/include/xen/iommu.h | 3 +++ 6 files changed, 40 insertions(+), 2 deletions(-) diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 34004ce282..b528f626a7 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -941,7 +941,7 @@ is necessary to fix an issue, please report a bug. ### dom0-iommu = List of [ passthrough=<bool>, strict=<bool>, map-inclusive=<bool>, - map-reserved=<bool>, none ] + map-reserved=<bool>, dma=<bool>, none ] Controls for the dom0 IOMMU setup. @@ -992,6 +992,20 @@ Controls for the dom0 IOMMU setup. subset of the correction by only mapping reserved memory regions rather than all non-RAM regions. +* The `dma` option determines if the IOMMU is configured to identity map + the "default IOMMU context". If set to false, all devices of the Dom0 get + their DMA blocked until the IOMMU is properly configured by the guest (aside + special reserved regions). + + Disabling this can slightly improve performance by removing the need to synchronize + p2m modifications with the IOMMU subsystem, moreover, disabling it provides DMA + protection that some operating systems can expect in order to securely handle some + devices (e.g Thunderbolt). + + Disabling this requires guest support for PV-IOMMU for devices to behave properly. + + This option is enabled by default. + * The `none` option is intended for development purposes only, and skips certain safety checks pertaining to the correct IOMMU configuration for dom0 to boot. diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index d4e6a9c0a2..00ff5d0b71 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -1315,7 +1315,8 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm) */ if ( is_iommu_enabled(hardware_domain) && !iommu_use_hap_pt(hardware_domain) && - !need_iommu_pt_sync(hardware_domain) ) + !need_iommu_pt_sync(hardware_domain) && + !iommu_hwdom_no_dma ) { for ( i = spfn; i < epfn; i++ ) if ( iommu_legacy_map(hardware_domain, _dfn(i), _mfn(i), diff --git a/xen/common/pv-iommu.c b/xen/common/pv-iommu.c index 4cdb30a031..a1d0552a66 100644 --- a/xen/common/pv-iommu.c +++ b/xen/common/pv-iommu.c @@ -107,6 +107,9 @@ static long capabilities_op(struct pv_iommu_capabilities *cap, struct domain *d) cap->max_pasid = 0; /* TODO */ cap->cap_flags = 0; + if ( !dom_iommu(d)->no_dma ) + cap->cap_flags |= IOMMUCAP_default_identity; + cap->pgsize_mask = PAGE_SIZE_4K; return 0; diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index 5c6b272697..81d4cb87cf 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -55,6 +55,7 @@ static bool __hwdom_initdata iommu_hwdom_none; bool __hwdom_initdata iommu_hwdom_strict; bool __read_mostly iommu_hwdom_passthrough; bool __hwdom_initdata iommu_hwdom_inclusive; +bool __read_mostly iommu_hwdom_no_dma = false; int8_t __hwdom_initdata iommu_hwdom_reserved = -1; #ifndef iommu_hap_pt_share @@ -172,6 +173,8 @@ static int __init cf_check parse_dom0_iommu_param(const char *s) iommu_hwdom_reserved = val; else if ( !cmdline_strcmp(s, "none") ) iommu_hwdom_none = true; + else if ( (val = parse_boolean("dma", s, ss)) >= 0 ) + iommu_hwdom_no_dma = !val; else rc = -EINVAL; @@ -292,7 +295,10 @@ int iommu_domain_init(struct domain *d, unsigned int opts) int ret = 0; if ( is_hardware_domain(d) ) + { check_hwdom_reqs(d); /* may modify iommu_hwdom_strict */ + hd->no_dma = iommu_hwdom_no_dma; + } if ( !is_iommu_enabled(d) ) return 0; @@ -329,6 +335,13 @@ int iommu_domain_init(struct domain *d, unsigned int opts) if ( !is_hardware_domain(d) || iommu_hwdom_strict ) hd->need_sync = !iommu_use_hap_pt(d); + if ( hd->no_dma ) + { + /* No-DMA mode is exclusive with HAP and sync_pt. */ + hd->hap_pt_share = false; + hd->need_sync = false; + } + ASSERT(!(hd->need_sync && hd->hap_pt_share)); hd->allow_pv_iommu = true; diff --git a/xen/drivers/passthrough/x86/iommu.c b/xen/drivers/passthrough/x86/iommu.c index ac339a2ed3..b100c55e69 100644 --- a/xen/drivers/passthrough/x86/iommu.c +++ b/xen/drivers/passthrough/x86/iommu.c @@ -542,6 +542,10 @@ void __hwdom_init arch_iommu_hwdom_init(struct domain *d) if ( iommu_hwdom_reserved == -1 ) iommu_hwdom_reserved = 1; + if ( iommu_hwdom_no_dma ) + /* Skip special mappings with no-dma mode */ + return; + if ( iommu_hwdom_inclusive ) { printk(XENLOG_WARNING diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index 3c77dfaf41..55bd9c9704 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -108,6 +108,7 @@ extern bool iommu_debug; extern bool amd_iommu_perdev_intremap; extern bool iommu_hwdom_strict, iommu_hwdom_passthrough, iommu_hwdom_inclusive; +extern bool iommu_hwdom_no_dma; extern int8_t iommu_hwdom_reserved; extern unsigned int iommu_dev_iotlb_timeout; @@ -487,6 +488,8 @@ struct domain_iommu { /* SAF-2-safe enum constant in arithmetic operation */ DECLARE_BITMAP(features, IOMMU_FEAT_count); + /* Do the IOMMU block all DMA on default context (implies !has_pt_share) ? */ + bool no_dma; /* Is the domain allowed to use PV-IOMMU ? */ bool allow_pv_iommu; -- 2.51.2 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
