aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/paravirt.c2
-rw-r--r--arch/x86/mm/init_64.c21
-rw-r--r--arch/x86/mm/pgtable.c20
-rw-r--r--arch/x86/mm/pgtable_32.c20
-rw-r--r--arch/x86/xen/enlighten.c29
-rw-r--r--include/asm-x86/fixmap.h55
-rw-r--r--include/asm-x86/fixmap_32.h42
-rw-r--r--include/asm-x86/fixmap_64.h37
-rw-r--r--include/asm-x86/paravirt.h13
-rw-r--r--include/asm-x86/pgtable.h3
10 files changed, 130 insertions, 112 deletions
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 74f0c5ea2a03..cf06670349dc 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -416,6 +416,8 @@ struct pv_mmu_ops pv_mmu_ops = {
416 .enter = paravirt_nop, 416 .enter = paravirt_nop,
417 .leave = paravirt_nop, 417 .leave = paravirt_nop,
418 }, 418 },
419
420 .set_fixmap = native_set_fixmap,
419}; 421};
420 422
421EXPORT_SYMBOL_GPL(pv_time_ops); 423EXPORT_SYMBOL_GPL(pv_time_ops);
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 156e6d7b0e32..74fae8335128 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -135,15 +135,15 @@ static __init void *spp_getpage(void)
135 return ptr; 135 return ptr;
136} 136}
137 137
138static void 138void
139set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot) 139set_pte_vaddr(unsigned long vaddr, pte_t new_pte)
140{ 140{
141 pgd_t *pgd; 141 pgd_t *pgd;
142 pud_t *pud; 142 pud_t *pud;
143 pmd_t *pmd; 143 pmd_t *pmd;
144 pte_t *pte, new_pte; 144 pte_t *pte;
145 145
146 pr_debug("set_pte_phys %lx to %lx\n", vaddr, phys); 146 pr_debug("set_pte_vaddr %lx to %lx\n", vaddr, native_pte_val(new_pte));
147 147
148 pgd = pgd_offset_k(vaddr); 148 pgd = pgd_offset_k(vaddr);
149 if (pgd_none(*pgd)) { 149 if (pgd_none(*pgd)) {
@@ -170,7 +170,6 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
170 return; 170 return;
171 } 171 }
172 } 172 }
173 new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
174 173
175 pte = pte_offset_kernel(pmd, vaddr); 174 pte = pte_offset_kernel(pmd, vaddr);
176 if (!pte_none(*pte) && pte_val(new_pte) && 175 if (!pte_none(*pte) && pte_val(new_pte) &&
@@ -213,18 +212,6 @@ void __init cleanup_highmap(void)
213 } 212 }
214} 213}
215 214
216/* NOTE: this is meant to be run only at boot */
217void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
218{
219 unsigned long address = __fix_to_virt(idx);
220
221 if (idx >= __end_of_fixed_addresses) {
222 printk(KERN_ERR "Invalid __set_fixmap\n");
223 return;
224 }
225 set_pte_phys(address, phys, prot);
226}
227
228static unsigned long __initdata table_start; 215static unsigned long __initdata table_start;
229static unsigned long __meminitdata table_end; 216static unsigned long __meminitdata table_end;
230 217
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 50159764f694..892fd1892b8d 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -2,6 +2,7 @@
2#include <asm/pgalloc.h> 2#include <asm/pgalloc.h>
3#include <asm/pgtable.h> 3#include <asm/pgtable.h>
4#include <asm/tlb.h> 4#include <asm/tlb.h>
5#include <asm/fixmap.h>
5 6
6pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) 7pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
7{ 8{
@@ -274,3 +275,22 @@ int ptep_clear_flush_young(struct vm_area_struct *vma,
274 275
275 return young; 276 return young;
276} 277}
278
279int fixmaps_set;
280
281void __native_set_fixmap(enum fixed_addresses idx, pte_t pte)
282{
283 unsigned long address = __fix_to_virt(idx);
284
285 if (idx >= __end_of_fixed_addresses) {
286 BUG();
287 return;
288 }
289 set_pte_vaddr(address, pte);
290 fixmaps_set++;
291}
292
293void native_set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
294{
295 __native_set_fixmap(idx, pfn_pte(phys >> PAGE_SHIFT, flags));
296}
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index 369cf065b6a4..0662f345212f 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -71,7 +71,7 @@ void show_mem(void)
71 * Associate a virtual page frame with a given physical page frame 71 * Associate a virtual page frame with a given physical page frame
72 * and protection flags for that frame. 72 * and protection flags for that frame.
73 */ 73 */
74static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) 74void set_pte_vaddr(unsigned long vaddr, pte_t pteval)
75{ 75{
76 pgd_t *pgd; 76 pgd_t *pgd;
77 pud_t *pud; 77 pud_t *pud;
@@ -94,8 +94,8 @@ static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
94 return; 94 return;
95 } 95 }
96 pte = pte_offset_kernel(pmd, vaddr); 96 pte = pte_offset_kernel(pmd, vaddr);
97 if (pgprot_val(flags)) 97 if (pte_val(pteval))
98 set_pte_present(&init_mm, vaddr, pte, pfn_pte(pfn, flags)); 98 set_pte_present(&init_mm, vaddr, pte, pteval);
99 else 99 else
100 pte_clear(&init_mm, vaddr, pte); 100 pte_clear(&init_mm, vaddr, pte);
101 101
@@ -145,18 +145,6 @@ static int fixmaps;
145unsigned long __FIXADDR_TOP = 0xfffff000; 145unsigned long __FIXADDR_TOP = 0xfffff000;
146EXPORT_SYMBOL(__FIXADDR_TOP); 146EXPORT_SYMBOL(__FIXADDR_TOP);
147 147
148void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
149{
150 unsigned long address = __fix_to_virt(idx);
151
152 if (idx >= __end_of_fixed_addresses) {
153 BUG();
154 return;
155 }
156 set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
157 fixmaps++;
158}
159
160/** 148/**
161 * reserve_top_address - reserves a hole in the top of kernel address space 149 * reserve_top_address - reserves a hole in the top of kernel address space
162 * @reserve - size of hole to reserve 150 * @reserve - size of hole to reserve
@@ -166,7 +154,7 @@ void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
166 */ 154 */
167void reserve_top_address(unsigned long reserve) 155void reserve_top_address(unsigned long reserve)
168{ 156{
169 BUG_ON(fixmaps > 0); 157 BUG_ON(fixmaps_set > 0);
170 printk(KERN_INFO "Reserving virtual address space above 0x%08x\n", 158 printk(KERN_INFO "Reserving virtual address space above 0x%08x\n",
171 (int)-reserve); 159 (int)-reserve);
172 __FIXADDR_TOP = -reserve - PAGE_SIZE; 160 __FIXADDR_TOP = -reserve - PAGE_SIZE;
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index f09c1c69c37a..2d19382e6555 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -947,6 +947,33 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
947 return ret; 947 return ret;
948} 948}
949 949
950static void xen_set_fixmap(unsigned idx, unsigned long phys, pgprot_t prot)
951{
952 pte_t pte;
953
954 phys >>= PAGE_SHIFT;
955
956 switch (idx) {
957 case FIX_BTMAP_END ... FIX_BTMAP_BEGIN:
958#ifdef CONFIG_X86_F00F_BUG
959 case FIX_F00F_IDT:
960#endif
961 case FIX_WP_TEST:
962 case FIX_VDSO:
963#ifdef CONFIG_X86_LOCAL_APIC
964 case FIX_APIC_BASE: /* maps dummy local APIC */
965#endif
966 pte = pfn_pte(phys, prot);
967 break;
968
969 default:
970 pte = mfn_pte(phys, prot);
971 break;
972 }
973
974 __native_set_fixmap(idx, pte);
975}
976
950static const struct pv_info xen_info __initdata = { 977static const struct pv_info xen_info __initdata = {
951 .paravirt_enabled = 1, 978 .paravirt_enabled = 1,
952 .shared_kernel_pmd = 0, 979 .shared_kernel_pmd = 0,
@@ -1097,6 +1124,8 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
1097 .enter = paravirt_enter_lazy_mmu, 1124 .enter = paravirt_enter_lazy_mmu,
1098 .leave = xen_leave_lazy, 1125 .leave = xen_leave_lazy,
1099 }, 1126 },
1127
1128 .set_fixmap = xen_set_fixmap,
1100}; 1129};
1101 1130
1102#ifdef CONFIG_SMP 1131#ifdef CONFIG_SMP
diff --git a/include/asm-x86/fixmap.h b/include/asm-x86/fixmap.h
index 5bd206973dca..44d4f8217349 100644
--- a/include/asm-x86/fixmap.h
+++ b/include/asm-x86/fixmap.h
@@ -7,7 +7,62 @@
7# include "fixmap_64.h" 7# include "fixmap_64.h"
8#endif 8#endif
9 9
10extern int fixmaps_set;
11
12void __native_set_fixmap(enum fixed_addresses idx, pte_t pte);
13void native_set_fixmap(enum fixed_addresses idx,
14 unsigned long phys, pgprot_t flags);
15
16#ifndef CONFIG_PARAVIRT
17static inline void __set_fixmap(enum fixed_addresses idx,
18 unsigned long phys, pgprot_t flags)
19{
20 native_set_fixmap(idx, phys, flags);
21}
22#endif
23
24#define set_fixmap(idx, phys) \
25 __set_fixmap(idx, phys, PAGE_KERNEL)
26
27/*
28 * Some hardware wants to get fixmapped without caching.
29 */
30#define set_fixmap_nocache(idx, phys) \
31 __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
32
10#define clear_fixmap(idx) \ 33#define clear_fixmap(idx) \
11 __set_fixmap(idx, 0, __pgprot(0)) 34 __set_fixmap(idx, 0, __pgprot(0))
12 35
36#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
37#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
38
39extern void __this_fixmap_does_not_exist(void);
40
41/*
42 * 'index to address' translation. If anyone tries to use the idx
43 * directly without translation, we catch the bug with a NULL-deference
44 * kernel oops. Illegal ranges of incoming indices are caught too.
45 */
46static __always_inline unsigned long fix_to_virt(const unsigned int idx)
47{
48 /*
49 * this branch gets completely eliminated after inlining,
50 * except when someone tries to use fixaddr indices in an
51 * illegal way. (such as mixing up address types or using
52 * out-of-range indices).
53 *
54 * If it doesn't get removed, the linker will complain
55 * loudly with a reasonably clear error message..
56 */
57 if (idx >= __end_of_fixed_addresses)
58 __this_fixmap_does_not_exist();
59
60 return __fix_to_virt(idx);
61}
62
63static inline unsigned long virt_to_fix(const unsigned long vaddr)
64{
65 BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
66 return __virt_to_fix(vaddr);
67}
13#endif 68#endif
diff --git a/include/asm-x86/fixmap_32.h b/include/asm-x86/fixmap_32.h
index 4b96148e90c1..3a94115952ff 100644
--- a/include/asm-x86/fixmap_32.h
+++ b/include/asm-x86/fixmap_32.h
@@ -109,17 +109,8 @@ enum fixed_addresses {
109 __end_of_fixed_addresses 109 __end_of_fixed_addresses
110}; 110};
111 111
112extern void __set_fixmap(enum fixed_addresses idx,
113 unsigned long phys, pgprot_t flags);
114extern void reserve_top_address(unsigned long reserve); 112extern void reserve_top_address(unsigned long reserve);
115 113
116#define set_fixmap(idx, phys) \
117 __set_fixmap(idx, phys, PAGE_KERNEL)
118/*
119 * Some hardware wants to get fixmapped without caching.
120 */
121#define set_fixmap_nocache(idx, phys) \
122 __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
123 114
124#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP) 115#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
125 116
@@ -128,38 +119,5 @@ extern void reserve_top_address(unsigned long reserve);
128#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) 119#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
129#define FIXADDR_BOOT_START (FIXADDR_TOP - __FIXADDR_BOOT_SIZE) 120#define FIXADDR_BOOT_START (FIXADDR_TOP - __FIXADDR_BOOT_SIZE)
130 121
131#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
132#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
133
134extern void __this_fixmap_does_not_exist(void);
135
136/*
137 * 'index to address' translation. If anyone tries to use the idx
138 * directly without tranlation, we catch the bug with a NULL-deference
139 * kernel oops. Illegal ranges of incoming indices are caught too.
140 */
141static __always_inline unsigned long fix_to_virt(const unsigned int idx)
142{
143 /*
144 * this branch gets completely eliminated after inlining,
145 * except when someone tries to use fixaddr indices in an
146 * illegal way. (such as mixing up address types or using
147 * out-of-range indices).
148 *
149 * If it doesn't get removed, the linker will complain
150 * loudly with a reasonably clear error message..
151 */
152 if (idx >= __end_of_fixed_addresses)
153 __this_fixmap_does_not_exist();
154
155 return __fix_to_virt(idx);
156}
157
158static inline unsigned long virt_to_fix(const unsigned long vaddr)
159{
160 BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
161 return __virt_to_fix(vaddr);
162}
163
164#endif /* !__ASSEMBLY__ */ 122#endif /* !__ASSEMBLY__ */
165#endif 123#endif
diff --git a/include/asm-x86/fixmap_64.h b/include/asm-x86/fixmap_64.h
index 355d26a75a82..626098823a0c 100644
--- a/include/asm-x86/fixmap_64.h
+++ b/include/asm-x86/fixmap_64.h
@@ -52,17 +52,6 @@ enum fixed_addresses {
52 __end_of_fixed_addresses 52 __end_of_fixed_addresses
53}; 53};
54 54
55extern void __set_fixmap(enum fixed_addresses idx,
56 unsigned long phys, pgprot_t flags);
57
58#define set_fixmap(idx, phys) \
59 __set_fixmap(idx, phys, PAGE_KERNEL)
60/*
61 * Some hardware wants to get fixmapped without caching.
62 */
63#define set_fixmap_nocache(idx, phys) \
64 __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
65
66#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE) 55#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE)
67#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) 56#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
68#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) 57#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
@@ -71,30 +60,4 @@ extern void __set_fixmap(enum fixed_addresses idx,
71#define FIXADDR_USER_START ((unsigned long)VSYSCALL32_VSYSCALL) 60#define FIXADDR_USER_START ((unsigned long)VSYSCALL32_VSYSCALL)
72#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE) 61#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
73 62
74#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
75
76extern void __this_fixmap_does_not_exist(void);
77
78/*
79 * 'index to address' translation. If anyone tries to use the idx
80 * directly without translation, we catch the bug with a NULL-deference
81 * kernel oops. Illegal ranges of incoming indices are caught too.
82 */
83static __always_inline unsigned long fix_to_virt(const unsigned int idx)
84{
85 /*
86 * this branch gets completely eliminated after inlining,
87 * except when someone tries to use fixaddr indices in an
88 * illegal way. (such as mixing up address types or using
89 * out-of-range indices).
90 *
91 * If it doesn't get removed, the linker will complain
92 * loudly with a reasonably clear error message..
93 */
94 if (idx >= __end_of_fixed_addresses)
95 __this_fixmap_does_not_exist();
96
97 return __fix_to_virt(idx);
98}
99
100#endif 63#endif
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index 0f13b945e240..af85caf9a799 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -273,6 +273,13 @@ struct pv_mmu_ops {
273#endif 273#endif
274 274
275 struct pv_lazy_ops lazy_mode; 275 struct pv_lazy_ops lazy_mode;
276
277 /* dom0 ops */
278
279 /* Sometimes the physical address is a pfn, and sometimes its
280 an mfn. We can tell which is which from the index. */
281 void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx,
282 unsigned long phys, pgprot_t flags);
276}; 283};
277 284
278/* This contains all the paravirt structures: we get a convenient 285/* This contains all the paravirt structures: we get a convenient
@@ -1252,6 +1259,12 @@ static inline void arch_flush_lazy_mmu_mode(void)
1252 } 1259 }
1253} 1260}
1254 1261
1262static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
1263 unsigned long phys, pgprot_t flags)
1264{
1265 pv_mmu_ops.set_fixmap(idx, phys, flags);
1266}
1267
1255void _paravirt_nop(void); 1268void _paravirt_nop(void);
1256#define paravirt_nop ((void *)_paravirt_nop) 1269#define paravirt_nop ((void *)_paravirt_nop)
1257 1270
diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h
index 97c271b2910b..702f2699c6df 100644
--- a/include/asm-x86/pgtable.h
+++ b/include/asm-x86/pgtable.h
@@ -318,6 +318,9 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
318 unsigned long size, pgprot_t *vma_prot); 318 unsigned long size, pgprot_t *vma_prot);
319#endif 319#endif
320 320
321/* Install a pte for a particular vaddr in kernel space. */
322void set_pte_vaddr(unsigned long vaddr, pte_t pte);
323
321#ifdef CONFIG_PARAVIRT 324#ifdef CONFIG_PARAVIRT
322#include <asm/paravirt.h> 325#include <asm/paravirt.h>
323#else /* !CONFIG_PARAVIRT */ 326#else /* !CONFIG_PARAVIRT */