mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 16:12:02 +00:00
x86/xen: avoid m2p lookup when setting early page table entries
When page tables entries are set using xen_set_pte_init() during early boot there is no page fault handler that could handle a fault when performing an M2P lookup. In 64 bit guests (usually dom0) early_ioremap() would fault in xen_set_pte_init() because an M2P lookup faults because the MFN is in MMIO space and not mapped in the M2P. This lookup is done to see if the PFN in in the range used for the initial page table pages, so that the PTE may be set as read-only. The M2P lookup can be avoided by moving the check (and clear of RW) earlier when the PFN is still available. Reported-by: Kevin Moraga <kmoragas@riseup.net> Signed-off-by: David Vrabel <david.vrabel@citrix.com> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Reviewed-by: Juergen Gross <jgross@suse.com>
This commit is contained in:
parent
02ef871eca
commit
d6b186c1e2
@ -1551,41 +1551,6 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
|
|
||||||
{
|
|
||||||
/* If there's an existing pte, then don't allow _PAGE_RW to be set */
|
|
||||||
if (pte_val_ma(*ptep) & _PAGE_PRESENT)
|
|
||||||
pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
|
|
||||||
pte_val_ma(pte));
|
|
||||||
|
|
||||||
return pte;
|
|
||||||
}
|
|
||||||
#else /* CONFIG_X86_64 */
|
|
||||||
static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
|
|
||||||
{
|
|
||||||
unsigned long pfn;
|
|
||||||
|
|
||||||
if (xen_feature(XENFEAT_writable_page_tables) ||
|
|
||||||
xen_feature(XENFEAT_auto_translated_physmap) ||
|
|
||||||
xen_start_info->mfn_list >= __START_KERNEL_map)
|
|
||||||
return pte;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pages belonging to the initial p2m list mapped outside the default
|
|
||||||
* address range must be mapped read-only. This region contains the
|
|
||||||
* page tables for mapping the p2m list, too, and page tables MUST be
|
|
||||||
* mapped read-only.
|
|
||||||
*/
|
|
||||||
pfn = pte_pfn(pte);
|
|
||||||
if (pfn >= xen_start_info->first_p2m_pfn &&
|
|
||||||
pfn < xen_start_info->first_p2m_pfn + xen_start_info->nr_p2m_frames)
|
|
||||||
pte = __pte_ma(pte_val_ma(pte) & ~_PAGE_RW);
|
|
||||||
|
|
||||||
return pte;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_X86_64 */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init-time set_pte while constructing initial pagetables, which
|
* Init-time set_pte while constructing initial pagetables, which
|
||||||
* doesn't allow RO page table pages to be remapped RW.
|
* doesn't allow RO page table pages to be remapped RW.
|
||||||
@ -1600,13 +1565,37 @@ static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
|
|||||||
* so always write the PTE directly and rely on Xen trapping and
|
* so always write the PTE directly and rely on Xen trapping and
|
||||||
* emulating any updates as necessary.
|
* emulating any updates as necessary.
|
||||||
*/
|
*/
|
||||||
|
__visible pte_t xen_make_pte_init(pteval_t pte)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
unsigned long pfn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pages belonging to the initial p2m list mapped outside the default
|
||||||
|
* address range must be mapped read-only. This region contains the
|
||||||
|
* page tables for mapping the p2m list, too, and page tables MUST be
|
||||||
|
* mapped read-only.
|
||||||
|
*/
|
||||||
|
pfn = (pte & PTE_PFN_MASK) >> PAGE_SHIFT;
|
||||||
|
if (xen_start_info->mfn_list < __START_KERNEL_map &&
|
||||||
|
pfn >= xen_start_info->first_p2m_pfn &&
|
||||||
|
pfn < xen_start_info->first_p2m_pfn + xen_start_info->nr_p2m_frames)
|
||||||
|
pte &= ~_PAGE_RW;
|
||||||
|
#endif
|
||||||
|
pte = pte_pfn_to_mfn(pte);
|
||||||
|
return native_make_pte(pte);
|
||||||
|
}
|
||||||
|
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_init);
|
||||||
|
|
||||||
static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
|
static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
|
||||||
{
|
{
|
||||||
if (pte_mfn(pte) != INVALID_P2M_ENTRY)
|
#ifdef CONFIG_X86_32
|
||||||
pte = mask_rw_pte(ptep, pte);
|
/* If there's an existing pte, then don't allow _PAGE_RW to be set */
|
||||||
else
|
if (pte_mfn(pte) != INVALID_P2M_ENTRY
|
||||||
pte = __pte_ma(0);
|
&& pte_val_ma(*ptep) & _PAGE_PRESENT)
|
||||||
|
pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
|
||||||
|
pte_val_ma(pte));
|
||||||
|
#endif
|
||||||
native_set_pte(ptep, pte);
|
native_set_pte(ptep, pte);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2407,6 +2396,7 @@ static void __init xen_post_allocator_init(void)
|
|||||||
pv_mmu_ops.alloc_pud = xen_alloc_pud;
|
pv_mmu_ops.alloc_pud = xen_alloc_pud;
|
||||||
pv_mmu_ops.release_pud = xen_release_pud;
|
pv_mmu_ops.release_pud = xen_release_pud;
|
||||||
#endif
|
#endif
|
||||||
|
pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte);
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
pv_mmu_ops.write_cr3 = &xen_write_cr3;
|
pv_mmu_ops.write_cr3 = &xen_write_cr3;
|
||||||
@ -2455,7 +2445,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
|
|||||||
.pte_val = PV_CALLEE_SAVE(xen_pte_val),
|
.pte_val = PV_CALLEE_SAVE(xen_pte_val),
|
||||||
.pgd_val = PV_CALLEE_SAVE(xen_pgd_val),
|
.pgd_val = PV_CALLEE_SAVE(xen_pgd_val),
|
||||||
|
|
||||||
.make_pte = PV_CALLEE_SAVE(xen_make_pte),
|
.make_pte = PV_CALLEE_SAVE(xen_make_pte_init),
|
||||||
.make_pgd = PV_CALLEE_SAVE(xen_make_pgd),
|
.make_pgd = PV_CALLEE_SAVE(xen_make_pgd),
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
#ifdef CONFIG_X86_PAE
|
||||||
|
Loading…
Reference in New Issue
Block a user