Skip to content

Commit d6b186c

Browse files
author
David Vrabel
committed
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 <[email protected]> Signed-off-by: David Vrabel <[email protected]> Reviewed-by: Boris Ostrovsky <[email protected]> Reviewed-by: Juergen Gross <[email protected]>
1 parent 02ef871 commit d6b186c

File tree

1 file changed

+31
-41
lines changed

1 file changed

+31
-41
lines changed

arch/x86/xen/mmu.c

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,41 +1551,6 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
15511551
#endif
15521552
}
15531553

1554-
#ifdef CONFIG_X86_32
1555-
static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
1556-
{
1557-
/* If there's an existing pte, then don't allow _PAGE_RW to be set */
1558-
if (pte_val_ma(*ptep) & _PAGE_PRESENT)
1559-
pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
1560-
pte_val_ma(pte));
1561-
1562-
return pte;
1563-
}
1564-
#else /* CONFIG_X86_64 */
1565-
static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
1566-
{
1567-
unsigned long pfn;
1568-
1569-
if (xen_feature(XENFEAT_writable_page_tables) ||
1570-
xen_feature(XENFEAT_auto_translated_physmap) ||
1571-
xen_start_info->mfn_list >= __START_KERNEL_map)
1572-
return pte;
1573-
1574-
/*
1575-
* Pages belonging to the initial p2m list mapped outside the default
1576-
* address range must be mapped read-only. This region contains the
1577-
* page tables for mapping the p2m list, too, and page tables MUST be
1578-
* mapped read-only.
1579-
*/
1580-
pfn = pte_pfn(pte);
1581-
if (pfn >= xen_start_info->first_p2m_pfn &&
1582-
pfn < xen_start_info->first_p2m_pfn + xen_start_info->nr_p2m_frames)
1583-
pte = __pte_ma(pte_val_ma(pte) & ~_PAGE_RW);
1584-
1585-
return pte;
1586-
}
1587-
#endif /* CONFIG_X86_64 */
1588-
15891554
/*
15901555
* Init-time set_pte while constructing initial pagetables, which
15911556
* 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)
16001565
* so always write the PTE directly and rely on Xen trapping and
16011566
* emulating any updates as necessary.
16021567
*/
1603-
static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
1568+
__visible pte_t xen_make_pte_init(pteval_t pte)
16041569
{
1605-
if (pte_mfn(pte) != INVALID_P2M_ENTRY)
1606-
pte = mask_rw_pte(ptep, pte);
1607-
else
1608-
pte = __pte_ma(0);
1570+
#ifdef CONFIG_X86_64
1571+
unsigned long pfn;
1572+
1573+
/*
1574+
* Pages belonging to the initial p2m list mapped outside the default
1575+
* address range must be mapped read-only. This region contains the
1576+
* page tables for mapping the p2m list, too, and page tables MUST be
1577+
* mapped read-only.
1578+
*/
1579+
pfn = (pte & PTE_PFN_MASK) >> PAGE_SHIFT;
1580+
if (xen_start_info->mfn_list < __START_KERNEL_map &&
1581+
pfn >= xen_start_info->first_p2m_pfn &&
1582+
pfn < xen_start_info->first_p2m_pfn + xen_start_info->nr_p2m_frames)
1583+
pte &= ~_PAGE_RW;
1584+
#endif
1585+
pte = pte_pfn_to_mfn(pte);
1586+
return native_make_pte(pte);
1587+
}
1588+
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_init);
16091589

1590+
static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
1591+
{
1592+
#ifdef CONFIG_X86_32
1593+
/* If there's an existing pte, then don't allow _PAGE_RW to be set */
1594+
if (pte_mfn(pte) != INVALID_P2M_ENTRY
1595+
&& pte_val_ma(*ptep) & _PAGE_PRESENT)
1596+
pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
1597+
pte_val_ma(pte));
1598+
#endif
16101599
native_set_pte(ptep, pte);
16111600
}
16121601

@@ -2407,6 +2396,7 @@ static void __init xen_post_allocator_init(void)
24072396
pv_mmu_ops.alloc_pud = xen_alloc_pud;
24082397
pv_mmu_ops.release_pud = xen_release_pud;
24092398
#endif
2399+
pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte);
24102400

24112401
#ifdef CONFIG_X86_64
24122402
pv_mmu_ops.write_cr3 = &xen_write_cr3;
@@ -2455,7 +2445,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
24552445
.pte_val = PV_CALLEE_SAVE(xen_pte_val),
24562446
.pgd_val = PV_CALLEE_SAVE(xen_pgd_val),
24572447

2458-
.make_pte = PV_CALLEE_SAVE(xen_make_pte),
2448+
.make_pte = PV_CALLEE_SAVE(xen_make_pte_init),
24592449
.make_pgd = PV_CALLEE_SAVE(xen_make_pgd),
24602450

24612451
#ifdef CONFIG_X86_PAE

0 commit comments

Comments
 (0)