Skip to content

Commit

Permalink
xen: Cope with unmapped pages when initializing kernel pagetable
Browse files Browse the repository at this point in the history
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 <[email protected]>
LKML-Reference: <[email protected]>
Cc: Yinghai Lu <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
  • Loading branch information
jsgf authored and H. Peter Anvin committed Oct 13, 2010
1 parent c7fc2de commit fef5ba7
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 8 deletions.
1 change: 1 addition & 0 deletions arch/x86/include/asm/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ extern void __iomem *early_memremap(resource_size_t phys_addr,
unsigned long size);
extern void early_iounmap(void __iomem *addr, unsigned long size);
extern void fixup_early_ioremap(void);
extern bool is_early_ioremap_ptep(pte_t *ptep);

#define IO_SPACE_LIMIT 0xffff

Expand Down
5 changes: 5 additions & 0 deletions arch/x86/mm/ioremap.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,11 @@ static inline pte_t * __init early_ioremap_pte(unsigned long addr)
return &bm_pte[pte_index(addr)];
}

bool __init is_early_ioremap_ptep(pte_t *ptep)
{
return ptep >= &bm_pte[0] && ptep < &bm_pte[PAGE_SIZE/sizeof(pte_t)];
}

static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata;

void __init early_ioremap_init(void)
Expand Down
26 changes: 18 additions & 8 deletions arch/x86/xen/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <asm/e820.h>
#include <asm/linkage.h>
#include <asm/page.h>
#include <asm/init.h>

#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
Expand Down Expand Up @@ -360,7 +361,8 @@ void make_lowmem_page_readonly(void *vaddr)
unsigned int level;

pte = lookup_address(address, &level);
BUG_ON(pte == NULL);
if (pte == NULL)
return; /* vaddr missing */

ptev = pte_wrprotect(*pte);

Expand All @@ -375,7 +377,8 @@ void make_lowmem_page_readwrite(void *vaddr)
unsigned int level;

pte = lookup_address(address, &level);
BUG_ON(pte == NULL);
if (pte == NULL)
return; /* vaddr missing */

ptev = pte_mkwrite(*pte);

Expand Down Expand Up @@ -1509,13 +1512,25 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
#endif
}

#ifdef CONFIG_X86_32
static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
{
unsigned long pfn = pte_pfn(pte);

#ifdef CONFIG_X86_32
/* 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));
#endif

/*
* If the new pfn is within the range of the newly allocated
* kernel pagetable, and it isn't being mapped into an
* early_ioremap fixmap slot, make sure it is RO.
*/
if (!is_early_ioremap_ptep(ptep) &&
pfn >= e820_table_start && pfn < e820_table_end)
pte = pte_wrprotect(pte);

return pte;
}
Expand All @@ -1528,7 +1543,6 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)

xen_set_pte(ptep, pte);
}
#endif

static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
{
Expand Down Expand Up @@ -1973,11 +1987,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
.alloc_pmd_clone = paravirt_nop,
.release_pmd = xen_release_pmd_init,

#ifdef CONFIG_X86_64
.set_pte = xen_set_pte,
#else
.set_pte = xen_set_pte_init,
#endif
.set_pte_at = xen_set_pte_at,
.set_pmd = xen_set_pmd_hyper,

Expand Down

0 comments on commit fef5ba7

Please sign in to comment.