2005-04-17 05:20:36 +07:00
|
|
|
#ifndef _I386_PGTABLE_H
|
|
|
|
#define _I386_PGTABLE_H
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The Linux memory management assumes a three-level page table setup. On
|
|
|
|
* the i386, we use that, but "fold" the mid level into the top-level page
|
|
|
|
* table, so that we physically have the same two-level page table as the
|
|
|
|
* i386 mmu expects.
|
|
|
|
*
|
|
|
|
* This file contains the functions and defines necessary to modify and use
|
|
|
|
* the i386 page table tree.
|
|
|
|
*/
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <asm/processor.h>
|
|
|
|
#include <asm/fixmap.h>
|
|
|
|
#include <linux/threads.h>
|
2006-12-07 08:14:08 +07:00
|
|
|
#include <asm/paravirt.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2007-10-19 13:40:25 +07:00
|
|
|
#include <linux/bitops.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
|
2005-11-07 15:59:43 +07:00
|
|
|
struct mm_struct;
|
|
|
|
struct vm_area_struct;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* ZERO_PAGE is a global shared page that is always zero: used
|
|
|
|
* for zero-mapped memory areas etc..
|
|
|
|
*/
|
|
|
|
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
|
|
|
|
extern unsigned long empty_zero_page[1024];
|
|
|
|
extern pgd_t swapper_pg_dir[1024];
|
2006-12-07 11:33:20 +07:00
|
|
|
extern struct kmem_cache *pmd_cache;
|
2005-04-17 05:20:36 +07:00
|
|
|
extern spinlock_t pgd_lock;
|
|
|
|
extern struct page *pgd_list;
|
2007-05-13 01:15:24 +07:00
|
|
|
void check_pgt_cache(void);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2007-10-17 13:25:51 +07:00
|
|
|
void pmd_ctor(struct kmem_cache *, void *);
|
2005-04-17 05:20:36 +07:00
|
|
|
void pgtable_cache_init(void);
|
|
|
|
void paging_init(void);
|
|
|
|
|
2007-05-13 01:15:24 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* The Linux x86 paging architecture is 'compile-time dual-mode', it
|
|
|
|
* implements both the traditional 2-level x86 page tables and the
|
|
|
|
* newer 3-level PAE-mode page tables.
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_X86_PAE
|
|
|
|
# include <asm/pgtable-3level-defs.h>
|
|
|
|
# define PMD_SIZE (1UL << PMD_SHIFT)
|
|
|
|
# define PMD_MASK (~(PMD_SIZE-1))
|
|
|
|
#else
|
|
|
|
# include <asm/pgtable-2level-defs.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
|
|
|
|
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
|
|
|
|
|
|
|
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
|
2005-04-20 03:29:23 +07:00
|
|
|
#define FIRST_USER_ADDRESS 0
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
|
|
|
|
#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
|
|
|
|
|
|
|
|
#define TWOLEVEL_PGDIR_SHIFT 22
|
|
|
|
#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
|
|
|
|
#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
|
|
|
|
|
|
|
|
/* Just any arbitrary offset to the start of the vmalloc VM area: the
|
|
|
|
* current 8MB value just means that there will be a 8MB "hole" after the
|
|
|
|
* physical memory until the kernel virtual memory starts. That means that
|
|
|
|
* any out-of-bounds memory accesses will hopefully be caught.
|
|
|
|
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
|
|
|
|
* area for the same reason. ;)
|
|
|
|
*/
|
|
|
|
#define VMALLOC_OFFSET (8*1024*1024)
|
2007-07-16 13:38:19 +07:00
|
|
|
#define VMALLOC_START (((unsigned long) high_memory + \
|
2005-04-17 05:20:36 +07:00
|
|
|
2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1))
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
|
|
# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
|
|
|
|
#else
|
|
|
|
# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
2005-09-04 05:54:57 +07:00
|
|
|
* _PAGE_PSE set in the page directory entry just means that
|
2005-04-17 05:20:36 +07:00
|
|
|
* the page directory entry points directly to a 4MB-aligned block of
|
|
|
|
* memory.
|
|
|
|
*/
|
|
|
|
#define _PAGE_BIT_PRESENT 0
|
|
|
|
#define _PAGE_BIT_RW 1
|
|
|
|
#define _PAGE_BIT_USER 2
|
|
|
|
#define _PAGE_BIT_PWT 3
|
|
|
|
#define _PAGE_BIT_PCD 4
|
|
|
|
#define _PAGE_BIT_ACCESSED 5
|
|
|
|
#define _PAGE_BIT_DIRTY 6
|
|
|
|
#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page, Pentium+, if present.. */
|
|
|
|
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
|
|
|
|
#define _PAGE_BIT_UNUSED1 9 /* available for programmer */
|
|
|
|
#define _PAGE_BIT_UNUSED2 10
|
|
|
|
#define _PAGE_BIT_UNUSED3 11
|
|
|
|
#define _PAGE_BIT_NX 63
|
|
|
|
|
|
|
|
#define _PAGE_PRESENT 0x001
|
|
|
|
#define _PAGE_RW 0x002
|
|
|
|
#define _PAGE_USER 0x004
|
|
|
|
#define _PAGE_PWT 0x008
|
|
|
|
#define _PAGE_PCD 0x010
|
|
|
|
#define _PAGE_ACCESSED 0x020
|
|
|
|
#define _PAGE_DIRTY 0x040
|
|
|
|
#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */
|
|
|
|
#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */
|
|
|
|
#define _PAGE_UNUSED1 0x200 /* available for programmer */
|
|
|
|
#define _PAGE_UNUSED2 0x400
|
|
|
|
#define _PAGE_UNUSED3 0x800
|
|
|
|
|
2005-09-04 05:54:57 +07:00
|
|
|
/* If _PAGE_PRESENT is clear, we use these: */
|
|
|
|
#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */
|
|
|
|
#define _PAGE_PROTNONE 0x080 /* if the user mapped it with PROT_NONE;
|
|
|
|
pte_present gives true */
|
2005-04-17 05:20:36 +07:00
|
|
|
#ifdef CONFIG_X86_PAE
|
|
|
|
#define _PAGE_NX (1ULL<<_PAGE_BIT_NX)
|
|
|
|
#else
|
|
|
|
#define _PAGE_NX 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
|
|
|
|
#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
|
|
|
|
#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
|
|
|
|
|
|
|
|
#define PAGE_NONE \
|
|
|
|
__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
|
|
|
|
#define PAGE_SHARED \
|
|
|
|
__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
|
|
|
|
|
|
|
|
#define PAGE_SHARED_EXEC \
|
|
|
|
__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
|
|
|
|
#define PAGE_COPY_NOEXEC \
|
|
|
|
__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
|
|
|
|
#define PAGE_COPY_EXEC \
|
|
|
|
__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
|
|
|
|
#define PAGE_COPY \
|
|
|
|
PAGE_COPY_NOEXEC
|
|
|
|
#define PAGE_READONLY \
|
|
|
|
__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
|
|
|
|
#define PAGE_READONLY_EXEC \
|
|
|
|
__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
|
|
|
|
|
|
|
|
#define _PAGE_KERNEL \
|
|
|
|
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
|
|
|
|
#define _PAGE_KERNEL_EXEC \
|
|
|
|
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
|
|
|
|
|
|
|
|
extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
|
|
|
|
#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
|
2007-05-03 00:27:10 +07:00
|
|
|
#define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
|
2005-04-17 05:20:36 +07:00
|
|
|
#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD)
|
|
|
|
#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
|
|
|
|
#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE)
|
|
|
|
|
|
|
|
#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)
|
|
|
|
#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
|
|
|
|
#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
|
2007-05-03 00:27:10 +07:00
|
|
|
#define PAGE_KERNEL_RX __pgprot(__PAGE_KERNEL_RX)
|
2005-04-17 05:20:36 +07:00
|
|
|
#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)
|
|
|
|
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
|
|
|
|
#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The i386 can't do page protection for execute, and considers that
|
|
|
|
* the same are read. Also, write permissions imply read permissions.
|
|
|
|
* This is the closest we can get..
|
|
|
|
*/
|
|
|
|
#define __P000 PAGE_NONE
|
|
|
|
#define __P001 PAGE_READONLY
|
|
|
|
#define __P010 PAGE_COPY
|
|
|
|
#define __P011 PAGE_COPY
|
|
|
|
#define __P100 PAGE_READONLY_EXEC
|
|
|
|
#define __P101 PAGE_READONLY_EXEC
|
|
|
|
#define __P110 PAGE_COPY_EXEC
|
|
|
|
#define __P111 PAGE_COPY_EXEC
|
|
|
|
|
|
|
|
#define __S000 PAGE_NONE
|
|
|
|
#define __S001 PAGE_READONLY
|
|
|
|
#define __S010 PAGE_SHARED
|
|
|
|
#define __S011 PAGE_SHARED
|
|
|
|
#define __S100 PAGE_READONLY_EXEC
|
|
|
|
#define __S101 PAGE_READONLY_EXEC
|
|
|
|
#define __S110 PAGE_SHARED_EXEC
|
|
|
|
#define __S111 PAGE_SHARED_EXEC
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Define this if things work differently on an i386 and an i486:
|
|
|
|
* it will (on an i486) warn about kernel memory accesses that are
|
2005-05-01 22:59:08 +07:00
|
|
|
* done without a 'access_ok(VERIFY_WRITE,..)'
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
2005-05-01 22:59:08 +07:00
|
|
|
#undef TEST_ACCESS_OK
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* The boot page tables (all created as a single array) */
|
|
|
|
extern unsigned long pg0[];
|
|
|
|
|
|
|
|
#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
|
|
|
|
|
2005-10-30 08:16:27 +07:00
|
|
|
/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */
|
|
|
|
#define pmd_none(x) (!(unsigned long)pmd_val(x))
|
2005-04-17 05:20:36 +07:00
|
|
|
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
|
|
|
|
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
|
|
|
|
|
|
|
|
|
|
|
|
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The following only work if pte_present() is true.
|
|
|
|
* Undefined behaviour if not..
|
|
|
|
*/
|
|
|
|
static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
|
|
|
|
static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; }
|
|
|
|
static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; }
|
2006-03-22 15:08:50 +07:00
|
|
|
static inline int pte_huge(pte_t pte) { return (pte).pte_low & _PAGE_PSE; }
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The following only works if pte_present() is not true.
|
|
|
|
*/
|
|
|
|
static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; }
|
|
|
|
|
|
|
|
static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
|
|
|
|
static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
|
|
|
|
static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; }
|
|
|
|
static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
|
|
|
|
static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
|
|
|
|
static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
|
2006-03-22 15:08:50 +07:00
|
|
|
static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return pte; }
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#ifdef CONFIG_X86_PAE
|
|
|
|
# include <asm/pgtable-3level.h>
|
|
|
|
#else
|
|
|
|
# include <asm/pgtable-2level.h>
|
|
|
|
#endif
|
|
|
|
|
2006-12-07 08:14:08 +07:00
|
|
|
#ifndef CONFIG_PARAVIRT
|
2006-10-01 13:29:38 +07:00
|
|
|
/*
|
|
|
|
* Rules for using pte_update - it must be called after any PTE update which
|
|
|
|
* has not been done using the set_pte / clear_pte interfaces. It is used by
|
|
|
|
* shadow mode hypervisors to resynchronize the shadow page tables. Kernel PTE
|
|
|
|
* updates should either be sets, clears, or set_pte_atomic for P->P
|
|
|
|
* transitions, which means this hook should only be called for user PTEs.
|
|
|
|
* This hook implies a P->P protection or access change has taken place, which
|
|
|
|
* requires a subsequent TLB flush. The notification can optionally be delayed
|
|
|
|
* until the TLB flush event by using the pte_update_defer form of the
|
|
|
|
* interface, but care must be taken to assure that the flush happens while
|
|
|
|
* still holding the same page table lock so that the shadow and primary pages
|
|
|
|
* do not become out of sync on SMP.
|
|
|
|
*/
|
|
|
|
#define pte_update(mm, addr, ptep) do { } while (0)
|
|
|
|
#define pte_update_defer(mm, addr, ptep) do { } while (0)
|
2006-12-07 08:14:08 +07:00
|
|
|
#endif
|
2006-10-01 13:29:38 +07:00
|
|
|
|
2007-05-03 00:27:19 +07:00
|
|
|
/* local pte updates need not use xchg for locking */
|
|
|
|
static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
|
|
|
|
{
|
|
|
|
pte_t res = *ptep;
|
|
|
|
|
|
|
|
/* Pure native function needs no input for mm, addr */
|
|
|
|
native_pte_clear(NULL, 0, ptep);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2006-09-26 13:32:31 +07:00
|
|
|
/*
|
|
|
|
* We only update the dirty/accessed state if we set
|
|
|
|
* the dirty bit by hand in the kernel, since the hardware
|
|
|
|
* will do the accessed bit for us, and we don't want to
|
|
|
|
* race with other CPU's that might be updating the dirty
|
|
|
|
* bit at the same time.
|
|
|
|
*/
|
|
|
|
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
|
|
|
|
#define ptep_set_access_flags(vma, address, ptep, entry, dirty) \
|
2007-06-17 00:16:12 +07:00
|
|
|
({ \
|
|
|
|
int __changed = !pte_same(*(ptep), entry); \
|
|
|
|
if (__changed && dirty) { \
|
2006-09-26 13:32:31 +07:00
|
|
|
(ptep)->pte_low = (entry).pte_low; \
|
2006-12-07 08:14:08 +07:00
|
|
|
pte_update_defer((vma)->vm_mm, (address), (ptep)); \
|
2006-09-26 13:32:31 +07:00
|
|
|
flush_tlb_page(vma, address); \
|
|
|
|
} \
|
2007-06-17 00:16:12 +07:00
|
|
|
__changed; \
|
|
|
|
})
|
2006-09-26 13:32:31 +07:00
|
|
|
|
2006-09-26 13:32:30 +07:00
|
|
|
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
|
2007-05-07 04:49:20 +07:00
|
|
|
#define ptep_test_and_clear_young(vma, addr, ptep) ({ \
|
2007-06-17 00:15:59 +07:00
|
|
|
int __ret = 0; \
|
|
|
|
if (pte_young(*(ptep))) \
|
|
|
|
__ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, \
|
|
|
|
&(ptep)->pte_low); \
|
|
|
|
if (__ret) \
|
|
|
|
pte_update((vma)->vm_mm, addr, ptep); \
|
|
|
|
__ret; \
|
2007-05-07 04:49:20 +07:00
|
|
|
})
|
[PATCH] paravirt: combine flush accessed dirty.patch
Remove ptep_test_and_clear_{dirty|young} from i386, and instead use the
dominating functions, ptep_clear_flush_{dirty|young}. This allows the TLB
page flush to be contained in the same macro, and allows for an eager
optimization - if reading the PTE initially returned dirty/accessed, we can
assume the fact that no subsequent update to the PTE which cleared accessed /
dirty has occurred, as the only way A/D bits can change without holding the
page table lock is if a remote processor clears them. This eliminates an
extra branch which came from the generic version of the code, as we know that
no other CPU could have cleared the A/D bit, so the flush will always be
needed.
We still export these two defines, even though we do not actually define
the macros in the i386 code:
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
The reason for this is that the only use of these functions is within the
generic clear_flush functions, and we want a strong guarantee that there
are no other users of these functions, so we want to prevent the generic
code from defining them for us.
Signed-off-by: Zachary Amsden <zach@vmware.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-10-01 13:29:34 +07:00
|
|
|
|
|
|
|
#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
|
|
|
|
#define ptep_clear_flush_young(vma, address, ptep) \
|
|
|
|
({ \
|
|
|
|
int __young; \
|
2007-05-07 04:49:19 +07:00
|
|
|
__young = ptep_test_and_clear_young((vma), (address), (ptep)); \
|
2007-05-07 04:49:20 +07:00
|
|
|
if (__young) \
|
[PATCH] paravirt: combine flush accessed dirty.patch
Remove ptep_test_and_clear_{dirty|young} from i386, and instead use the
dominating functions, ptep_clear_flush_{dirty|young}. This allows the TLB
page flush to be contained in the same macro, and allows for an eager
optimization - if reading the PTE initially returned dirty/accessed, we can
assume the fact that no subsequent update to the PTE which cleared accessed /
dirty has occurred, as the only way A/D bits can change without holding the
page table lock is if a remote processor clears them. This eliminates an
extra branch which came from the generic version of the code, as we know that
no other CPU could have cleared the A/D bit, so the flush will always be
needed.
We still export these two defines, even though we do not actually define
the macros in the i386 code:
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
The reason for this is that the only use of these functions is within the
generic clear_flush functions, and we want a strong guarantee that there
are no other users of these functions, so we want to prevent the generic
code from defining them for us.
Signed-off-by: Zachary Amsden <zach@vmware.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-10-01 13:29:34 +07:00
|
|
|
flush_tlb_page(vma, address); \
|
|
|
|
__young; \
|
|
|
|
})
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-12-07 08:14:09 +07:00
|
|
|
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
|
|
|
|
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
2007-05-03 00:27:15 +07:00
|
|
|
pte_t pte = native_ptep_get_and_clear(ptep);
|
2006-12-07 08:14:09 +07:00
|
|
|
pte_update(mm, addr, ptep);
|
|
|
|
return pte;
|
|
|
|
}
|
|
|
|
|
2006-09-26 13:32:30 +07:00
|
|
|
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
|
[PATCH] x86: ptep_clear optimization
Add a new accessor for PTEs, which passes the full hint from the mmu_gather
struct; this allows architectures with hardware pagetables to optimize away
atomic PTE operations when destroying an address space. Removing the
locked operation should allow better pipelining of memory access in this
loop. I measured an average savings of 30-35 cycles per zap_pte_range on
the first 500 destructions on Pentium-M, but I believe the optimization
would win more on older processors which still assert the bus lock on xchg
for an exclusive cacheline.
Update: I made some new measurements, and this saves exactly 26 cycles over
ptep_get_and_clear on Pentium M. On P4, with a PAE kernel, this saves 180
cycles per ptep_get_and_clear, for a whopping 92160 cycles savings for a
full address space destruction.
pte_clear_full is not yet used, but is provided for future optimizations
(in particular, when running inside of a hypervisor that queues page table
updates, the full hint allows us to avoid queueing unnecessary page table
update for an address space in the process of being destroyed.
This is not a huge win, but it does help a bit, and sets the stage for
further hypervisor optimization of the mm layer on all architectures.
Signed-off-by: Zachary Amsden <zach@vmware.com>
Cc: Christoph Lameter <christoph@lameter.com>
Cc: <linux-mm@kvack.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-04 05:55:04 +07:00
|
|
|
static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
|
|
|
|
{
|
|
|
|
pte_t pte;
|
|
|
|
if (full) {
|
2007-05-03 00:27:19 +07:00
|
|
|
/*
|
|
|
|
* Full address destruction in progress; paravirt does not
|
|
|
|
* care about updates and native needs no locking
|
|
|
|
*/
|
|
|
|
pte = native_local_ptep_get_and_clear(ptep);
|
[PATCH] x86: ptep_clear optimization
Add a new accessor for PTEs, which passes the full hint from the mmu_gather
struct; this allows architectures with hardware pagetables to optimize away
atomic PTE operations when destroying an address space. Removing the
locked operation should allow better pipelining of memory access in this
loop. I measured an average savings of 30-35 cycles per zap_pte_range on
the first 500 destructions on Pentium-M, but I believe the optimization
would win more on older processors which still assert the bus lock on xchg
for an exclusive cacheline.
Update: I made some new measurements, and this saves exactly 26 cycles over
ptep_get_and_clear on Pentium M. On P4, with a PAE kernel, this saves 180
cycles per ptep_get_and_clear, for a whopping 92160 cycles savings for a
full address space destruction.
pte_clear_full is not yet used, but is provided for future optimizations
(in particular, when running inside of a hypervisor that queues page table
updates, the full hint allows us to avoid queueing unnecessary page table
update for an address space in the process of being destroyed.
This is not a huge win, but it does help a bit, and sets the stage for
further hypervisor optimization of the mm layer on all architectures.
Signed-off-by: Zachary Amsden <zach@vmware.com>
Cc: Christoph Lameter <christoph@lameter.com>
Cc: <linux-mm@kvack.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-04 05:55:04 +07:00
|
|
|
} else {
|
|
|
|
pte = ptep_get_and_clear(mm, addr, ptep);
|
|
|
|
}
|
|
|
|
return pte;
|
|
|
|
}
|
|
|
|
|
2006-09-26 13:32:30 +07:00
|
|
|
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
2005-04-17 05:20:36 +07:00
|
|
|
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
|
|
|
clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
|
2006-10-01 13:29:38 +07:00
|
|
|
pte_update(mm, addr, ptep);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2005-09-04 05:56:50 +07:00
|
|
|
/*
|
|
|
|
* clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
|
|
|
|
*
|
|
|
|
* dst - pointer to pgd range anwhere on a pgd page
|
|
|
|
* src - ""
|
|
|
|
* count - the number of pgds to copy.
|
|
|
|
*
|
|
|
|
* dst and src can be on the same page, but the range must not overlap,
|
|
|
|
* and must not cross a page boundary.
|
|
|
|
*/
|
|
|
|
static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
|
|
|
|
{
|
|
|
|
memcpy(dst, src, count * sizeof(pgd_t));
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* Macro to mark a page protection value as "uncacheable". On processors which do not support
|
|
|
|
* it, this is a no-op.
|
|
|
|
*/
|
|
|
|
#define pgprot_noncached(prot) ((boot_cpu_data.x86 > 3) \
|
|
|
|
? (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) : (prot))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Conversion functions: convert a page and protection to a page entry,
|
|
|
|
* and a page entry and page directory to the page they refer to.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
|
|
|
|
|
|
|
|
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
|
|
|
|
{
|
|
|
|
pte.pte_low &= _PAGE_CHG_MASK;
|
|
|
|
pte.pte_low |= pgprot_val(newprot);
|
|
|
|
#ifdef CONFIG_X86_PAE
|
|
|
|
/*
|
|
|
|
* Chop off the NX bit (if present), and add the NX portion of
|
|
|
|
* the newprot (if present):
|
|
|
|
*/
|
|
|
|
pte.pte_high &= ~(1 << (_PAGE_BIT_NX - 32));
|
|
|
|
pte.pte_high |= (pgprot_val(newprot) >> 32) & \
|
|
|
|
(__supported_pte_mask >> 32);
|
|
|
|
#endif
|
|
|
|
return pte;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define pmd_large(pmd) \
|
|
|
|
((pmd_val(pmd) & (_PAGE_PSE|_PAGE_PRESENT)) == (_PAGE_PSE|_PAGE_PRESENT))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
|
|
|
|
*
|
|
|
|
* this macro returns the index of the entry in the pgd page which would
|
|
|
|
* control the given virtual address
|
|
|
|
*/
|
|
|
|
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
|
|
|
|
#define pgd_index_k(addr) pgd_index(addr)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pgd_offset() returns a (pgd_t *)
|
|
|
|
* pgd_index() is used get the offset into the pgd page's array of pgd_t's;
|
|
|
|
*/
|
|
|
|
#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* a shortcut which implies the use of the kernel's pgd, instead
|
|
|
|
* of a process's
|
|
|
|
*/
|
|
|
|
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
|
|
|
|
*
|
|
|
|
* this macro returns the index of the entry in the pmd page which would
|
|
|
|
* control the given virtual address
|
|
|
|
*/
|
|
|
|
#define pmd_index(address) \
|
|
|
|
(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
|
|
|
|
*
|
|
|
|
* this macro returns the index of the entry in the pte page which would
|
|
|
|
* control the given virtual address
|
|
|
|
*/
|
|
|
|
#define pte_index(address) \
|
|
|
|
(((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
|
|
|
|
#define pte_offset_kernel(dir, address) \
|
2006-09-26 13:31:48 +07:00
|
|
|
((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2005-10-31 05:59:31 +07:00
|
|
|
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
|
|
|
|
|
2006-09-26 13:31:48 +07:00
|
|
|
#define pmd_page_vaddr(pmd) \
|
2005-10-31 05:59:31 +07:00
|
|
|
((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* Helper function that returns the kernel pagetable entry controlling
|
|
|
|
* the virtual address 'address'. NULL means no pagetable entry present.
|
|
|
|
* NOTE: the return type is pte_t but if the pmd is PSE then we return it
|
|
|
|
* as a pte too.
|
|
|
|
*/
|
|
|
|
extern pte_t *lookup_address(unsigned long address);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a given kernel text page executable/non-executable.
|
|
|
|
* Returns the previous executability setting of that page (which
|
|
|
|
* is used to restore the previous state). Used by the SMP bootup code.
|
|
|
|
* NOTE: this is an __init function for security reasons.
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_X86_PAE
|
|
|
|
extern int set_kernel_exec(unsigned long vaddr, int enable);
|
|
|
|
#else
|
|
|
|
static inline int set_kernel_exec(unsigned long vaddr, int enable) { return 0;}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_HIGHPTE)
|
2007-05-03 00:27:15 +07:00
|
|
|
#define pte_offset_map(dir, address) \
|
2007-05-03 00:27:15 +07:00
|
|
|
((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
|
2007-05-03 00:27:15 +07:00
|
|
|
#define pte_offset_map_nested(dir, address) \
|
2007-05-03 00:27:15 +07:00
|
|
|
((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
|
2005-04-17 05:20:36 +07:00
|
|
|
#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
|
|
|
|
#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
|
|
|
|
#else
|
|
|
|
#define pte_offset_map(dir, address) \
|
|
|
|
((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
|
|
|
|
#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
|
|
|
|
#define pte_unmap(pte) do { } while (0)
|
|
|
|
#define pte_unmap_nested(pte) do { } while (0)
|
|
|
|
#endif
|
|
|
|
|
2006-10-01 13:29:35 +07:00
|
|
|
/* Clear a kernel PTE and flush it from the TLB */
|
|
|
|
#define kpte_clear_flush(ptep, vaddr) \
|
|
|
|
do { \
|
|
|
|
pte_clear(&init_mm, vaddr, ptep); \
|
|
|
|
__flush_tlb_one(vaddr); \
|
|
|
|
} while (0)
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* The i386 doesn't have any external MMU info: the kernel page
|
|
|
|
* tables contain all the necessary information.
|
|
|
|
*/
|
|
|
|
#define update_mmu_cache(vma,address,pte) do { } while (0)
|
[PATCH] i386: PARAVIRT: Hooks to set up initial pagetable
This patch introduces paravirt_ops hooks to control how the kernel's
initial pagetable is set up.
In the case of a native boot, the very early bootstrap code creates a
simple non-PAE pagetable to map the kernel and physical memory. When
the VM subsystem is initialized, it creates a proper pagetable which
respects the PAE mode, large pages, etc.
When booting under a hypervisor, there are many possibilities for what
paging environment the hypervisor establishes for the guest kernel, so
the constructon of the kernel's pagetable depends on the hypervisor.
In the case of Xen, the hypervisor boots the kernel with a fully
constructed pagetable, which is already using PAE if necessary. Also,
Xen requires particular care when constructing pagetables to make sure
all pagetables are always mapped read-only.
In order to make this easier, kernel's initial pagetable construction
has been changed to only allocate and initialize a pagetable page if
there's no page already present in the pagetable. This allows the Xen
paravirt backend to make a copy of the hypervisor-provided pagetable,
allowing the kernel to establish any more mappings it needs while
keeping the existing ones.
A slightly subtle point which is worth highlighting here is that Xen
requires all kernel mappings to share the same pte_t pages between all
pagetables, so that updating a kernel page's mapping in one pagetable
is reflected in all other pagetables. This makes it possible to
allocate a page and attach it to a pagetable without having to
explicitly enumerate that page's mapping in all pagetables.
And:
+From: "Eric W. Biederman" <ebiederm@xmission.com>
If we don't set the leaf page table entries it is quite possible that
will inherit and incorrect page table entry from the initial boot
page table setup in head.S. So we need to redo the effort here,
so we pick up PSE, PGE and the like.
Hypervisors like Xen require that their page tables be read-only,
which is slightly incompatible with our low identity mappings, however
I discussed this with Jeremy he has modified the Xen early set_pte
function to avoid problems in this area.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Acked-by: William Irwin <bill.irwin@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
2007-05-03 00:27:13 +07:00
|
|
|
|
|
|
|
void native_pagetable_setup_start(pgd_t *base);
|
|
|
|
void native_pagetable_setup_done(pgd_t *base);
|
|
|
|
|
|
|
|
#ifndef CONFIG_PARAVIRT
|
|
|
|
static inline void paravirt_pagetable_setup_start(pgd_t *base)
|
|
|
|
{
|
|
|
|
native_pagetable_setup_start(base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void paravirt_pagetable_setup_done(pgd_t *base)
|
|
|
|
{
|
|
|
|
native_pagetable_setup_done(base);
|
|
|
|
}
|
|
|
|
#endif /* !CONFIG_PARAVIRT */
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
|
2005-06-23 14:07:57 +07:00
|
|
|
#ifdef CONFIG_FLATMEM
|
2005-04-17 05:20:36 +07:00
|
|
|
#define kern_addr_valid(addr) (1)
|
2005-06-23 14:07:57 +07:00
|
|
|
#endif /* CONFIG_FLATMEM */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
|
|
|
|
remap_pfn_range(vma, vaddr, pfn, size, prot)
|
|
|
|
|
|
|
|
#include <asm-generic/pgtable.h>
|
|
|
|
|
|
|
|
#endif /* _I386_PGTABLE_H */
|