diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2007-05-02 13:27:15 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2007-05-02 13:27:15 -0400 |
commit | ce6234b5298902aaec831a67d5f8d9bd2ef5a488 (patch) | |
tree | 939c22684e11a4f5f17abb89c4898f016e878e21 /include | |
parent | a27fe809b82c5e18932fcceded28d0d1481ce7bb (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.h | 6 | ||||
-rw-r--r-- | include/asm-i386/paravirt.h | 15 | ||||
-rw-r--r-- | include/asm-i386/pgtable.h | 4 | ||||
-rw-r--r-- | include/linux/highmem.h | 6 |
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 @@ | |||
24 | #include <linux/threads.h> | 24 | #include <linux/threads.h> |
25 | #include <asm/kmap_types.h> | 25 | #include <asm/kmap_types.h> |
26 | #include <asm/tlbflush.h> | 26 | #include <asm/tlbflush.h> |
27 | #include <asm/paravirt.h> | ||
27 | 28 | ||
28 | /* declarations for highmem.c */ | 29 | /* declarations for highmem.c */ |
29 | extern unsigned long highstart_pfn, highend_pfn; | 30 | extern unsigned long highstart_pfn, highend_pfn; |
@@ -67,11 +68,16 @@ extern void FASTCALL(kunmap_high(struct page *page)); | |||
67 | 68 | ||
68 | void *kmap(struct page *page); | 69 | void *kmap(struct page *page); |
69 | void kunmap(struct page *page); | 70 | void kunmap(struct page *page); |
71 | void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot); | ||
70 | void *kmap_atomic(struct page *page, enum km_type type); | 72 | void *kmap_atomic(struct page *page, enum km_type type); |
71 | void kunmap_atomic(void *kvaddr, enum km_type type); | 73 | void kunmap_atomic(void *kvaddr, enum km_type type); |
72 | void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); | 74 | void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); |
73 | struct page *kmap_atomic_to_page(void *ptr); | 75 | struct page *kmap_atomic_to_page(void *ptr); |
74 | 76 | ||
77 | #ifndef CONFIG_PARAVIRT | ||
78 | #define kmap_atomic_pte(page, type) kmap_atomic(page, type) | ||
79 | #endif | ||
80 | |||
75 | #define flush_cache_kmaps() do { } while (0) | 81 | #define flush_cache_kmaps() do { } while (0) |
76 | 82 | ||
77 | #endif /* __KERNEL__ */ | 83 | #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 @@ | |||
16 | #ifndef __ASSEMBLY__ | 16 | #ifndef __ASSEMBLY__ |
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <linux/cpumask.h> | 18 | #include <linux/cpumask.h> |
19 | #include <asm/kmap_types.h> | ||
19 | 20 | ||
21 | struct page; | ||
20 | struct thread_struct; | 22 | struct thread_struct; |
21 | struct Xgt_desc_struct; | 23 | struct Xgt_desc_struct; |
22 | struct tss_struct; | 24 | struct tss_struct; |
@@ -187,6 +189,10 @@ struct paravirt_ops | |||
187 | 189 | ||
188 | pte_t (*ptep_get_and_clear)(pte_t *ptep); | 190 | pte_t (*ptep_get_and_clear)(pte_t *ptep); |
189 | 191 | ||
192 | #ifdef CONFIG_HIGHPTE | ||
193 | void *(*kmap_atomic_pte)(struct page *page, enum km_type type); | ||
194 | #endif | ||
195 | |||
190 | #ifdef CONFIG_X86_PAE | 196 | #ifdef CONFIG_X86_PAE |
191 | void (*set_pte_atomic)(pte_t *ptep, pte_t pteval); | 197 | void (*set_pte_atomic)(pte_t *ptep, pte_t pteval); |
192 | void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); | 198 | 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) | |||
884 | PVOP_VCALL1(release_pd, pfn); | 890 | PVOP_VCALL1(release_pd, pfn); |
885 | } | 891 | } |
886 | 892 | ||
893 | #ifdef CONFIG_HIGHPTE | ||
894 | static inline void *kmap_atomic_pte(struct page *page, enum km_type type) | ||
895 | { | ||
896 | unsigned long ret; | ||
897 | ret = PVOP_CALL2(unsigned long, kmap_atomic_pte, page, type); | ||
898 | return (void *)ret; | ||
899 | } | ||
900 | #endif | ||
901 | |||
887 | static inline void pte_update(struct mm_struct *mm, unsigned long addr, | 902 | static inline void pte_update(struct mm_struct *mm, unsigned long addr, |
888 | pte_t *ptep) | 903 | pte_t *ptep) |
889 | { | 904 | { |
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); | |||
476 | 476 | ||
477 | #if defined(CONFIG_HIGHPTE) | 477 | #if defined(CONFIG_HIGHPTE) |
478 | #define pte_offset_map(dir, address) \ | 478 | #define pte_offset_map(dir, address) \ |
479 | ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address)) | 479 | ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + pte_index(address)) |
480 | #define pte_offset_map_nested(dir, address) \ | 480 | #define pte_offset_map_nested(dir, address) \ |
481 | ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + pte_index(address)) | 481 | ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + pte_index(address)) |
482 | #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) | 482 | #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) |
483 | #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) | 483 | #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) |
484 | #else | 484 | #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) | |||
27 | unsigned int nr_free_highpages(void); | 27 | unsigned int nr_free_highpages(void); |
28 | extern unsigned long totalhigh_pages; | 28 | extern unsigned long totalhigh_pages; |
29 | 29 | ||
30 | void kmap_flush_unused(void); | ||
31 | |||
30 | #else /* CONFIG_HIGHMEM */ | 32 | #else /* CONFIG_HIGHMEM */ |
31 | 33 | ||
32 | static inline unsigned int nr_free_highpages(void) { return 0; } | 34 | static inline unsigned int nr_free_highpages(void) { return 0; } |
@@ -44,9 +46,13 @@ static inline void *kmap(struct page *page) | |||
44 | 46 | ||
45 | #define kmap_atomic(page, idx) \ | 47 | #define kmap_atomic(page, idx) \ |
46 | ({ pagefault_disable(); page_address(page); }) | 48 | ({ pagefault_disable(); page_address(page); }) |
49 | #define kmap_atomic_prot(page, idx, prot) kmap_atomic(page, idx) | ||
50 | |||
47 | #define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0) | 51 | #define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0) |
48 | #define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx)) | 52 | #define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx)) |
49 | #define kmap_atomic_to_page(ptr) virt_to_page(ptr) | 53 | #define kmap_atomic_to_page(ptr) virt_to_page(ptr) |
54 | |||
55 | #define kmap_flush_unused() do {} while(0) | ||
50 | #endif | 56 | #endif |
51 | 57 | ||
52 | #endif /* CONFIG_HIGHMEM */ | 58 | #endif /* CONFIG_HIGHMEM */ |