Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP5:Update
xen.26346
xsa378-3.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File xsa378-3.patch of Package xen.26346
IOMMU: also pass p2m_access_t to p2m_get_iommu_flags() A subsequent change will want to customize the IOMMU permissions based on this. This is part of XSA-378. Signed-off-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Paul Durrant <paul@xen.org> # Commit e70a9a043a5ce6d4025420f729bc473f711bf5d1 # Date 2021-09-07 14:24:49 +0200 # Author Jan Beulich <jbeulich@suse.com> # Committer Jan Beulich <jbeulich@suse.com> x86/p2m-pt: fix p2m_flags_to_access() The initial if() was inverted, invalidating all output from this function. Which in turn means the mirroring of P2M mappings into the IOMMU didn't always work as intended: Mappings may have got updated when there was no need to. There would not have been too few (un)mappings; what saves us is that alongside the flags comparison MFNs also get compared, with non-present entries always having an MFN of 0 or INVALID_MFN while present entries always have MFNs different from these two (0 in the table also meant to cover INVALID_MFN): OLD NEW P W access MFN P W access MFN 0 0 r 0 0 0 n 0 0 1 rw 0 0 1 n 0 1 0 n non-0 1 0 r non-0 1 1 n non-0 1 1 rw non-0 present <-> non-present transitions are fine because the MFNs differ. present -> present transitions as well as non-present -> non-present ones are potentially causing too many map/unmap operations, but never too few, because in that case old (bogus) and new access differ. Fixes: d1bb6c97c31e ("IOMMU: also pass p2m_access_t to p2m_get_iommu_flags()) Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Andrew Cooper <andrew.cooper3@citrix.com> --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -711,7 +711,7 @@ ept_set_entry(struct p2m_domain *p2m, gf uint8_t ipat = 0; bool_t need_modify_vtd_table = 1; bool_t vtd_pte_present = 0; - unsigned int iommu_flags = p2m_get_iommu_flags(p2mt, mfn); + unsigned int iommu_flags = p2m_get_iommu_flags(p2mt, p2ma, mfn); bool_t needs_sync = 1; ept_entry_t old_entry = { .epte = 0 }; ept_entry_t new_entry = { .epte = 0 }; @@ -837,8 +837,8 @@ ept_set_entry(struct p2m_domain *p2m, gf /* Safe to read-then-write because we hold the p2m lock */ if ( ept_entry->mfn == new_entry.mfn && - p2m_get_iommu_flags(ept_entry->sa_p2mt, _mfn(ept_entry->mfn)) == - iommu_flags ) + p2m_get_iommu_flags(ept_entry->sa_p2mt, ept_entry->access, + _mfn(ept_entry->mfn)) == iommu_flags ) need_modify_vtd_table = 0; ept_p2m_type_to_flags(p2m, &new_entry, p2mt, p2ma); --- a/xen/arch/x86/mm/p2m-pt.c +++ b/xen/arch/x86/mm/p2m-pt.c @@ -474,6 +474,16 @@ int p2m_pt_handle_deferred_changes(uint6 return rc; } +/* Reconstruct a fake p2m_access_t from stored PTE flags. */ +static p2m_access_t p2m_flags_to_access(unsigned int flags) +{ + if ( !(flags & _PAGE_PRESENT) ) + return p2m_access_n; + + /* No need to look at _PAGE_NX for now. */ + return flags & _PAGE_RW ? p2m_access_rw : p2m_access_r; +} + /* Returns: 0 for success, -errno for failure */ static int p2m_pt_set_entry(struct p2m_domain *p2m, gfn_t gfn_, mfn_t mfn, @@ -490,7 +500,7 @@ p2m_pt_set_entry(struct p2m_domain *p2m, l2_pgentry_t l2e_content; l3_pgentry_t l3e_content; int rc; - unsigned int iommu_pte_flags = p2m_get_iommu_flags(p2mt, mfn); + unsigned int iommu_pte_flags = p2m_get_iommu_flags(p2mt, p2ma, mfn); /* * old_mfn and iommu_old_flags control possible flush/update needs on the * IOMMU: We need to flush when MFN or flags (i.e. permissions) change. @@ -559,6 +569,7 @@ p2m_pt_set_entry(struct p2m_domain *p2m, old_mfn = l1e_get_pfn(*p2m_entry); iommu_old_flags = p2m_get_iommu_flags(p2m_flags_to_type(flags), + p2m_flags_to_access(flags), _mfn(old_mfn)); } else @@ -605,9 +616,10 @@ p2m_pt_set_entry(struct p2m_domain *p2m, 0, L1_PAGETABLE_ENTRIES); ASSERT(p2m_entry); old_mfn = l1e_get_pfn(*p2m_entry); + flags = l1e_get_flags(*p2m_entry); iommu_old_flags = - p2m_get_iommu_flags(p2m_flags_to_type(l1e_get_flags(*p2m_entry)), - _mfn(old_mfn)); + p2m_get_iommu_flags(p2m_flags_to_type(flags), + p2m_flags_to_access(flags), _mfn(old_mfn)); if ( mfn_valid(mfn) || p2m_allows_invalid_mfn(p2mt) ) entry_content = p2m_l1e_from_pfn(mfn_x(mfn), @@ -651,6 +663,7 @@ p2m_pt_set_entry(struct p2m_domain *p2m, old_mfn = l1e_get_pfn(*p2m_entry); iommu_old_flags = p2m_get_iommu_flags(p2m_flags_to_type(flags), + p2m_flags_to_access(flags), _mfn(old_mfn)); } else --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -839,7 +839,8 @@ int p2m_altp2m_propagate_change(struct d /* * p2m type to IOMMU flags */ -static inline unsigned int p2m_get_iommu_flags(p2m_type_t p2mt, mfn_t mfn) +static inline unsigned int p2m_get_iommu_flags(p2m_type_t p2mt, + p2m_access_t p2ma, mfn_t mfn) { unsigned int flags;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor