[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] Ping: [PATCH v3 1/3] x86/p2m-pt: simplify p2m_next_level()
>>> On 11.08.17 at 15:19, <JBeulich@xxxxxxxx> wrote: > Calculate entry PFN and flags just once. Convert the two successive > main if()-s to and if/else-if chain. Restrict variable scope where > reasonable. Take the opportunity and also make the induction variable > unsigned. > > This at once fixes excessive permissions granted in the 2M PTEs > resulting from splitting a 1G one - original permissions should be > inherited instead. This is not a security issue only because all of > this takes no effect anyway, as iommu_hap_pt_share is always false on > AMD systems for all supported branches. > > Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> > --- > v3: Fix IOMMU permission handling for shattered PTEs. > v2: Re-do mostly from scratch following review feedback. > > --- a/xen/arch/x86/mm/p2m-pt.c > +++ b/xen/arch/x86/mm/p2m-pt.c > @@ -191,18 +191,18 @@ p2m_next_level(struct p2m_domain *p2m, v > unsigned long *gfn_remainder, unsigned long gfn, u32 shift, > u32 max, unsigned long type, bool_t unmap) > { > - l1_pgentry_t *l1_entry; > - l1_pgentry_t *p2m_entry; > - l1_pgentry_t new_entry; > + l1_pgentry_t *p2m_entry, new_entry; > void *next; > - int i; > + unsigned int flags; > > if ( !(p2m_entry = p2m_find_entry(*table, gfn_remainder, gfn, > shift, max)) ) > return -ENOENT; > > + flags = l1e_get_flags(*p2m_entry); > + > /* PoD/paging: Not present doesn't imply empty. */ > - if ( !l1e_get_flags(*p2m_entry) ) > + if ( !flags ) > { > struct page_info *pg; > > @@ -231,70 +231,67 @@ p2m_next_level(struct p2m_domain *p2m, v > break; > } > } > - > - ASSERT(l1e_get_flags(*p2m_entry) & (_PAGE_PRESENT|_PAGE_PSE)); > - > - /* split 1GB pages into 2MB pages */ > - if ( type == PGT_l2_page_table && (l1e_get_flags(*p2m_entry) & > _PAGE_PSE) > ) > + else if ( flags & _PAGE_PSE ) > { > - unsigned long flags, pfn; > + /* Split superpages pages into smaller ones. */ > + unsigned long pfn = l1e_get_pfn(*p2m_entry); > struct page_info *pg; > + l1_pgentry_t *l1_entry; > + unsigned int i, level; > > - pg = p2m_alloc_ptp(p2m, PGT_l2_page_table); > - if ( pg == NULL ) > - return -ENOMEM; > - > - flags = l1e_get_flags(*p2m_entry); > - pfn = l1e_get_pfn(*p2m_entry); > - > - l1_entry = __map_domain_page(pg); > - for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) > + switch ( type ) > { > - new_entry = l1e_from_pfn(pfn | (i * L1_PAGETABLE_ENTRIES), > flags); > - p2m_add_iommu_flags(&new_entry, 1, > IOMMUF_readable|IOMMUF_writable); > - p2m->write_p2m_entry(p2m, gfn, l1_entry + i, new_entry, 2); > - } > - unmap_domain_page(l1_entry); > - new_entry = l1e_from_pfn(mfn_x(page_to_mfn(pg)), > - P2M_BASE_FLAGS | _PAGE_RW); /* disable PSE > */ > - p2m_add_iommu_flags(&new_entry, 2, IOMMUF_readable|IOMMUF_writable); > - p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, 3); > - } > + case PGT_l2_page_table: > + level = 2; > + break; > > + case PGT_l1_page_table: > + /* > + * New splintered mappings inherit the flags of the old > superpage, > + * with a little reorganisation for the _PAGE_PSE_PAT bit. > + */ > + if ( pfn & 1 ) /* ==> _PAGE_PSE_PAT was set */ > + pfn -= 1; /* Clear it; _PAGE_PSE becomes > _PAGE_PAT */ > + else > + flags &= ~_PAGE_PSE; /* Clear _PAGE_PSE (== _PAGE_PAT) */ > > - /* split single 2MB large page into 4KB page in P2M table */ > - if ( type == PGT_l1_page_table && (l1e_get_flags(*p2m_entry) & > _PAGE_PSE) > ) > - { > - unsigned long flags, pfn; > - struct page_info *pg; > + level = 1; > + break; > + > + default: > + ASSERT_UNREACHABLE(); > + return -EINVAL; > + } > > - pg = p2m_alloc_ptp(p2m, PGT_l1_page_table); > + pg = p2m_alloc_ptp(p2m, type); > if ( pg == NULL ) > return -ENOMEM; > > - /* New splintered mappings inherit the flags of the old superpage, > - * with a little reorganisation for the _PAGE_PSE_PAT bit. */ > - flags = l1e_get_flags(*p2m_entry); > - pfn = l1e_get_pfn(*p2m_entry); > - if ( pfn & 1 ) /* ==> _PAGE_PSE_PAT was set */ > - pfn -= 1; /* Clear it; _PAGE_PSE becomes _PAGE_PAT > */ > - else > - flags &= ~_PAGE_PSE; /* Clear _PAGE_PSE (== _PAGE_PAT) */ > - > l1_entry = __map_domain_page(pg); > - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) > + > + /* Inherit original IOMMU permissions, but update Next Level. */ > + if ( iommu_hap_pt_share ) > { > - new_entry = l1e_from_pfn(pfn | i, flags); > - p2m_add_iommu_flags(&new_entry, 0, 0); > - p2m->write_p2m_entry(p2m, gfn, l1_entry + i, new_entry, 1); > + 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)), > + flags); > + p2m->write_p2m_entry(p2m, gfn, l1_entry + i, new_entry, level); > + } > + > unmap_domain_page(l1_entry); > - > + > new_entry = l1e_from_pfn(mfn_x(page_to_mfn(pg)), > P2M_BASE_FLAGS | _PAGE_RW); > - p2m_add_iommu_flags(&new_entry, 1, IOMMUF_readable|IOMMUF_writable); > - p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, 2); > + p2m_add_iommu_flags(&new_entry, level, > IOMMUF_readable|IOMMUF_writable); > + p2m->write_p2m_entry(p2m, gfn, p2m_entry, new_entry, level + 1); > } > + else > + ASSERT(flags & _PAGE_PRESENT); > > next = map_domain_page(_mfn(l1e_get_pfn(*p2m_entry))); > if ( unmap ) > > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxx > https://lists.xen.org/xen-devel _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |