diff options
Diffstat (limited to 'arch/x86/xen')
-rw-r--r-- | arch/x86/xen/enlighten.c | 99 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 134 | ||||
-rw-r--r-- | arch/x86/xen/mmu.h | 3 | ||||
-rw-r--r-- | arch/x86/xen/smp.c | 4 | ||||
-rw-r--r-- | arch/x86/xen/xen-ops.h | 3 |
5 files changed, 168 insertions, 75 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 82cd39a6cbd3..12a3159333bc 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/xen/hypervisor.h> | 42 | #include <asm/xen/hypervisor.h> |
43 | #include <asm/fixmap.h> | 43 | #include <asm/fixmap.h> |
44 | #include <asm/processor.h> | 44 | #include <asm/processor.h> |
45 | #include <asm/proto.h> | ||
45 | #include <asm/msr-index.h> | 46 | #include <asm/msr-index.h> |
46 | #include <asm/setup.h> | 47 | #include <asm/setup.h> |
47 | #include <asm/desc.h> | 48 | #include <asm/desc.h> |
@@ -168,21 +169,23 @@ static void __init xen_banner(void) | |||
168 | xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); | 169 | xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); |
169 | } | 170 | } |
170 | 171 | ||
172 | static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0; | ||
173 | static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0; | ||
174 | |||
171 | static void xen_cpuid(unsigned int *ax, unsigned int *bx, | 175 | static void xen_cpuid(unsigned int *ax, unsigned int *bx, |
172 | unsigned int *cx, unsigned int *dx) | 176 | unsigned int *cx, unsigned int *dx) |
173 | { | 177 | { |
178 | unsigned maskecx = ~0; | ||
174 | unsigned maskedx = ~0; | 179 | unsigned maskedx = ~0; |
175 | 180 | ||
176 | /* | 181 | /* |
177 | * Mask out inconvenient features, to try and disable as many | 182 | * Mask out inconvenient features, to try and disable as many |
178 | * unsupported kernel subsystems as possible. | 183 | * unsupported kernel subsystems as possible. |
179 | */ | 184 | */ |
180 | if (*ax == 1) | 185 | if (*ax == 1) { |
181 | maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */ | 186 | maskecx = cpuid_leaf1_ecx_mask; |
182 | (1 << X86_FEATURE_ACPI) | /* disable ACPI */ | 187 | maskedx = cpuid_leaf1_edx_mask; |
183 | (1 << X86_FEATURE_MCE) | /* disable MCE */ | 188 | } |
184 | (1 << X86_FEATURE_MCA) | /* disable MCA */ | ||
185 | (1 << X86_FEATURE_ACC)); /* thermal monitoring */ | ||
186 | 189 | ||
187 | asm(XEN_EMULATE_PREFIX "cpuid" | 190 | asm(XEN_EMULATE_PREFIX "cpuid" |
188 | : "=a" (*ax), | 191 | : "=a" (*ax), |
@@ -190,9 +193,43 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, | |||
190 | "=c" (*cx), | 193 | "=c" (*cx), |
191 | "=d" (*dx) | 194 | "=d" (*dx) |
192 | : "0" (*ax), "2" (*cx)); | 195 | : "0" (*ax), "2" (*cx)); |
196 | |||
197 | *cx &= maskecx; | ||
193 | *dx &= maskedx; | 198 | *dx &= maskedx; |
194 | } | 199 | } |
195 | 200 | ||
201 | static __init void xen_init_cpuid_mask(void) | ||
202 | { | ||
203 | unsigned int ax, bx, cx, dx; | ||
204 | |||
205 | cpuid_leaf1_edx_mask = | ||
206 | ~((1 << X86_FEATURE_MCE) | /* disable MCE */ | ||
207 | (1 << X86_FEATURE_MCA) | /* disable MCA */ | ||
208 | (1 << X86_FEATURE_ACC)); /* thermal monitoring */ | ||
209 | |||
210 | if (!xen_initial_domain()) | ||
211 | cpuid_leaf1_edx_mask &= | ||
212 | ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ | ||
213 | (1 << X86_FEATURE_ACPI)); /* disable ACPI */ | ||
214 | |||
215 | ax = 1; | ||
216 | xen_cpuid(&ax, &bx, &cx, &dx); | ||
217 | |||
218 | /* cpuid claims we support xsave; try enabling it to see what happens */ | ||
219 | if (cx & (1 << (X86_FEATURE_XSAVE % 32))) { | ||
220 | unsigned long cr4; | ||
221 | |||
222 | set_in_cr4(X86_CR4_OSXSAVE); | ||
223 | |||
224 | cr4 = read_cr4(); | ||
225 | |||
226 | if ((cr4 & X86_CR4_OSXSAVE) == 0) | ||
227 | cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32)); | ||
228 | |||
229 | clear_in_cr4(X86_CR4_OSXSAVE); | ||
230 | } | ||
231 | } | ||
232 | |||
196 | static void xen_set_debugreg(int reg, unsigned long val) | 233 | static void xen_set_debugreg(int reg, unsigned long val) |
197 | { | 234 | { |
198 | HYPERVISOR_set_debugreg(reg, val); | 235 | HYPERVISOR_set_debugreg(reg, val); |
@@ -203,10 +240,10 @@ static unsigned long xen_get_debugreg(int reg) | |||
203 | return HYPERVISOR_get_debugreg(reg); | 240 | return HYPERVISOR_get_debugreg(reg); |
204 | } | 241 | } |
205 | 242 | ||
206 | void xen_leave_lazy(void) | 243 | static void xen_end_context_switch(struct task_struct *next) |
207 | { | 244 | { |
208 | paravirt_leave_lazy(paravirt_get_lazy_mode()); | ||
209 | xen_mc_flush(); | 245 | xen_mc_flush(); |
246 | paravirt_end_context_switch(next); | ||
210 | } | 247 | } |
211 | 248 | ||
212 | static unsigned long xen_store_tr(void) | 249 | static unsigned long xen_store_tr(void) |
@@ -284,12 +321,11 @@ static void xen_set_ldt(const void *addr, unsigned entries) | |||
284 | 321 | ||
285 | static void xen_load_gdt(const struct desc_ptr *dtr) | 322 | static void xen_load_gdt(const struct desc_ptr *dtr) |
286 | { | 323 | { |
287 | unsigned long *frames; | ||
288 | unsigned long va = dtr->address; | 324 | unsigned long va = dtr->address; |
289 | unsigned int size = dtr->size + 1; | 325 | unsigned int size = dtr->size + 1; |
290 | unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; | 326 | unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; |
327 | unsigned long frames[pages]; | ||
291 | int f; | 328 | int f; |
292 | struct multicall_space mcs; | ||
293 | 329 | ||
294 | /* A GDT can be up to 64k in size, which corresponds to 8192 | 330 | /* A GDT can be up to 64k in size, which corresponds to 8192 |
295 | 8-byte entries, or 16 4k pages.. */ | 331 | 8-byte entries, or 16 4k pages.. */ |
@@ -297,19 +333,26 @@ static void xen_load_gdt(const struct desc_ptr *dtr) | |||
297 | BUG_ON(size > 65536); | 333 | BUG_ON(size > 65536); |
298 | BUG_ON(va & ~PAGE_MASK); | 334 | BUG_ON(va & ~PAGE_MASK); |
299 | 335 | ||
300 | mcs = xen_mc_entry(sizeof(*frames) * pages); | ||
301 | frames = mcs.args; | ||
302 | |||
303 | for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { | 336 | for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { |
304 | frames[f] = arbitrary_virt_to_mfn((void *)va); | 337 | int level; |
338 | pte_t *ptep = lookup_address(va, &level); | ||
339 | unsigned long pfn, mfn; | ||
340 | void *virt; | ||
341 | |||
342 | BUG_ON(ptep == NULL); | ||
343 | |||
344 | pfn = pte_pfn(*ptep); | ||
345 | mfn = pfn_to_mfn(pfn); | ||
346 | virt = __va(PFN_PHYS(pfn)); | ||
347 | |||
348 | frames[f] = mfn; | ||
305 | 349 | ||
306 | make_lowmem_page_readonly((void *)va); | 350 | make_lowmem_page_readonly((void *)va); |
307 | make_lowmem_page_readonly(mfn_to_virt(frames[f])); | 351 | make_lowmem_page_readonly(virt); |
308 | } | 352 | } |
309 | 353 | ||
310 | MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct)); | 354 | if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct))) |
311 | 355 | BUG(); | |
312 | xen_mc_issue(PARAVIRT_LAZY_CPU); | ||
313 | } | 356 | } |
314 | 357 | ||
315 | static void load_TLS_descriptor(struct thread_struct *t, | 358 | static void load_TLS_descriptor(struct thread_struct *t, |
@@ -385,7 +428,7 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, | |||
385 | static int cvt_gate_to_trap(int vector, const gate_desc *val, | 428 | static int cvt_gate_to_trap(int vector, const gate_desc *val, |
386 | struct trap_info *info) | 429 | struct trap_info *info) |
387 | { | 430 | { |
388 | if (val->type != 0xf && val->type != 0xe) | 431 | if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT) |
389 | return 0; | 432 | return 0; |
390 | 433 | ||
391 | info->vector = vector; | 434 | info->vector = vector; |
@@ -393,8 +436,8 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val, | |||
393 | info->cs = gate_segment(*val); | 436 | info->cs = gate_segment(*val); |
394 | info->flags = val->dpl; | 437 | info->flags = val->dpl; |
395 | /* interrupt gates clear IF */ | 438 | /* interrupt gates clear IF */ |
396 | if (val->type == 0xe) | 439 | if (val->type == GATE_INTERRUPT) |
397 | info->flags |= 4; | 440 | info->flags |= 1 << 2; |
398 | 441 | ||
399 | return 1; | 442 | return 1; |
400 | } | 443 | } |
@@ -817,10 +860,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
817 | /* Xen takes care of %gs when switching to usermode for us */ | 860 | /* Xen takes care of %gs when switching to usermode for us */ |
818 | .swapgs = paravirt_nop, | 861 | .swapgs = paravirt_nop, |
819 | 862 | ||
820 | .lazy_mode = { | 863 | .start_context_switch = paravirt_start_context_switch, |
821 | .enter = paravirt_enter_lazy_cpu, | 864 | .end_context_switch = xen_end_context_switch, |
822 | .leave = xen_leave_lazy, | ||
823 | }, | ||
824 | }; | 865 | }; |
825 | 866 | ||
826 | static const struct pv_apic_ops xen_apic_ops __initdata = { | 867 | static const struct pv_apic_ops xen_apic_ops __initdata = { |
@@ -872,7 +913,6 @@ static const struct machine_ops __initdata xen_machine_ops = { | |||
872 | .emergency_restart = xen_emergency_restart, | 913 | .emergency_restart = xen_emergency_restart, |
873 | }; | 914 | }; |
874 | 915 | ||
875 | |||
876 | /* First C function to be called on Xen boot */ | 916 | /* First C function to be called on Xen boot */ |
877 | asmlinkage void __init xen_start_kernel(void) | 917 | asmlinkage void __init xen_start_kernel(void) |
878 | { | 918 | { |
@@ -897,6 +937,8 @@ asmlinkage void __init xen_start_kernel(void) | |||
897 | 937 | ||
898 | xen_init_irq_ops(); | 938 | xen_init_irq_ops(); |
899 | 939 | ||
940 | xen_init_cpuid_mask(); | ||
941 | |||
900 | #ifdef CONFIG_X86_LOCAL_APIC | 942 | #ifdef CONFIG_X86_LOCAL_APIC |
901 | /* | 943 | /* |
902 | * set up the basic apic ops. | 944 | * set up the basic apic ops. |
@@ -938,6 +980,11 @@ asmlinkage void __init xen_start_kernel(void) | |||
938 | if (!xen_initial_domain()) | 980 | if (!xen_initial_domain()) |
939 | __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); | 981 | __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); |
940 | 982 | ||
983 | #ifdef CONFIG_X86_64 | ||
984 | /* Work out if we support NX */ | ||
985 | check_efer(); | ||
986 | #endif | ||
987 | |||
941 | /* Don't do the full vcpu_info placement stuff until we have a | 988 | /* Don't do the full vcpu_info placement stuff until we have a |
942 | possible map and a non-dummy shared_info. */ | 989 | possible map and a non-dummy shared_info. */ |
943 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; | 990 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index db3802fb7b84..77b242c9a11e 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -184,7 +184,7 @@ static inline unsigned p2m_index(unsigned long pfn) | |||
184 | } | 184 | } |
185 | 185 | ||
186 | /* Build the parallel p2m_top_mfn structures */ | 186 | /* Build the parallel p2m_top_mfn structures */ |
187 | void xen_setup_mfn_list_list(void) | 187 | static void __init xen_build_mfn_list_list(void) |
188 | { | 188 | { |
189 | unsigned pfn, idx; | 189 | unsigned pfn, idx; |
190 | 190 | ||
@@ -198,7 +198,10 @@ void xen_setup_mfn_list_list(void) | |||
198 | unsigned topidx = idx * P2M_ENTRIES_PER_PAGE; | 198 | unsigned topidx = idx * P2M_ENTRIES_PER_PAGE; |
199 | p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]); | 199 | p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]); |
200 | } | 200 | } |
201 | } | ||
201 | 202 | ||
203 | void xen_setup_mfn_list_list(void) | ||
204 | { | ||
202 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); | 205 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); |
203 | 206 | ||
204 | HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = | 207 | HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = |
@@ -218,6 +221,8 @@ void __init xen_build_dynamic_phys_to_machine(void) | |||
218 | 221 | ||
219 | p2m_top[topidx] = &mfn_list[pfn]; | 222 | p2m_top[topidx] = &mfn_list[pfn]; |
220 | } | 223 | } |
224 | |||
225 | xen_build_mfn_list_list(); | ||
221 | } | 226 | } |
222 | 227 | ||
223 | unsigned long get_phys_to_machine(unsigned long pfn) | 228 | unsigned long get_phys_to_machine(unsigned long pfn) |
@@ -233,47 +238,74 @@ unsigned long get_phys_to_machine(unsigned long pfn) | |||
233 | } | 238 | } |
234 | EXPORT_SYMBOL_GPL(get_phys_to_machine); | 239 | EXPORT_SYMBOL_GPL(get_phys_to_machine); |
235 | 240 | ||
236 | static void alloc_p2m(unsigned long **pp, unsigned long *mfnp) | 241 | /* install a new p2m_top page */ |
242 | bool install_p2mtop_page(unsigned long pfn, unsigned long *p) | ||
237 | { | 243 | { |
238 | unsigned long *p; | 244 | unsigned topidx = p2m_top_index(pfn); |
245 | unsigned long **pfnp, *mfnp; | ||
239 | unsigned i; | 246 | unsigned i; |
240 | 247 | ||
241 | p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); | 248 | pfnp = &p2m_top[topidx]; |
242 | BUG_ON(p == NULL); | 249 | mfnp = &p2m_top_mfn[topidx]; |
243 | 250 | ||
244 | for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) | 251 | for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) |
245 | p[i] = INVALID_P2M_ENTRY; | 252 | p[i] = INVALID_P2M_ENTRY; |
246 | 253 | ||
247 | if (cmpxchg(pp, p2m_missing, p) != p2m_missing) | 254 | if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) { |
248 | free_page((unsigned long)p); | ||
249 | else | ||
250 | *mfnp = virt_to_mfn(p); | 255 | *mfnp = virt_to_mfn(p); |
256 | return true; | ||
257 | } | ||
258 | |||
259 | return false; | ||
251 | } | 260 | } |
252 | 261 | ||
253 | void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | 262 | static void alloc_p2m(unsigned long pfn) |
254 | { | 263 | { |
255 | unsigned topidx, idx; | 264 | unsigned long *p; |
256 | 265 | ||
257 | if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { | 266 | p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); |
258 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | 267 | BUG_ON(p == NULL); |
259 | return; | 268 | |
260 | } | 269 | if (!install_p2mtop_page(pfn, p)) |
270 | free_page((unsigned long)p); | ||
271 | } | ||
272 | |||
273 | /* Try to install p2m mapping; fail if intermediate bits missing */ | ||
274 | bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
275 | { | ||
276 | unsigned topidx, idx; | ||
261 | 277 | ||
262 | if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { | 278 | if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { |
263 | BUG_ON(mfn != INVALID_P2M_ENTRY); | 279 | BUG_ON(mfn != INVALID_P2M_ENTRY); |
264 | return; | 280 | return true; |
265 | } | 281 | } |
266 | 282 | ||
267 | topidx = p2m_top_index(pfn); | 283 | topidx = p2m_top_index(pfn); |
268 | if (p2m_top[topidx] == p2m_missing) { | 284 | if (p2m_top[topidx] == p2m_missing) { |
269 | /* no need to allocate a page to store an invalid entry */ | ||
270 | if (mfn == INVALID_P2M_ENTRY) | 285 | if (mfn == INVALID_P2M_ENTRY) |
271 | return; | 286 | return true; |
272 | alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]); | 287 | return false; |
273 | } | 288 | } |
274 | 289 | ||
275 | idx = p2m_index(pfn); | 290 | idx = p2m_index(pfn); |
276 | p2m_top[topidx][idx] = mfn; | 291 | p2m_top[topidx][idx] = mfn; |
292 | |||
293 | return true; | ||
294 | } | ||
295 | |||
296 | void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
297 | { | ||
298 | if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { | ||
299 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | if (unlikely(!__set_phys_to_machine(pfn, mfn))) { | ||
304 | alloc_p2m(pfn); | ||
305 | |||
306 | if (!__set_phys_to_machine(pfn, mfn)) | ||
307 | BUG(); | ||
308 | } | ||
277 | } | 309 | } |
278 | 310 | ||
279 | unsigned long arbitrary_virt_to_mfn(void *vaddr) | 311 | unsigned long arbitrary_virt_to_mfn(void *vaddr) |
@@ -419,10 +451,6 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags) | |||
419 | void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, | 451 | void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, |
420 | pte_t *ptep, pte_t pteval) | 452 | pte_t *ptep, pte_t pteval) |
421 | { | 453 | { |
422 | /* updates to init_mm may be done without lock */ | ||
423 | if (mm == &init_mm) | ||
424 | preempt_disable(); | ||
425 | |||
426 | ADD_STATS(set_pte_at, 1); | 454 | ADD_STATS(set_pte_at, 1); |
427 | // ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep)); | 455 | // ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep)); |
428 | ADD_STATS(set_pte_at_current, mm == current->mm); | 456 | ADD_STATS(set_pte_at_current, mm == current->mm); |
@@ -443,9 +471,7 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
443 | } | 471 | } |
444 | xen_set_pte(ptep, pteval); | 472 | xen_set_pte(ptep, pteval); |
445 | 473 | ||
446 | out: | 474 | out: return; |
447 | if (mm == &init_mm) | ||
448 | preempt_enable(); | ||
449 | } | 475 | } |
450 | 476 | ||
451 | pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, | 477 | pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, |
@@ -987,7 +1013,7 @@ static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page, | |||
987 | return 0; | 1013 | return 0; |
988 | } | 1014 | } |
989 | 1015 | ||
990 | void __init xen_mark_init_mm_pinned(void) | 1016 | static void __init xen_mark_init_mm_pinned(void) |
991 | { | 1017 | { |
992 | xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP); | 1018 | xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP); |
993 | } | 1019 | } |
@@ -1119,10 +1145,8 @@ static void drop_other_mm_ref(void *info) | |||
1119 | 1145 | ||
1120 | /* If this cpu still has a stale cr3 reference, then make sure | 1146 | /* If this cpu still has a stale cr3 reference, then make sure |
1121 | it has been flushed. */ | 1147 | it has been flushed. */ |
1122 | if (percpu_read(xen_current_cr3) == __pa(mm->pgd)) { | 1148 | if (percpu_read(xen_current_cr3) == __pa(mm->pgd)) |
1123 | load_cr3(swapper_pg_dir); | 1149 | load_cr3(swapper_pg_dir); |
1124 | arch_flush_lazy_cpu_mode(); | ||
1125 | } | ||
1126 | } | 1150 | } |
1127 | 1151 | ||
1128 | static void xen_drop_mm_ref(struct mm_struct *mm) | 1152 | static void xen_drop_mm_ref(struct mm_struct *mm) |
@@ -1135,7 +1159,6 @@ static void xen_drop_mm_ref(struct mm_struct *mm) | |||
1135 | load_cr3(swapper_pg_dir); | 1159 | load_cr3(swapper_pg_dir); |
1136 | else | 1160 | else |
1137 | leave_mm(smp_processor_id()); | 1161 | leave_mm(smp_processor_id()); |
1138 | arch_flush_lazy_cpu_mode(); | ||
1139 | } | 1162 | } |
1140 | 1163 | ||
1141 | /* Get the "official" set of cpus referring to our pagetable. */ | 1164 | /* Get the "official" set of cpus referring to our pagetable. */ |
@@ -1270,8 +1293,8 @@ static void xen_flush_tlb_others(const struct cpumask *cpus, | |||
1270 | } *args; | 1293 | } *args; |
1271 | struct multicall_space mcs; | 1294 | struct multicall_space mcs; |
1272 | 1295 | ||
1273 | BUG_ON(cpumask_empty(cpus)); | 1296 | if (cpumask_empty(cpus)) |
1274 | BUG_ON(!mm); | 1297 | return; /* nothing to do */ |
1275 | 1298 | ||
1276 | mcs = xen_mc_entry(sizeof(*args)); | 1299 | mcs = xen_mc_entry(sizeof(*args)); |
1277 | args = mcs.args; | 1300 | args = mcs.args; |
@@ -1438,6 +1461,15 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte) | |||
1438 | } | 1461 | } |
1439 | #endif | 1462 | #endif |
1440 | 1463 | ||
1464 | static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) | ||
1465 | { | ||
1466 | struct mmuext_op op; | ||
1467 | op.cmd = cmd; | ||
1468 | op.arg1.mfn = pfn_to_mfn(pfn); | ||
1469 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF)) | ||
1470 | BUG(); | ||
1471 | } | ||
1472 | |||
1441 | /* Early in boot, while setting up the initial pagetable, assume | 1473 | /* Early in boot, while setting up the initial pagetable, assume |
1442 | everything is pinned. */ | 1474 | everything is pinned. */ |
1443 | static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) | 1475 | static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) |
@@ -1446,22 +1478,29 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) | |||
1446 | BUG_ON(mem_map); /* should only be used early */ | 1478 | BUG_ON(mem_map); /* should only be used early */ |
1447 | #endif | 1479 | #endif |
1448 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); | 1480 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); |
1481 | pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); | ||
1482 | } | ||
1483 | |||
1484 | /* Used for pmd and pud */ | ||
1485 | static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) | ||
1486 | { | ||
1487 | #ifdef CONFIG_FLATMEM | ||
1488 | BUG_ON(mem_map); /* should only be used early */ | ||
1489 | #endif | ||
1490 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); | ||
1449 | } | 1491 | } |
1450 | 1492 | ||
1451 | /* Early release_pte assumes that all pts are pinned, since there's | 1493 | /* Early release_pte assumes that all pts are pinned, since there's |
1452 | only init_mm and anything attached to that is pinned. */ | 1494 | only init_mm and anything attached to that is pinned. */ |
1453 | static void xen_release_pte_init(unsigned long pfn) | 1495 | static __init void xen_release_pte_init(unsigned long pfn) |
1454 | { | 1496 | { |
1497 | pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); | ||
1455 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); | 1498 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); |
1456 | } | 1499 | } |
1457 | 1500 | ||
1458 | static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) | 1501 | static __init void xen_release_pmd_init(unsigned long pfn) |
1459 | { | 1502 | { |
1460 | struct mmuext_op op; | 1503 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); |
1461 | op.cmd = cmd; | ||
1462 | op.arg1.mfn = pfn_to_mfn(pfn); | ||
1463 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF)) | ||
1464 | BUG(); | ||
1465 | } | 1504 | } |
1466 | 1505 | ||
1467 | /* This needs to make sure the new pte page is pinned iff its being | 1506 | /* This needs to make sure the new pte page is pinned iff its being |
@@ -1819,6 +1858,13 @@ __init void xen_post_allocator_init(void) | |||
1819 | xen_mark_init_mm_pinned(); | 1858 | xen_mark_init_mm_pinned(); |
1820 | } | 1859 | } |
1821 | 1860 | ||
1861 | static void xen_leave_lazy_mmu(void) | ||
1862 | { | ||
1863 | preempt_disable(); | ||
1864 | xen_mc_flush(); | ||
1865 | paravirt_leave_lazy_mmu(); | ||
1866 | preempt_enable(); | ||
1867 | } | ||
1822 | 1868 | ||
1823 | const struct pv_mmu_ops xen_mmu_ops __initdata = { | 1869 | const struct pv_mmu_ops xen_mmu_ops __initdata = { |
1824 | .pagetable_setup_start = xen_pagetable_setup_start, | 1870 | .pagetable_setup_start = xen_pagetable_setup_start, |
@@ -1843,9 +1889,9 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = { | |||
1843 | 1889 | ||
1844 | .alloc_pte = xen_alloc_pte_init, | 1890 | .alloc_pte = xen_alloc_pte_init, |
1845 | .release_pte = xen_release_pte_init, | 1891 | .release_pte = xen_release_pte_init, |
1846 | .alloc_pmd = xen_alloc_pte_init, | 1892 | .alloc_pmd = xen_alloc_pmd_init, |
1847 | .alloc_pmd_clone = paravirt_nop, | 1893 | .alloc_pmd_clone = paravirt_nop, |
1848 | .release_pmd = xen_release_pte_init, | 1894 | .release_pmd = xen_release_pmd_init, |
1849 | 1895 | ||
1850 | #ifdef CONFIG_HIGHPTE | 1896 | #ifdef CONFIG_HIGHPTE |
1851 | .kmap_atomic_pte = xen_kmap_atomic_pte, | 1897 | .kmap_atomic_pte = xen_kmap_atomic_pte, |
@@ -1883,8 +1929,8 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = { | |||
1883 | .make_pud = PV_CALLEE_SAVE(xen_make_pud), | 1929 | .make_pud = PV_CALLEE_SAVE(xen_make_pud), |
1884 | .set_pgd = xen_set_pgd_hyper, | 1930 | .set_pgd = xen_set_pgd_hyper, |
1885 | 1931 | ||
1886 | .alloc_pud = xen_alloc_pte_init, | 1932 | .alloc_pud = xen_alloc_pmd_init, |
1887 | .release_pud = xen_release_pte_init, | 1933 | .release_pud = xen_release_pmd_init, |
1888 | #endif /* PAGETABLE_LEVELS == 4 */ | 1934 | #endif /* PAGETABLE_LEVELS == 4 */ |
1889 | 1935 | ||
1890 | .activate_mm = xen_activate_mm, | 1936 | .activate_mm = xen_activate_mm, |
@@ -1893,7 +1939,7 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = { | |||
1893 | 1939 | ||
1894 | .lazy_mode = { | 1940 | .lazy_mode = { |
1895 | .enter = paravirt_enter_lazy_mmu, | 1941 | .enter = paravirt_enter_lazy_mmu, |
1896 | .leave = xen_leave_lazy, | 1942 | .leave = xen_leave_lazy_mmu, |
1897 | }, | 1943 | }, |
1898 | 1944 | ||
1899 | .set_fixmap = xen_set_fixmap, | 1945 | .set_fixmap = xen_set_fixmap, |
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h index 24d1b44a337d..da7302624897 100644 --- a/arch/x86/xen/mmu.h +++ b/arch/x86/xen/mmu.h | |||
@@ -11,6 +11,9 @@ enum pt_level { | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | 13 | ||
14 | bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); | ||
15 | bool install_p2mtop_page(unsigned long pfn, unsigned long *p); | ||
16 | |||
14 | void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); | 17 | void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); |
15 | 18 | ||
16 | 19 | ||
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 585a6e330837..429834ec1687 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c | |||
@@ -317,7 +317,7 @@ static int __cpuinit xen_cpu_up(unsigned int cpu) | |||
317 | BUG_ON(rc); | 317 | BUG_ON(rc); |
318 | 318 | ||
319 | while(per_cpu(cpu_state, cpu) != CPU_ONLINE) { | 319 | while(per_cpu(cpu_state, cpu) != CPU_ONLINE) { |
320 | HYPERVISOR_sched_op(SCHEDOP_yield, 0); | 320 | HYPERVISOR_sched_op(SCHEDOP_yield, NULL); |
321 | barrier(); | 321 | barrier(); |
322 | } | 322 | } |
323 | 323 | ||
@@ -422,7 +422,7 @@ static void xen_smp_send_call_function_ipi(const struct cpumask *mask) | |||
422 | /* Make sure other vcpus get a chance to run if they need to. */ | 422 | /* Make sure other vcpus get a chance to run if they need to. */ |
423 | for_each_cpu(cpu, mask) { | 423 | for_each_cpu(cpu, mask) { |
424 | if (xen_vcpu_stolen(cpu)) { | 424 | if (xen_vcpu_stolen(cpu)) { |
425 | HYPERVISOR_sched_op(SCHEDOP_yield, 0); | 425 | HYPERVISOR_sched_op(SCHEDOP_yield, NULL); |
426 | break; | 426 | break; |
427 | } | 427 | } |
428 | } | 428 | } |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 2f5ef2632ea2..5c50a1017a37 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -30,7 +30,6 @@ pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn); | |||
30 | void xen_ident_map_ISA(void); | 30 | void xen_ident_map_ISA(void); |
31 | void xen_reserve_top(void); | 31 | void xen_reserve_top(void); |
32 | 32 | ||
33 | void xen_leave_lazy(void); | ||
34 | void xen_post_allocator_init(void); | 33 | void xen_post_allocator_init(void); |
35 | 34 | ||
36 | char * __init xen_memory_setup(void); | 35 | char * __init xen_memory_setup(void); |
@@ -57,8 +56,6 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id); | |||
57 | 56 | ||
58 | bool xen_vcpu_stolen(int vcpu); | 57 | bool xen_vcpu_stolen(int vcpu); |
59 | 58 | ||
60 | void xen_mark_init_mm_pinned(void); | ||
61 | |||
62 | void xen_setup_vcpu_info_placement(void); | 59 | void xen_setup_vcpu_info_placement(void); |
63 | 60 | ||
64 | #ifdef CONFIG_SMP | 61 | #ifdef CONFIG_SMP |