|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 06/18] IOMMU/x86: restrict IO-APIC mappings for PV Dom0
On Fri, Sep 24, 2021 at 11:46:57AM +0200, Jan Beulich wrote:
> While already the case for PVH, there's no reason to treat PV
> differently here, though of course the addresses get taken from another
> source in this case. Except that, to match CPU side mappings, by default
> we permit r/o ones. This then also means we now deal consistently with
> IO-APICs whose MMIO is or is not covered by E820 reserved regions.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> [integrated] v1: Integrate into series.
> [standalone] v2: Keep IOMMU mappings in sync with CPU ones.
>
> --- a/xen/drivers/passthrough/x86/iommu.c
> +++ b/xen/drivers/passthrough/x86/iommu.c
> @@ -253,12 +253,12 @@ void iommu_identity_map_teardown(struct
> }
> }
>
> -static bool __hwdom_init hwdom_iommu_map(const struct domain *d,
> - unsigned long pfn,
> - unsigned long max_pfn)
> +static unsigned int __hwdom_init hwdom_iommu_map(const struct domain *d,
> + unsigned long pfn,
> + unsigned long max_pfn)
> {
> mfn_t mfn = _mfn(pfn);
> - unsigned int i, type;
> + unsigned int i, type, perms = IOMMUF_readable | IOMMUF_writable;
>
> /*
> * Set up 1:1 mapping for dom0. Default to include only conventional RAM
> @@ -267,44 +267,60 @@ static bool __hwdom_init hwdom_iommu_map
> * that fall in unusable ranges for PV Dom0.
> */
> if ( (pfn > max_pfn && !mfn_valid(mfn)) || xen_in_range(pfn) )
> - return false;
> + return 0;
>
> switch ( type = page_get_ram_type(mfn) )
> {
> case RAM_TYPE_UNUSABLE:
> - return false;
> + return 0;
>
> case RAM_TYPE_CONVENTIONAL:
> if ( iommu_hwdom_strict )
> - return false;
> + return 0;
> break;
>
> default:
> if ( type & RAM_TYPE_RESERVED )
> {
> if ( !iommu_hwdom_inclusive && !iommu_hwdom_reserved )
> - return false;
> + perms = 0;
> }
> - else if ( is_hvm_domain(d) || !iommu_hwdom_inclusive || pfn >
> max_pfn )
> - return false;
> + else if ( is_hvm_domain(d) )
> + return 0;
> + else if ( !iommu_hwdom_inclusive || pfn > max_pfn )
> + perms = 0;
I'm confused about the reason to set perms = 0 instead of just
returning here. AFAICT perms won't be set to any other value below,
so you might as well just return 0.
> }
>
> /* Check that it doesn't overlap with the Interrupt Address Range. */
> if ( pfn >= 0xfee00 && pfn <= 0xfeeff )
> - return false;
> + return 0;
> /* ... or the IO-APIC */
> - for ( i = 0; has_vioapic(d) && i < d->arch.hvm.nr_vioapics; i++ )
> - if ( pfn == PFN_DOWN(domain_vioapic(d, i)->base_address) )
> - return false;
> + if ( has_vioapic(d) )
> + {
> + for ( i = 0; i < d->arch.hvm.nr_vioapics; i++ )
> + if ( pfn == PFN_DOWN(domain_vioapic(d, i)->base_address) )
> + return 0;
> + }
> + else if ( is_pv_domain(d) )
> + {
> + /*
> + * Be consistent with CPU mappings: Dom0 is permitted to establish
> r/o
> + * ones there, so it should also have such established for IOMMUs.
> + */
> + for ( i = 0; i < nr_ioapics; i++ )
> + if ( pfn == PFN_DOWN(mp_ioapics[i].mpc_apicaddr) )
> + return rangeset_contains_singleton(mmio_ro_ranges, pfn)
> + ? IOMMUF_readable : 0;
> + }
Note that the emulated vIO-APICs are mapped over the real ones (ie:
using the same base addresses), and hence both loops will end up using
the same regions. I would rather keep them separated anyway, just in
case we decide to somehow change the position of the emulated ones in
the future.
> /*
> * ... or the PCIe MCFG regions.
> * TODO: runtime added MMCFG regions are not checked to make sure they
> * don't overlap with already mapped regions, thus preventing trapping.
> */
> if ( has_vpci(d) && vpci_is_mmcfg_address(d, pfn_to_paddr(pfn)) )
> - return false;
> + return 0;
>
> - return true;
> + return perms;
> }
>
> void __hwdom_init arch_iommu_hwdom_init(struct domain *d)
> @@ -346,15 +362,19 @@ void __hwdom_init arch_iommu_hwdom_init(
> for ( ; i < top; i++ )
> {
> unsigned long pfn = pdx_to_pfn(i);
> + unsigned int perms = hwdom_iommu_map(d, pfn, max_pfn);
> int rc;
>
> - if ( !hwdom_iommu_map(d, pfn, max_pfn) )
> + if ( !perms )
> rc = 0;
> else if ( paging_mode_translate(d) )
> - rc = set_identity_p2m_entry(d, pfn, p2m_access_rw, 0);
> + rc = set_identity_p2m_entry(d, pfn,
> + perms & IOMMUF_writable ?
> p2m_access_rw
> + :
> p2m_access_r,
> + 0);
> else
> rc = iommu_map(d, _dfn(pfn), _mfn(pfn), 1ul << PAGE_ORDER_4K,
> - IOMMUF_readable | IOMMUF_writable, &flush_flags);
> + perms, &flush_flags);
You could just call set_identity_p2m_entry uniformly here. It will
DTRT for non-translated guests also, and then hwdom_iommu_map could
perhaps return a p2m_access_t?
Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |