xen: Cope with unmapped pages when initializing kernel pagetable

Xen requires that all pages containing pagetable entries to be mapped
read-only. If pages used for the initial pagetable are already mapped
then we can change the mapping to RO. However, if they are initially
unmapped, we need to make sure that when they are later mapped, they
are also mapped RO.

We do this by knowing that the kernel pagetable memory is pre-allocated
in the range e820_table_start - e820_table_end, so any pfn within this
range should be mapped read-only. However, the pagetable setup code
early_ioremaps the pages to write their entries, so we must make sure
that mappings created in the early_ioremap fixmap area are mapped RW.
(Those mappings are removed before the pages are presented to Xen
as pagetable pages.)

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
LKML-Reference: <4CB63A80.8060702@goop.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

authored by Jeremy Fitzhardinge and committed by H. Peter Anvin fef5ba79 c7fc2de0

+24 -8
+1
arch/x86/include/asm/io.h
··· 348 348 unsigned long size); 349 349 extern void early_iounmap(void __iomem *addr, unsigned long size); 350 350 extern void fixup_early_ioremap(void); 351 + extern bool is_early_ioremap_ptep(pte_t *ptep); 351 352 352 353 #define IO_SPACE_LIMIT 0xffff 353 354
+5
arch/x86/mm/ioremap.c
··· 362 362 return &bm_pte[pte_index(addr)]; 363 363 } 364 364 365 + bool __init is_early_ioremap_ptep(pte_t *ptep) 366 + { 367 + return ptep >= &bm_pte[0] && ptep < &bm_pte[PAGE_SIZE/sizeof(pte_t)]; 368 + } 369 + 365 370 static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata; 366 371 367 372 void __init early_ioremap_init(void)
+18 -8
arch/x86/xen/mmu.c
··· 56 56 #include <asm/e820.h> 57 57 #include <asm/linkage.h> 58 58 #include <asm/page.h> 59 + #include <asm/init.h> 59 60 60 61 #include <asm/xen/hypercall.h> 61 62 #include <asm/xen/hypervisor.h> ··· 361 360 unsigned int level; 362 361 363 362 pte = lookup_address(address, &level); 364 - BUG_ON(pte == NULL); 363 + if (pte == NULL) 364 + return; /* vaddr missing */ 365 365 366 366 ptev = pte_wrprotect(*pte); 367 367 ··· 377 375 unsigned int level; 378 376 379 377 pte = lookup_address(address, &level); 380 - BUG_ON(pte == NULL); 378 + if (pte == NULL) 379 + return; /* vaddr missing */ 381 380 382 381 ptev = pte_mkwrite(*pte); 383 382 ··· 1512 1509 #endif 1513 1510 } 1514 1511 1515 - #ifdef CONFIG_X86_32 1516 1512 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) 1517 1513 { 1514 + unsigned long pfn = pte_pfn(pte); 1515 + 1516 + #ifdef CONFIG_X86_32 1518 1517 /* If there's an existing pte, then don't allow _PAGE_RW to be set */ 1519 1518 if (pte_val_ma(*ptep) & _PAGE_PRESENT) 1520 1519 pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) & 1521 1520 pte_val_ma(pte)); 1521 + #endif 1522 + 1523 + /* 1524 + * If the new pfn is within the range of the newly allocated 1525 + * kernel pagetable, and it isn't being mapped into an 1526 + * early_ioremap fixmap slot, make sure it is RO. 1527 + */ 1528 + if (!is_early_ioremap_ptep(ptep) && 1529 + pfn >= e820_table_start && pfn < e820_table_end) 1530 + pte = pte_wrprotect(pte); 1522 1531 1523 1532 return pte; 1524 1533 } ··· 1543 1528 1544 1529 xen_set_pte(ptep, pte); 1545 1530 } 1546 - #endif 1547 1531 1548 1532 static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) 1549 1533 { ··· 1987 1973 .alloc_pmd_clone = paravirt_nop, 1988 1974 .release_pmd = xen_release_pmd_init, 1989 1975 1990 - #ifdef CONFIG_X86_64 1991 - .set_pte = xen_set_pte, 1992 - #else 1993 1976 .set_pte = xen_set_pte_init, 1994 - #endif 1995 1977 .set_pte_at = xen_set_pte_at, 1996 1978 .set_pmd = xen_set_pmd_hyper, 1997 1979