summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2007-05-02 19:27:15 +0200
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 19:27:15 +0200
commitce6234b5298902aaec831a67d5f8d9bd2ef5a488 (patch)
tree939c22684e11a4f5f17abb89c4898f016e878e21 /include
parenta27fe809b82c5e18932fcceded28d0d1481ce7bb (diff)
[PATCH] i386: PARAVIRT: add kmap_atomic_pte for mapping highpte pages
Xen and VMI both have special requirements when mapping a highmem pte page into the kernel address space. These can be dealt with by adding a new kmap_atomic_pte() function for mapping highptes, and hooking it into the paravirt_ops infrastructure. Xen specifically wants to map the pte page RO, so this patch exposes a helper function, kmap_atomic_prot, which maps the page with the specified page protections. This also adds a kmap_flush_unused() function to clear out the cached kmap mappings. Xen needs this to clear out any potential stray RW mappings of pages which will become part of a pagetable. [ Zach - vmi.c will need some attention after this patch. It wasn't immediately obvious to me what needs to be done. ] Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Zachary Amsden <zach@vmware.com>
Diffstat (limited to 'include')
-rw-r--r--include/asm-i386/highmem.h6
-rw-r--r--include/asm-i386/paravirt.h15
-rw-r--r--include/asm-i386/pgtable.h4
-rw-r--r--include/linux/highmem.h6
4 files changed, 29 insertions, 2 deletions
diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
index e9a34ebc25d5..13cdcd66fff2 100644
--- a/include/asm-i386/highmem.h
+++ b/include/asm-i386/highmem.h
@@ -24,6 +24,7 @@
#include <linux/threads.h>
#include <asm/kmap_types.h>
#include <asm/tlbflush.h>
+#include <asm/paravirt.h>
/* declarations for highmem.c */
extern unsigned long highstart_pfn, highend_pfn;
@@ -67,11 +68,16 @@ extern void FASTCALL(kunmap_high(struct page *page));
void *kmap(struct page *page);
void kunmap(struct page *page);
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *kvaddr, enum km_type type);
void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
struct page *kmap_atomic_to_page(void *ptr);
+#ifndef CONFIG_PARAVIRT
+#define kmap_atomic_pte(page, type) kmap_atomic(page, type)
+#endif
+
#define flush_cache_kmaps() do { } while (0)
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index 10f44af76b49..5048b41428fa 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -16,7 +16,9 @@
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/cpumask.h>
+#include <asm/kmap_types.h>
+struct page;
struct thread_struct;
struct Xgt_desc_struct;
struct tss_struct;
@@ -187,6 +189,10 @@ struct paravirt_ops
pte_t (*ptep_get_and_clear)(pte_t *ptep);
+#ifdef CONFIG_HIGHPTE
+ void *(*kmap_atomic_pte)(struct page *page, enum km_type type);
+#endif
+
#ifdef CONFIG_X86_PAE
void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte);
@@ -884,6 +890,15 @@ static inline void paravirt_release_pd(unsigned pfn)
PVOP_VCALL1(release_pd, pfn);
}
+#ifdef CONFIG_HIGHPTE
+static inline void *kmap_atomic_pte(struct page *page, enum km_type type)
+{
+ unsigned long ret;
+ ret = PVOP_CALL2(unsigned long, kmap_atomic_pte, page, type);
+ return (void *)ret;
+}
+#endif
+
static inline void pte_update(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index 6599f2aa91b7..befc697821e5 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -476,9 +476,9 @@ extern pte_t *lookup_address(unsigned long address);
#if defined(CONFIG_HIGHPTE)
#define pte_offset_map(dir, address) \
- ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
+ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
#define pte_offset_map_nested(dir, address) \
- ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
+ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
#else
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 645d440807c2..bca8e2dfa355 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -27,6 +27,8 @@ static inline void flush_kernel_dcache_page(struct page *page)
unsigned int nr_free_highpages(void);
extern unsigned long totalhigh_pages;
+void kmap_flush_unused(void);
+
#else /* CONFIG_HIGHMEM */
static inline unsigned int nr_free_highpages(void) { return 0; }
@@ -44,9 +46,13 @@ static inline void *kmap(struct page *page)
#define kmap_atomic(page, idx) \
({ pagefault_disable(); page_address(page); })
+#define kmap_atomic_prot(page, idx, prot) kmap_atomic(page, idx)
+
#define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0)
#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx))
#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
+
+#define kmap_flush_unused() do {} while(0)
#endif
#endif /* CONFIG_HIGHMEM */