|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH v7 14/14] iommu: Introduce no-dma feature
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 <teddy.astie@xxxxxxxxxx>
---
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |