* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
-#include <xen/iommu.h>
#include <xen/vm_event.h>
#include <xen/event.h>
#include <xen/trace.h>
#include <asm/p2m.h>
#include <asm/mem_sharing.h>
#include <asm/hvm/nestedhvm.h>
-#include <asm/hvm/svm/amd-iommu-proto.h>
#include "mm-locks.h"
/*
* We may store INVALID_MFN in PTEs. We need to clip this to avoid trampling
- * over higher-order bits (NX, p2m type, IOMMU flags). We seem to not need
- * to unclip on the read path, as callers are concerned only with p2m type in
- * such cases.
+ * over higher-order bits (NX, p2m type). We seem to not need to unclip on the
+ * read path, as callers are concerned only with p2m type in such cases.
*/
#define p2m_l1e_from_pfn(pfn, flags) \
l1e_from_pfn((pfn) & (PADDR_MASK >> PAGE_SHIFT), (flags))
mfn_t mfn,
unsigned int level)
{
- unsigned long flags;
- /*
- * AMD IOMMU: When we share p2m table with iommu, bit 9 - bit 11 will be
- * used for iommu hardware to encode next io page level. Bit 59 - bit 62
- * are used for iommu flags, We could not use these bits to store p2m types.
- */
- flags = (unsigned long)(t & 0x7f) << 12;
+ unsigned long flags = (unsigned long)(t & 0x7f) << 12;
switch(t)
{
// Returns 0 on error.
//
-/* AMD IOMMU: Convert next level bits and r/w bits into 24 bits p2m flags */
-#define iommu_nlevel_to_flags(nl, f) ((((nl) & 0x7) << 9 )|(((f) & 0x3) << 21))
-
-static void p2m_add_iommu_flags(l1_pgentry_t *p2m_entry,
- unsigned int nlevel, unsigned int flags)
-{
- if ( iommu_hap_pt_share )
- l1e_add_flags(*p2m_entry, iommu_nlevel_to_flags(nlevel, flags));
-}
-
/* Returns: 0 for success, -errno for failure */
static int
p2m_next_level(struct p2m_domain *p2m, void **table,
new_entry = l1e_from_mfn(mfn, P2M_BASE_FLAGS | _PAGE_RW);
- p2m_add_iommu_flags(&new_entry, level, IOMMUF_readable|IOMMUF_writable);
rc = p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, level + 1);
if ( rc )
goto error;
l1_entry = map_domain_page(mfn);
- /* Inherit original IOMMU permissions, but update Next Level. */
- if ( iommu_hap_pt_share )
- {
- flags &= ~iommu_nlevel_to_flags(~0, 0);
- flags |= iommu_nlevel_to_flags(level - 1, 0);
- }
-
for ( i = 0; i < (1u << PAGETABLE_ORDER); i++ )
{
new_entry = l1e_from_pfn(pfn | (i << ((level - 1) * PAGETABLE_ORDER)),
unmap_domain_page(l1_entry);
new_entry = l1e_from_mfn(mfn, P2M_BASE_FLAGS | _PAGE_RW);
- p2m_add_iommu_flags(&new_entry, level,
- IOMMUF_readable|IOMMUF_writable);
rc = p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry,
level + 1);
if ( rc )
}
e = l1e_from_pfn(mfn, flags);
- p2m_add_iommu_flags(&e, level,
- (nt == p2m_ram_rw)
- ? IOMMUF_readable|IOMMUF_writable : 0);
ASSERT(!needs_recalc(l1, e));
}
else
l2_pgentry_t l2e_content;
l3_pgentry_t l3e_content;
int rc;
- unsigned int iommu_pte_flags = p2m_get_iommu_flags(p2mt, 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.
- * iommu_old_flags being initialized to zero covers the case of the entry
- * getting replaced being a non-present (leaf or intermediate) one. For
- * present leaf entries the real value will get calculated below, while
- * for present intermediate entries ~0 (guaranteed != iommu_pte_flags)
- * will be used (to cover all cases of what the leaf entries underneath
- * the intermediate one might be).
- */
- unsigned int flags, iommu_old_flags = 0;
+ unsigned int flags;
unsigned long old_mfn = mfn_x(INVALID_MFN);
if ( !sve )
if ( flags & _PAGE_PRESENT )
{
if ( flags & _PAGE_PSE )
- {
old_mfn = l1e_get_pfn(*p2m_entry);
- iommu_old_flags =
- p2m_get_iommu_flags(p2m_flags_to_type(flags),
- _mfn(old_mfn));
- }
else
- {
- iommu_old_flags = ~0;
intermediate_entry = *p2m_entry;
- }
}
check_entry(mfn, p2mt, p2m_flags_to_type(flags), page_order);
: l3e_empty();
entry_content.l1 = l3e_content.l3;
- if ( entry_content.l1 != 0 )
- p2m_add_iommu_flags(&entry_content, 0, iommu_pte_flags);
-
rc = p2m->write_p2m_entry(p2m, gfn, p2m_entry, entry_content, 3);
/* NB: paging_write_p2m_entry() handles tlb flushes properly */
if ( rc )
0, L1_PAGETABLE_ENTRIES);
ASSERT(p2m_entry);
old_mfn = l1e_get_pfn(*p2m_entry);
- iommu_old_flags =
- p2m_get_iommu_flags(p2m_flags_to_type(l1e_get_flags(*p2m_entry)),
- _mfn(old_mfn));
if ( mfn_valid(mfn) || p2m_allows_invalid_mfn(p2mt) )
entry_content = p2m_l1e_from_pfn(mfn_x(mfn),
else
entry_content = l1e_empty();
- if ( entry_content.l1 != 0 )
- p2m_add_iommu_flags(&entry_content, 0, iommu_pte_flags);
-
/* level 1 entry */
rc = p2m->write_p2m_entry(p2m, gfn, p2m_entry, entry_content, 1);
/* NB: paging_write_p2m_entry() handles tlb flushes properly */
if ( flags & _PAGE_PRESENT )
{
if ( flags & _PAGE_PSE )
- {
old_mfn = l1e_get_pfn(*p2m_entry);
- iommu_old_flags =
- p2m_get_iommu_flags(p2m_flags_to_type(flags),
- _mfn(old_mfn));
- }
else
- {
- iommu_old_flags = ~0;
intermediate_entry = *p2m_entry;
- }
}
check_entry(mfn, p2mt, p2m_flags_to_type(flags), page_order);
: l2e_empty();
entry_content.l1 = l2e_content.l2;
- if ( entry_content.l1 != 0 )
- p2m_add_iommu_flags(&entry_content, 0, iommu_pte_flags);
-
rc = p2m->write_p2m_entry(p2m, gfn, p2m_entry, entry_content, 2);
/* NB: paging_write_p2m_entry() handles tlb flushes properly */
if ( rc )
&& (gfn + (1UL << page_order) - 1 > p2m->max_mapped_pfn) )
p2m->max_mapped_pfn = gfn + (1UL << page_order) - 1;
- if ( iommu_enabled && (iommu_old_flags != iommu_pte_flags ||
- old_mfn != mfn_x(mfn)) )
- {
- ASSERT(rc == 0);
-
- if ( need_iommu_pt_sync(p2m->domain) )
- rc = iommu_pte_flags ?
- iommu_legacy_map(d, _dfn(gfn), mfn, page_order,
- iommu_pte_flags) :
- iommu_legacy_unmap(d, _dfn(gfn), page_order);
- else if ( iommu_use_hap_pt(d) && iommu_old_flags )
- amd_iommu_flush_pages(p2m->domain, gfn, page_order);
- }
-
/*
* Free old intermediate tables if necessary. This has to be the
- * last thing we do, after removal from the IOMMU tables, so as to
- * avoid a potential use-after-free.
+ * last thing we do so as to avoid a potential use-after-free.
*/
if ( l1e_get_flags(intermediate_entry) & _PAGE_PRESENT )
p2m_free_entry(p2m, &intermediate_entry, page_order);