diff options
Diffstat (limited to 'arch/x86/xen')
-rw-r--r-- | arch/x86/xen/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 35 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 153 | ||||
-rw-r--r-- | arch/x86/xen/multicalls.c | 169 | ||||
-rw-r--r-- | arch/x86/xen/multicalls.h | 6 | ||||
-rw-r--r-- | arch/x86/xen/platform-pci-unplug.c | 2 | ||||
-rw-r--r-- | arch/x86/xen/setup.c | 48 | ||||
-rw-r--r-- | arch/x86/xen/smp.c | 15 | ||||
-rw-r--r-- | arch/x86/xen/time.c | 5 | ||||
-rw-r--r-- | arch/x86/xen/trace.c | 62 | ||||
-rw-r--r-- | arch/x86/xen/vga.c | 67 | ||||
-rw-r--r-- | arch/x86/xen/xen-asm_32.S | 8 | ||||
-rw-r--r-- | arch/x86/xen/xen-ops.h | 11 |
13 files changed, 409 insertions, 176 deletions
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 17c565de3d6..add2c2d729c 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile | |||
@@ -15,8 +15,10 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ | |||
15 | grant-table.o suspend.o platform-pci-unplug.o \ | 15 | grant-table.o suspend.o platform-pci-unplug.o \ |
16 | p2m.o | 16 | p2m.o |
17 | 17 | ||
18 | obj-$(CONFIG_EVENT_TRACING) += trace.o | ||
19 | |||
18 | obj-$(CONFIG_SMP) += smp.o | 20 | obj-$(CONFIG_SMP) += smp.o |
19 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o | 21 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o |
20 | obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o | 22 | obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o |
21 | 23 | obj-$(CONFIG_XEN_DOM0) += vga.o | |
22 | obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o | 24 | obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 5525163a039..46c8069ae98 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -77,8 +77,8 @@ EXPORT_SYMBOL_GPL(xen_domain_type); | |||
77 | 77 | ||
78 | unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START; | 78 | unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START; |
79 | EXPORT_SYMBOL(machine_to_phys_mapping); | 79 | EXPORT_SYMBOL(machine_to_phys_mapping); |
80 | unsigned int machine_to_phys_order; | 80 | unsigned long machine_to_phys_nr; |
81 | EXPORT_SYMBOL(machine_to_phys_order); | 81 | EXPORT_SYMBOL(machine_to_phys_nr); |
82 | 82 | ||
83 | struct start_info *xen_start_info; | 83 | struct start_info *xen_start_info; |
84 | EXPORT_SYMBOL_GPL(xen_start_info); | 84 | EXPORT_SYMBOL_GPL(xen_start_info); |
@@ -341,6 +341,8 @@ static void xen_set_ldt(const void *addr, unsigned entries) | |||
341 | struct mmuext_op *op; | 341 | struct mmuext_op *op; |
342 | struct multicall_space mcs = xen_mc_entry(sizeof(*op)); | 342 | struct multicall_space mcs = xen_mc_entry(sizeof(*op)); |
343 | 343 | ||
344 | trace_xen_cpu_set_ldt(addr, entries); | ||
345 | |||
344 | op = mcs.args; | 346 | op = mcs.args; |
345 | op->cmd = MMUEXT_SET_LDT; | 347 | op->cmd = MMUEXT_SET_LDT; |
346 | op->arg1.linear_addr = (unsigned long)addr; | 348 | op->arg1.linear_addr = (unsigned long)addr; |
@@ -496,6 +498,8 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, | |||
496 | xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]); | 498 | xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]); |
497 | u64 entry = *(u64 *)ptr; | 499 | u64 entry = *(u64 *)ptr; |
498 | 500 | ||
501 | trace_xen_cpu_write_ldt_entry(dt, entrynum, entry); | ||
502 | |||
499 | preempt_disable(); | 503 | preempt_disable(); |
500 | 504 | ||
501 | xen_mc_flush(); | 505 | xen_mc_flush(); |
@@ -565,6 +569,8 @@ static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g) | |||
565 | unsigned long p = (unsigned long)&dt[entrynum]; | 569 | unsigned long p = (unsigned long)&dt[entrynum]; |
566 | unsigned long start, end; | 570 | unsigned long start, end; |
567 | 571 | ||
572 | trace_xen_cpu_write_idt_entry(dt, entrynum, g); | ||
573 | |||
568 | preempt_disable(); | 574 | preempt_disable(); |
569 | 575 | ||
570 | start = __this_cpu_read(idt_desc.address); | 576 | start = __this_cpu_read(idt_desc.address); |
@@ -619,6 +625,8 @@ static void xen_load_idt(const struct desc_ptr *desc) | |||
619 | static DEFINE_SPINLOCK(lock); | 625 | static DEFINE_SPINLOCK(lock); |
620 | static struct trap_info traps[257]; | 626 | static struct trap_info traps[257]; |
621 | 627 | ||
628 | trace_xen_cpu_load_idt(desc); | ||
629 | |||
622 | spin_lock(&lock); | 630 | spin_lock(&lock); |
623 | 631 | ||
624 | __get_cpu_var(idt_desc) = *desc; | 632 | __get_cpu_var(idt_desc) = *desc; |
@@ -637,6 +645,8 @@ static void xen_load_idt(const struct desc_ptr *desc) | |||
637 | static void xen_write_gdt_entry(struct desc_struct *dt, int entry, | 645 | static void xen_write_gdt_entry(struct desc_struct *dt, int entry, |
638 | const void *desc, int type) | 646 | const void *desc, int type) |
639 | { | 647 | { |
648 | trace_xen_cpu_write_gdt_entry(dt, entry, desc, type); | ||
649 | |||
640 | preempt_disable(); | 650 | preempt_disable(); |
641 | 651 | ||
642 | switch (type) { | 652 | switch (type) { |
@@ -665,6 +675,8 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry, | |||
665 | static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, | 675 | static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, |
666 | const void *desc, int type) | 676 | const void *desc, int type) |
667 | { | 677 | { |
678 | trace_xen_cpu_write_gdt_entry(dt, entry, desc, type); | ||
679 | |||
668 | switch (type) { | 680 | switch (type) { |
669 | case DESC_LDT: | 681 | case DESC_LDT: |
670 | case DESC_TSS: | 682 | case DESC_TSS: |
@@ -684,7 +696,9 @@ static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, | |||
684 | static void xen_load_sp0(struct tss_struct *tss, | 696 | static void xen_load_sp0(struct tss_struct *tss, |
685 | struct thread_struct *thread) | 697 | struct thread_struct *thread) |
686 | { | 698 | { |
687 | struct multicall_space mcs = xen_mc_entry(0); | 699 | struct multicall_space mcs; |
700 | |||
701 | mcs = xen_mc_entry(0); | ||
688 | MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0); | 702 | MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0); |
689 | xen_mc_issue(PARAVIRT_LAZY_CPU); | 703 | xen_mc_issue(PARAVIRT_LAZY_CPU); |
690 | } | 704 | } |
@@ -937,6 +951,10 @@ static const struct pv_info xen_info __initconst = { | |||
937 | .paravirt_enabled = 1, | 951 | .paravirt_enabled = 1, |
938 | .shared_kernel_pmd = 0, | 952 | .shared_kernel_pmd = 0, |
939 | 953 | ||
954 | #ifdef CONFIG_X86_64 | ||
955 | .extra_user_64bit_cs = FLAT_USER_CS64, | ||
956 | #endif | ||
957 | |||
940 | .name = "Xen", | 958 | .name = "Xen", |
941 | }; | 959 | }; |
942 | 960 | ||
@@ -1248,6 +1266,14 @@ asmlinkage void __init xen_start_kernel(void) | |||
1248 | if (pci_xen) | 1266 | if (pci_xen) |
1249 | x86_init.pci.arch_init = pci_xen_init; | 1267 | x86_init.pci.arch_init = pci_xen_init; |
1250 | } else { | 1268 | } else { |
1269 | const struct dom0_vga_console_info *info = | ||
1270 | (void *)((char *)xen_start_info + | ||
1271 | xen_start_info->console.dom0.info_off); | ||
1272 | |||
1273 | xen_init_vga(info, xen_start_info->console.dom0.info_size); | ||
1274 | xen_start_info->console.domU.mfn = 0; | ||
1275 | xen_start_info->console.domU.evtchn = 0; | ||
1276 | |||
1251 | /* Make sure ACS will be enabled */ | 1277 | /* Make sure ACS will be enabled */ |
1252 | pci_request_acs(); | 1278 | pci_request_acs(); |
1253 | } | 1279 | } |
@@ -1329,7 +1355,7 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, | |||
1329 | int cpu = (long)hcpu; | 1355 | int cpu = (long)hcpu; |
1330 | switch (action) { | 1356 | switch (action) { |
1331 | case CPU_UP_PREPARE: | 1357 | case CPU_UP_PREPARE: |
1332 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | 1358 | xen_vcpu_setup(cpu); |
1333 | if (xen_have_vector_callback) | 1359 | if (xen_have_vector_callback) |
1334 | xen_init_lock_cpu(cpu); | 1360 | xen_init_lock_cpu(cpu); |
1335 | break; | 1361 | break; |
@@ -1359,7 +1385,6 @@ static void __init xen_hvm_guest_init(void) | |||
1359 | xen_hvm_smp_init(); | 1385 | xen_hvm_smp_init(); |
1360 | register_cpu_notifier(&xen_hvm_cpu_notifier); | 1386 | register_cpu_notifier(&xen_hvm_cpu_notifier); |
1361 | xen_unplug_emulated_devices(); | 1387 | xen_unplug_emulated_devices(); |
1362 | have_vcpu_info_placement = 0; | ||
1363 | x86_init.irqs.intr_init = xen_init_IRQ; | 1388 | x86_init.irqs.intr_init = xen_init_IRQ; |
1364 | xen_hvm_init_time_ops(); | 1389 | xen_hvm_init_time_ops(); |
1365 | xen_hvm_init_mmu_ops(); | 1390 | xen_hvm_init_mmu_ops(); |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 0ccccb67a99..3dd53f997b1 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -48,6 +48,8 @@ | |||
48 | #include <linux/memblock.h> | 48 | #include <linux/memblock.h> |
49 | #include <linux/seq_file.h> | 49 | #include <linux/seq_file.h> |
50 | 50 | ||
51 | #include <trace/events/xen.h> | ||
52 | |||
51 | #include <asm/pgtable.h> | 53 | #include <asm/pgtable.h> |
52 | #include <asm/tlbflush.h> | 54 | #include <asm/tlbflush.h> |
53 | #include <asm/fixmap.h> | 55 | #include <asm/fixmap.h> |
@@ -194,6 +196,8 @@ void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid) | |||
194 | struct multicall_space mcs; | 196 | struct multicall_space mcs; |
195 | struct mmu_update *u; | 197 | struct mmu_update *u; |
196 | 198 | ||
199 | trace_xen_mmu_set_domain_pte(ptep, pteval, domid); | ||
200 | |||
197 | mcs = xen_mc_entry(sizeof(*u)); | 201 | mcs = xen_mc_entry(sizeof(*u)); |
198 | u = mcs.args; | 202 | u = mcs.args; |
199 | 203 | ||
@@ -225,6 +229,24 @@ static void xen_extend_mmu_update(const struct mmu_update *update) | |||
225 | *u = *update; | 229 | *u = *update; |
226 | } | 230 | } |
227 | 231 | ||
232 | static void xen_extend_mmuext_op(const struct mmuext_op *op) | ||
233 | { | ||
234 | struct multicall_space mcs; | ||
235 | struct mmuext_op *u; | ||
236 | |||
237 | mcs = xen_mc_extend_args(__HYPERVISOR_mmuext_op, sizeof(*u)); | ||
238 | |||
239 | if (mcs.mc != NULL) { | ||
240 | mcs.mc->args[1]++; | ||
241 | } else { | ||
242 | mcs = __xen_mc_entry(sizeof(*u)); | ||
243 | MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF); | ||
244 | } | ||
245 | |||
246 | u = mcs.args; | ||
247 | *u = *op; | ||
248 | } | ||
249 | |||
228 | static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val) | 250 | static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val) |
229 | { | 251 | { |
230 | struct mmu_update u; | 252 | struct mmu_update u; |
@@ -245,6 +267,8 @@ static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val) | |||
245 | 267 | ||
246 | static void xen_set_pmd(pmd_t *ptr, pmd_t val) | 268 | static void xen_set_pmd(pmd_t *ptr, pmd_t val) |
247 | { | 269 | { |
270 | trace_xen_mmu_set_pmd(ptr, val); | ||
271 | |||
248 | /* If page is not pinned, we can just update the entry | 272 | /* If page is not pinned, we can just update the entry |
249 | directly */ | 273 | directly */ |
250 | if (!xen_page_pinned(ptr)) { | 274 | if (!xen_page_pinned(ptr)) { |
@@ -282,22 +306,30 @@ static bool xen_batched_set_pte(pte_t *ptep, pte_t pteval) | |||
282 | return true; | 306 | return true; |
283 | } | 307 | } |
284 | 308 | ||
285 | static void xen_set_pte(pte_t *ptep, pte_t pteval) | 309 | static inline void __xen_set_pte(pte_t *ptep, pte_t pteval) |
286 | { | 310 | { |
287 | if (!xen_batched_set_pte(ptep, pteval)) | 311 | if (!xen_batched_set_pte(ptep, pteval)) |
288 | native_set_pte(ptep, pteval); | 312 | native_set_pte(ptep, pteval); |
289 | } | 313 | } |
290 | 314 | ||
315 | static void xen_set_pte(pte_t *ptep, pte_t pteval) | ||
316 | { | ||
317 | trace_xen_mmu_set_pte(ptep, pteval); | ||
318 | __xen_set_pte(ptep, pteval); | ||
319 | } | ||
320 | |||
291 | static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, | 321 | static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, |
292 | pte_t *ptep, pte_t pteval) | 322 | pte_t *ptep, pte_t pteval) |
293 | { | 323 | { |
294 | xen_set_pte(ptep, pteval); | 324 | trace_xen_mmu_set_pte_at(mm, addr, ptep, pteval); |
325 | __xen_set_pte(ptep, pteval); | ||
295 | } | 326 | } |
296 | 327 | ||
297 | pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, | 328 | pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, |
298 | unsigned long addr, pte_t *ptep) | 329 | unsigned long addr, pte_t *ptep) |
299 | { | 330 | { |
300 | /* Just return the pte as-is. We preserve the bits on commit */ | 331 | /* Just return the pte as-is. We preserve the bits on commit */ |
332 | trace_xen_mmu_ptep_modify_prot_start(mm, addr, ptep, *ptep); | ||
301 | return *ptep; | 333 | return *ptep; |
302 | } | 334 | } |
303 | 335 | ||
@@ -306,6 +338,7 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, | |||
306 | { | 338 | { |
307 | struct mmu_update u; | 339 | struct mmu_update u; |
308 | 340 | ||
341 | trace_xen_mmu_ptep_modify_prot_commit(mm, addr, ptep, pte); | ||
309 | xen_mc_batch(); | 342 | xen_mc_batch(); |
310 | 343 | ||
311 | u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD; | 344 | u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD; |
@@ -530,6 +563,8 @@ static void xen_set_pud_hyper(pud_t *ptr, pud_t val) | |||
530 | 563 | ||
531 | static void xen_set_pud(pud_t *ptr, pud_t val) | 564 | static void xen_set_pud(pud_t *ptr, pud_t val) |
532 | { | 565 | { |
566 | trace_xen_mmu_set_pud(ptr, val); | ||
567 | |||
533 | /* If page is not pinned, we can just update the entry | 568 | /* If page is not pinned, we can just update the entry |
534 | directly */ | 569 | directly */ |
535 | if (!xen_page_pinned(ptr)) { | 570 | if (!xen_page_pinned(ptr)) { |
@@ -543,17 +578,20 @@ static void xen_set_pud(pud_t *ptr, pud_t val) | |||
543 | #ifdef CONFIG_X86_PAE | 578 | #ifdef CONFIG_X86_PAE |
544 | static void xen_set_pte_atomic(pte_t *ptep, pte_t pte) | 579 | static void xen_set_pte_atomic(pte_t *ptep, pte_t pte) |
545 | { | 580 | { |
581 | trace_xen_mmu_set_pte_atomic(ptep, pte); | ||
546 | set_64bit((u64 *)ptep, native_pte_val(pte)); | 582 | set_64bit((u64 *)ptep, native_pte_val(pte)); |
547 | } | 583 | } |
548 | 584 | ||
549 | static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 585 | static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
550 | { | 586 | { |
587 | trace_xen_mmu_pte_clear(mm, addr, ptep); | ||
551 | if (!xen_batched_set_pte(ptep, native_make_pte(0))) | 588 | if (!xen_batched_set_pte(ptep, native_make_pte(0))) |
552 | native_pte_clear(mm, addr, ptep); | 589 | native_pte_clear(mm, addr, ptep); |
553 | } | 590 | } |
554 | 591 | ||
555 | static void xen_pmd_clear(pmd_t *pmdp) | 592 | static void xen_pmd_clear(pmd_t *pmdp) |
556 | { | 593 | { |
594 | trace_xen_mmu_pmd_clear(pmdp); | ||
557 | set_pmd(pmdp, __pmd(0)); | 595 | set_pmd(pmdp, __pmd(0)); |
558 | } | 596 | } |
559 | #endif /* CONFIG_X86_PAE */ | 597 | #endif /* CONFIG_X86_PAE */ |
@@ -629,6 +667,8 @@ static void xen_set_pgd(pgd_t *ptr, pgd_t val) | |||
629 | { | 667 | { |
630 | pgd_t *user_ptr = xen_get_user_pgd(ptr); | 668 | pgd_t *user_ptr = xen_get_user_pgd(ptr); |
631 | 669 | ||
670 | trace_xen_mmu_set_pgd(ptr, user_ptr, val); | ||
671 | |||
632 | /* If page is not pinned, we can just update the entry | 672 | /* If page is not pinned, we can just update the entry |
633 | directly */ | 673 | directly */ |
634 | if (!xen_page_pinned(ptr)) { | 674 | if (!xen_page_pinned(ptr)) { |
@@ -788,14 +828,12 @@ static void xen_pte_unlock(void *v) | |||
788 | 828 | ||
789 | static void xen_do_pin(unsigned level, unsigned long pfn) | 829 | static void xen_do_pin(unsigned level, unsigned long pfn) |
790 | { | 830 | { |
791 | struct mmuext_op *op; | 831 | struct mmuext_op op; |
792 | struct multicall_space mcs; | ||
793 | 832 | ||
794 | mcs = __xen_mc_entry(sizeof(*op)); | 833 | op.cmd = level; |
795 | op = mcs.args; | 834 | op.arg1.mfn = pfn_to_mfn(pfn); |
796 | op->cmd = level; | 835 | |
797 | op->arg1.mfn = pfn_to_mfn(pfn); | 836 | xen_extend_mmuext_op(&op); |
798 | MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); | ||
799 | } | 837 | } |
800 | 838 | ||
801 | static int xen_pin_page(struct mm_struct *mm, struct page *page, | 839 | static int xen_pin_page(struct mm_struct *mm, struct page *page, |
@@ -863,6 +901,8 @@ static int xen_pin_page(struct mm_struct *mm, struct page *page, | |||
863 | read-only, and can be pinned. */ | 901 | read-only, and can be pinned. */ |
864 | static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd) | 902 | static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd) |
865 | { | 903 | { |
904 | trace_xen_mmu_pgd_pin(mm, pgd); | ||
905 | |||
866 | xen_mc_batch(); | 906 | xen_mc_batch(); |
867 | 907 | ||
868 | if (__xen_pgd_walk(mm, pgd, xen_pin_page, USER_LIMIT)) { | 908 | if (__xen_pgd_walk(mm, pgd, xen_pin_page, USER_LIMIT)) { |
@@ -988,6 +1028,8 @@ static int xen_unpin_page(struct mm_struct *mm, struct page *page, | |||
988 | /* Release a pagetables pages back as normal RW */ | 1028 | /* Release a pagetables pages back as normal RW */ |
989 | static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd) | 1029 | static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd) |
990 | { | 1030 | { |
1031 | trace_xen_mmu_pgd_unpin(mm, pgd); | ||
1032 | |||
991 | xen_mc_batch(); | 1033 | xen_mc_batch(); |
992 | 1034 | ||
993 | xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); | 1035 | xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); |
@@ -1196,6 +1238,8 @@ static void xen_flush_tlb(void) | |||
1196 | struct mmuext_op *op; | 1238 | struct mmuext_op *op; |
1197 | struct multicall_space mcs; | 1239 | struct multicall_space mcs; |
1198 | 1240 | ||
1241 | trace_xen_mmu_flush_tlb(0); | ||
1242 | |||
1199 | preempt_disable(); | 1243 | preempt_disable(); |
1200 | 1244 | ||
1201 | mcs = xen_mc_entry(sizeof(*op)); | 1245 | mcs = xen_mc_entry(sizeof(*op)); |
@@ -1214,6 +1258,8 @@ static void xen_flush_tlb_single(unsigned long addr) | |||
1214 | struct mmuext_op *op; | 1258 | struct mmuext_op *op; |
1215 | struct multicall_space mcs; | 1259 | struct multicall_space mcs; |
1216 | 1260 | ||
1261 | trace_xen_mmu_flush_tlb_single(addr); | ||
1262 | |||
1217 | preempt_disable(); | 1263 | preempt_disable(); |
1218 | 1264 | ||
1219 | mcs = xen_mc_entry(sizeof(*op)); | 1265 | mcs = xen_mc_entry(sizeof(*op)); |
@@ -1240,6 +1286,8 @@ static void xen_flush_tlb_others(const struct cpumask *cpus, | |||
1240 | } *args; | 1286 | } *args; |
1241 | struct multicall_space mcs; | 1287 | struct multicall_space mcs; |
1242 | 1288 | ||
1289 | trace_xen_mmu_flush_tlb_others(cpus, mm, va); | ||
1290 | |||
1243 | if (cpumask_empty(cpus)) | 1291 | if (cpumask_empty(cpus)) |
1244 | return; /* nothing to do */ | 1292 | return; /* nothing to do */ |
1245 | 1293 | ||
@@ -1275,10 +1323,11 @@ static void set_current_cr3(void *v) | |||
1275 | 1323 | ||
1276 | static void __xen_write_cr3(bool kernel, unsigned long cr3) | 1324 | static void __xen_write_cr3(bool kernel, unsigned long cr3) |
1277 | { | 1325 | { |
1278 | struct mmuext_op *op; | 1326 | struct mmuext_op op; |
1279 | struct multicall_space mcs; | ||
1280 | unsigned long mfn; | 1327 | unsigned long mfn; |
1281 | 1328 | ||
1329 | trace_xen_mmu_write_cr3(kernel, cr3); | ||
1330 | |||
1282 | if (cr3) | 1331 | if (cr3) |
1283 | mfn = pfn_to_mfn(PFN_DOWN(cr3)); | 1332 | mfn = pfn_to_mfn(PFN_DOWN(cr3)); |
1284 | else | 1333 | else |
@@ -1286,13 +1335,10 @@ static void __xen_write_cr3(bool kernel, unsigned long cr3) | |||
1286 | 1335 | ||
1287 | WARN_ON(mfn == 0 && kernel); | 1336 | WARN_ON(mfn == 0 && kernel); |
1288 | 1337 | ||
1289 | mcs = __xen_mc_entry(sizeof(*op)); | 1338 | op.cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR; |
1290 | 1339 | op.arg1.mfn = mfn; | |
1291 | op = mcs.args; | ||
1292 | op->cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR; | ||
1293 | op->arg1.mfn = mfn; | ||
1294 | 1340 | ||
1295 | MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); | 1341 | xen_extend_mmuext_op(&op); |
1296 | 1342 | ||
1297 | if (kernel) { | 1343 | if (kernel) { |
1298 | percpu_write(xen_cr3, cr3); | 1344 | percpu_write(xen_cr3, cr3); |
@@ -1451,19 +1497,52 @@ static void __init xen_release_pmd_init(unsigned long pfn) | |||
1451 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); | 1497 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); |
1452 | } | 1498 | } |
1453 | 1499 | ||
1500 | static inline void __pin_pagetable_pfn(unsigned cmd, unsigned long pfn) | ||
1501 | { | ||
1502 | struct multicall_space mcs; | ||
1503 | struct mmuext_op *op; | ||
1504 | |||
1505 | mcs = __xen_mc_entry(sizeof(*op)); | ||
1506 | op = mcs.args; | ||
1507 | op->cmd = cmd; | ||
1508 | op->arg1.mfn = pfn_to_mfn(pfn); | ||
1509 | |||
1510 | MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF); | ||
1511 | } | ||
1512 | |||
1513 | static inline void __set_pfn_prot(unsigned long pfn, pgprot_t prot) | ||
1514 | { | ||
1515 | struct multicall_space mcs; | ||
1516 | unsigned long addr = (unsigned long)__va(pfn << PAGE_SHIFT); | ||
1517 | |||
1518 | mcs = __xen_mc_entry(0); | ||
1519 | MULTI_update_va_mapping(mcs.mc, (unsigned long)addr, | ||
1520 | pfn_pte(pfn, prot), 0); | ||
1521 | } | ||
1522 | |||
1454 | /* This needs to make sure the new pte page is pinned iff its being | 1523 | /* This needs to make sure the new pte page is pinned iff its being |
1455 | attached to a pinned pagetable. */ | 1524 | attached to a pinned pagetable. */ |
1456 | static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned level) | 1525 | static inline void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, |
1526 | unsigned level) | ||
1457 | { | 1527 | { |
1458 | struct page *page = pfn_to_page(pfn); | 1528 | bool pinned = PagePinned(virt_to_page(mm->pgd)); |
1529 | |||
1530 | trace_xen_mmu_alloc_ptpage(mm, pfn, level, pinned); | ||
1531 | |||
1532 | if (pinned) { | ||
1533 | struct page *page = pfn_to_page(pfn); | ||
1459 | 1534 | ||
1460 | if (PagePinned(virt_to_page(mm->pgd))) { | ||
1461 | SetPagePinned(page); | 1535 | SetPagePinned(page); |
1462 | 1536 | ||
1463 | if (!PageHighMem(page)) { | 1537 | if (!PageHighMem(page)) { |
1464 | make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn))); | 1538 | xen_mc_batch(); |
1539 | |||
1540 | __set_pfn_prot(pfn, PAGE_KERNEL_RO); | ||
1541 | |||
1465 | if (level == PT_PTE && USE_SPLIT_PTLOCKS) | 1542 | if (level == PT_PTE && USE_SPLIT_PTLOCKS) |
1466 | pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); | 1543 | __pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); |
1544 | |||
1545 | xen_mc_issue(PARAVIRT_LAZY_MMU); | ||
1467 | } else { | 1546 | } else { |
1468 | /* make sure there are no stray mappings of | 1547 | /* make sure there are no stray mappings of |
1469 | this page */ | 1548 | this page */ |
@@ -1483,15 +1562,23 @@ static void xen_alloc_pmd(struct mm_struct *mm, unsigned long pfn) | |||
1483 | } | 1562 | } |
1484 | 1563 | ||
1485 | /* This should never happen until we're OK to use struct page */ | 1564 | /* This should never happen until we're OK to use struct page */ |
1486 | static void xen_release_ptpage(unsigned long pfn, unsigned level) | 1565 | static inline void xen_release_ptpage(unsigned long pfn, unsigned level) |
1487 | { | 1566 | { |
1488 | struct page *page = pfn_to_page(pfn); | 1567 | struct page *page = pfn_to_page(pfn); |
1568 | bool pinned = PagePinned(page); | ||
1489 | 1569 | ||
1490 | if (PagePinned(page)) { | 1570 | trace_xen_mmu_release_ptpage(pfn, level, pinned); |
1571 | |||
1572 | if (pinned) { | ||
1491 | if (!PageHighMem(page)) { | 1573 | if (!PageHighMem(page)) { |
1574 | xen_mc_batch(); | ||
1575 | |||
1492 | if (level == PT_PTE && USE_SPLIT_PTLOCKS) | 1576 | if (level == PT_PTE && USE_SPLIT_PTLOCKS) |
1493 | pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); | 1577 | __pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); |
1494 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); | 1578 | |
1579 | __set_pfn_prot(pfn, PAGE_KERNEL); | ||
1580 | |||
1581 | xen_mc_issue(PARAVIRT_LAZY_MMU); | ||
1495 | } | 1582 | } |
1496 | ClearPagePinned(page); | 1583 | ClearPagePinned(page); |
1497 | } | 1584 | } |
@@ -1626,15 +1713,17 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) | |||
1626 | void __init xen_setup_machphys_mapping(void) | 1713 | void __init xen_setup_machphys_mapping(void) |
1627 | { | 1714 | { |
1628 | struct xen_machphys_mapping mapping; | 1715 | struct xen_machphys_mapping mapping; |
1629 | unsigned long machine_to_phys_nr_ents; | ||
1630 | 1716 | ||
1631 | if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { | 1717 | if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { |
1632 | machine_to_phys_mapping = (unsigned long *)mapping.v_start; | 1718 | machine_to_phys_mapping = (unsigned long *)mapping.v_start; |
1633 | machine_to_phys_nr_ents = mapping.max_mfn + 1; | 1719 | machine_to_phys_nr = mapping.max_mfn + 1; |
1634 | } else { | 1720 | } else { |
1635 | machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES; | 1721 | machine_to_phys_nr = MACH2PHYS_NR_ENTRIES; |
1636 | } | 1722 | } |
1637 | machine_to_phys_order = fls(machine_to_phys_nr_ents - 1); | 1723 | #ifdef CONFIG_X86_32 |
1724 | WARN_ON((machine_to_phys_mapping + (machine_to_phys_nr - 1)) | ||
1725 | < machine_to_phys_mapping); | ||
1726 | #endif | ||
1638 | } | 1727 | } |
1639 | 1728 | ||
1640 | #ifdef CONFIG_X86_64 | 1729 | #ifdef CONFIG_X86_64 |
@@ -1829,6 +1918,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) | |||
1829 | # endif | 1918 | # endif |
1830 | #else | 1919 | #else |
1831 | case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE: | 1920 | case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE: |
1921 | case VVAR_PAGE: | ||
1832 | #endif | 1922 | #endif |
1833 | case FIX_TEXT_POKE0: | 1923 | case FIX_TEXT_POKE0: |
1834 | case FIX_TEXT_POKE1: | 1924 | case FIX_TEXT_POKE1: |
@@ -1869,7 +1959,8 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) | |||
1869 | #ifdef CONFIG_X86_64 | 1959 | #ifdef CONFIG_X86_64 |
1870 | /* Replicate changes to map the vsyscall page into the user | 1960 | /* Replicate changes to map the vsyscall page into the user |
1871 | pagetable vsyscall mapping. */ | 1961 | pagetable vsyscall mapping. */ |
1872 | if (idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) { | 1962 | if ((idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) || |
1963 | idx == VVAR_PAGE) { | ||
1873 | unsigned long vaddr = __fix_to_virt(idx); | 1964 | unsigned long vaddr = __fix_to_virt(idx); |
1874 | set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte); | 1965 | set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte); |
1875 | } | 1966 | } |
diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c index 1b2b73ff0a6..0d82003e76a 100644 --- a/arch/x86/xen/multicalls.c +++ b/arch/x86/xen/multicalls.c | |||
@@ -30,12 +30,13 @@ | |||
30 | 30 | ||
31 | #define MC_BATCH 32 | 31 | #define MC_BATCH 32 |
32 | 32 | ||
33 | #define MC_DEBUG 1 | 33 | #define MC_DEBUG 0 |
34 | 34 | ||
35 | #define MC_ARGS (MC_BATCH * 16) | 35 | #define MC_ARGS (MC_BATCH * 16) |
36 | 36 | ||
37 | 37 | ||
38 | struct mc_buffer { | 38 | struct mc_buffer { |
39 | unsigned mcidx, argidx, cbidx; | ||
39 | struct multicall_entry entries[MC_BATCH]; | 40 | struct multicall_entry entries[MC_BATCH]; |
40 | #if MC_DEBUG | 41 | #if MC_DEBUG |
41 | struct multicall_entry debug[MC_BATCH]; | 42 | struct multicall_entry debug[MC_BATCH]; |
@@ -46,85 +47,15 @@ struct mc_buffer { | |||
46 | void (*fn)(void *); | 47 | void (*fn)(void *); |
47 | void *data; | 48 | void *data; |
48 | } callbacks[MC_BATCH]; | 49 | } callbacks[MC_BATCH]; |
49 | unsigned mcidx, argidx, cbidx; | ||
50 | }; | 50 | }; |
51 | 51 | ||
52 | static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); | 52 | static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); |
53 | DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); | 53 | DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); |
54 | 54 | ||
55 | /* flush reasons 0- slots, 1- args, 2- callbacks */ | ||
56 | enum flush_reasons | ||
57 | { | ||
58 | FL_SLOTS, | ||
59 | FL_ARGS, | ||
60 | FL_CALLBACKS, | ||
61 | |||
62 | FL_N_REASONS | ||
63 | }; | ||
64 | |||
65 | #ifdef CONFIG_XEN_DEBUG_FS | ||
66 | #define NHYPERCALLS 40 /* not really */ | ||
67 | |||
68 | static struct { | ||
69 | unsigned histo[MC_BATCH+1]; | ||
70 | |||
71 | unsigned issued; | ||
72 | unsigned arg_total; | ||
73 | unsigned hypercalls; | ||
74 | unsigned histo_hypercalls[NHYPERCALLS]; | ||
75 | |||
76 | unsigned flush[FL_N_REASONS]; | ||
77 | } mc_stats; | ||
78 | |||
79 | static u8 zero_stats; | ||
80 | |||
81 | static inline void check_zero(void) | ||
82 | { | ||
83 | if (unlikely(zero_stats)) { | ||
84 | memset(&mc_stats, 0, sizeof(mc_stats)); | ||
85 | zero_stats = 0; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static void mc_add_stats(const struct mc_buffer *mc) | ||
90 | { | ||
91 | int i; | ||
92 | |||
93 | check_zero(); | ||
94 | |||
95 | mc_stats.issued++; | ||
96 | mc_stats.hypercalls += mc->mcidx; | ||
97 | mc_stats.arg_total += mc->argidx; | ||
98 | |||
99 | mc_stats.histo[mc->mcidx]++; | ||
100 | for(i = 0; i < mc->mcidx; i++) { | ||
101 | unsigned op = mc->entries[i].op; | ||
102 | if (op < NHYPERCALLS) | ||
103 | mc_stats.histo_hypercalls[op]++; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | static void mc_stats_flush(enum flush_reasons idx) | ||
108 | { | ||
109 | check_zero(); | ||
110 | |||
111 | mc_stats.flush[idx]++; | ||
112 | } | ||
113 | |||
114 | #else /* !CONFIG_XEN_DEBUG_FS */ | ||
115 | |||
116 | static inline void mc_add_stats(const struct mc_buffer *mc) | ||
117 | { | ||
118 | } | ||
119 | |||
120 | static inline void mc_stats_flush(enum flush_reasons idx) | ||
121 | { | ||
122 | } | ||
123 | #endif /* CONFIG_XEN_DEBUG_FS */ | ||
124 | |||
125 | void xen_mc_flush(void) | 55 | void xen_mc_flush(void) |
126 | { | 56 | { |
127 | struct mc_buffer *b = &__get_cpu_var(mc_buffer); | 57 | struct mc_buffer *b = &__get_cpu_var(mc_buffer); |
58 | struct multicall_entry *mc; | ||
128 | int ret = 0; | 59 | int ret = 0; |
129 | unsigned long flags; | 60 | unsigned long flags; |
130 | int i; | 61 | int i; |
@@ -135,9 +66,26 @@ void xen_mc_flush(void) | |||
135 | something in the middle */ | 66 | something in the middle */ |
136 | local_irq_save(flags); | 67 | local_irq_save(flags); |
137 | 68 | ||
138 | mc_add_stats(b); | 69 | trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx); |
70 | |||
71 | switch (b->mcidx) { | ||
72 | case 0: | ||
73 | /* no-op */ | ||
74 | BUG_ON(b->argidx != 0); | ||
75 | break; | ||
76 | |||
77 | case 1: | ||
78 | /* Singleton multicall - bypass multicall machinery | ||
79 | and just do the call directly. */ | ||
80 | mc = &b->entries[0]; | ||
81 | |||
82 | mc->result = privcmd_call(mc->op, | ||
83 | mc->args[0], mc->args[1], mc->args[2], | ||
84 | mc->args[3], mc->args[4]); | ||
85 | ret = mc->result < 0; | ||
86 | break; | ||
139 | 87 | ||
140 | if (b->mcidx) { | 88 | default: |
141 | #if MC_DEBUG | 89 | #if MC_DEBUG |
142 | memcpy(b->debug, b->entries, | 90 | memcpy(b->debug, b->entries, |
143 | b->mcidx * sizeof(struct multicall_entry)); | 91 | b->mcidx * sizeof(struct multicall_entry)); |
@@ -164,11 +112,10 @@ void xen_mc_flush(void) | |||
164 | } | 112 | } |
165 | } | 113 | } |
166 | #endif | 114 | #endif |
115 | } | ||
167 | 116 | ||
168 | b->mcidx = 0; | 117 | b->mcidx = 0; |
169 | b->argidx = 0; | 118 | b->argidx = 0; |
170 | } else | ||
171 | BUG_ON(b->argidx != 0); | ||
172 | 119 | ||
173 | for (i = 0; i < b->cbidx; i++) { | 120 | for (i = 0; i < b->cbidx; i++) { |
174 | struct callback *cb = &b->callbacks[i]; | 121 | struct callback *cb = &b->callbacks[i]; |
@@ -188,18 +135,21 @@ struct multicall_space __xen_mc_entry(size_t args) | |||
188 | struct multicall_space ret; | 135 | struct multicall_space ret; |
189 | unsigned argidx = roundup(b->argidx, sizeof(u64)); | 136 | unsigned argidx = roundup(b->argidx, sizeof(u64)); |
190 | 137 | ||
138 | trace_xen_mc_entry_alloc(args); | ||
139 | |||
191 | BUG_ON(preemptible()); | 140 | BUG_ON(preemptible()); |
192 | BUG_ON(b->argidx >= MC_ARGS); | 141 | BUG_ON(b->argidx >= MC_ARGS); |
193 | 142 | ||
194 | if (b->mcidx == MC_BATCH || | 143 | if (unlikely(b->mcidx == MC_BATCH || |
195 | (argidx + args) >= MC_ARGS) { | 144 | (argidx + args) >= MC_ARGS)) { |
196 | mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS); | 145 | trace_xen_mc_flush_reason((b->mcidx == MC_BATCH) ? |
146 | XEN_MC_FL_BATCH : XEN_MC_FL_ARGS); | ||
197 | xen_mc_flush(); | 147 | xen_mc_flush(); |
198 | argidx = roundup(b->argidx, sizeof(u64)); | 148 | argidx = roundup(b->argidx, sizeof(u64)); |
199 | } | 149 | } |
200 | 150 | ||
201 | ret.mc = &b->entries[b->mcidx]; | 151 | ret.mc = &b->entries[b->mcidx]; |
202 | #ifdef MC_DEBUG | 152 | #if MC_DEBUG |
203 | b->caller[b->mcidx] = __builtin_return_address(0); | 153 | b->caller[b->mcidx] = __builtin_return_address(0); |
204 | #endif | 154 | #endif |
205 | b->mcidx++; | 155 | b->mcidx++; |
@@ -218,20 +168,25 @@ struct multicall_space xen_mc_extend_args(unsigned long op, size_t size) | |||
218 | BUG_ON(preemptible()); | 168 | BUG_ON(preemptible()); |
219 | BUG_ON(b->argidx >= MC_ARGS); | 169 | BUG_ON(b->argidx >= MC_ARGS); |
220 | 170 | ||
221 | if (b->mcidx == 0) | 171 | if (unlikely(b->mcidx == 0 || |
222 | return ret; | 172 | b->entries[b->mcidx - 1].op != op)) { |
223 | 173 | trace_xen_mc_extend_args(op, size, XEN_MC_XE_BAD_OP); | |
224 | if (b->entries[b->mcidx - 1].op != op) | 174 | goto out; |
225 | return ret; | 175 | } |
226 | 176 | ||
227 | if ((b->argidx + size) >= MC_ARGS) | 177 | if (unlikely((b->argidx + size) >= MC_ARGS)) { |
228 | return ret; | 178 | trace_xen_mc_extend_args(op, size, XEN_MC_XE_NO_SPACE); |
179 | goto out; | ||
180 | } | ||
229 | 181 | ||
230 | ret.mc = &b->entries[b->mcidx - 1]; | 182 | ret.mc = &b->entries[b->mcidx - 1]; |
231 | ret.args = &b->args[b->argidx]; | 183 | ret.args = &b->args[b->argidx]; |
232 | b->argidx += size; | 184 | b->argidx += size; |
233 | 185 | ||
234 | BUG_ON(b->argidx >= MC_ARGS); | 186 | BUG_ON(b->argidx >= MC_ARGS); |
187 | |||
188 | trace_xen_mc_extend_args(op, size, XEN_MC_XE_OK); | ||
189 | out: | ||
235 | return ret; | 190 | return ret; |
236 | } | 191 | } |
237 | 192 | ||
@@ -241,43 +196,13 @@ void xen_mc_callback(void (*fn)(void *), void *data) | |||
241 | struct callback *cb; | 196 | struct callback *cb; |
242 | 197 | ||
243 | if (b->cbidx == MC_BATCH) { | 198 | if (b->cbidx == MC_BATCH) { |
244 | mc_stats_flush(FL_CALLBACKS); | 199 | trace_xen_mc_flush_reason(XEN_MC_FL_CALLBACK); |
245 | xen_mc_flush(); | 200 | xen_mc_flush(); |
246 | } | 201 | } |
247 | 202 | ||
203 | trace_xen_mc_callback(fn, data); | ||
204 | |||
248 | cb = &b->callbacks[b->cbidx++]; | 205 | cb = &b->callbacks[b->cbidx++]; |
249 | cb->fn = fn; | 206 | cb->fn = fn; |
250 | cb->data = data; | 207 | cb->data = data; |
251 | } | 208 | } |
252 | |||
253 | #ifdef CONFIG_XEN_DEBUG_FS | ||
254 | |||
255 | static struct dentry *d_mc_debug; | ||
256 | |||
257 | static int __init xen_mc_debugfs(void) | ||
258 | { | ||
259 | struct dentry *d_xen = xen_init_debugfs(); | ||
260 | |||
261 | if (d_xen == NULL) | ||
262 | return -ENOMEM; | ||
263 | |||
264 | d_mc_debug = debugfs_create_dir("multicalls", d_xen); | ||
265 | |||
266 | debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats); | ||
267 | |||
268 | debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued); | ||
269 | debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls); | ||
270 | debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total); | ||
271 | |||
272 | xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug, | ||
273 | mc_stats.histo, MC_BATCH); | ||
274 | xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug, | ||
275 | mc_stats.histo_hypercalls, NHYPERCALLS); | ||
276 | xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug, | ||
277 | mc_stats.flush, FL_N_REASONS); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | fs_initcall(xen_mc_debugfs); | ||
282 | |||
283 | #endif /* CONFIG_XEN_DEBUG_FS */ | ||
diff --git a/arch/x86/xen/multicalls.h b/arch/x86/xen/multicalls.h index 4ec8035e321..dee79b78a90 100644 --- a/arch/x86/xen/multicalls.h +++ b/arch/x86/xen/multicalls.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef _XEN_MULTICALLS_H | 1 | #ifndef _XEN_MULTICALLS_H |
2 | #define _XEN_MULTICALLS_H | 2 | #define _XEN_MULTICALLS_H |
3 | 3 | ||
4 | #include <trace/events/xen.h> | ||
5 | |||
4 | #include "xen-ops.h" | 6 | #include "xen-ops.h" |
5 | 7 | ||
6 | /* Multicalls */ | 8 | /* Multicalls */ |
@@ -20,8 +22,10 @@ DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags); | |||
20 | static inline void xen_mc_batch(void) | 22 | static inline void xen_mc_batch(void) |
21 | { | 23 | { |
22 | unsigned long flags; | 24 | unsigned long flags; |
25 | |||
23 | /* need to disable interrupts until this entry is complete */ | 26 | /* need to disable interrupts until this entry is complete */ |
24 | local_irq_save(flags); | 27 | local_irq_save(flags); |
28 | trace_xen_mc_batch(paravirt_get_lazy_mode()); | ||
25 | __this_cpu_write(xen_mc_irq_flags, flags); | 29 | __this_cpu_write(xen_mc_irq_flags, flags); |
26 | } | 30 | } |
27 | 31 | ||
@@ -37,6 +41,8 @@ void xen_mc_flush(void); | |||
37 | /* Issue a multicall if we're not in a lazy mode */ | 41 | /* Issue a multicall if we're not in a lazy mode */ |
38 | static inline void xen_mc_issue(unsigned mode) | 42 | static inline void xen_mc_issue(unsigned mode) |
39 | { | 43 | { |
44 | trace_xen_mc_issue(mode); | ||
45 | |||
40 | if ((paravirt_get_lazy_mode() & mode) == 0) | 46 | if ((paravirt_get_lazy_mode() & mode) == 0) |
41 | xen_mc_flush(); | 47 | xen_mc_flush(); |
42 | 48 | ||
diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index 25c52f94a27..ffcf2615640 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c | |||
@@ -35,7 +35,7 @@ EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); | |||
35 | #ifdef CONFIG_XEN_PVHVM | 35 | #ifdef CONFIG_XEN_PVHVM |
36 | static int xen_emul_unplug; | 36 | static int xen_emul_unplug; |
37 | 37 | ||
38 | static int __init check_platform_magic(void) | 38 | static int check_platform_magic(void) |
39 | { | 39 | { |
40 | short magic; | 40 | short magic; |
41 | char protocol; | 41 | char protocol; |
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 60aeeb56948..e1913024687 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
10 | #include <linux/pm.h> | 10 | #include <linux/pm.h> |
11 | #include <linux/memblock.h> | 11 | #include <linux/memblock.h> |
12 | #include <linux/cpuidle.h> | ||
12 | 13 | ||
13 | #include <asm/elf.h> | 14 | #include <asm/elf.h> |
14 | #include <asm/vdso.h> | 15 | #include <asm/vdso.h> |
@@ -92,8 +93,6 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr, | |||
92 | if (end <= start) | 93 | if (end <= start) |
93 | return 0; | 94 | return 0; |
94 | 95 | ||
95 | printk(KERN_INFO "xen_release_chunk: looking at area pfn %lx-%lx: ", | ||
96 | start, end); | ||
97 | for(pfn = start; pfn < end; pfn++) { | 96 | for(pfn = start; pfn < end; pfn++) { |
98 | unsigned long mfn = pfn_to_mfn(pfn); | 97 | unsigned long mfn = pfn_to_mfn(pfn); |
99 | 98 | ||
@@ -106,14 +105,14 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr, | |||
106 | 105 | ||
107 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, | 106 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, |
108 | &reservation); | 107 | &reservation); |
109 | WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n", | 108 | WARN(ret != 1, "Failed to release pfn %lx err=%d\n", pfn, ret); |
110 | start, end, ret); | ||
111 | if (ret == 1) { | 109 | if (ret == 1) { |
112 | __set_phys_to_machine(pfn, INVALID_P2M_ENTRY); | 110 | __set_phys_to_machine(pfn, INVALID_P2M_ENTRY); |
113 | len++; | 111 | len++; |
114 | } | 112 | } |
115 | } | 113 | } |
116 | printk(KERN_CONT "%ld pages freed\n", len); | 114 | printk(KERN_INFO "Freeing %lx-%lx pfn range: %lu pages freed\n", |
115 | start, end, len); | ||
117 | 116 | ||
118 | return len; | 117 | return len; |
119 | } | 118 | } |
@@ -139,7 +138,7 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn, | |||
139 | if (last_end < max_addr) | 138 | if (last_end < max_addr) |
140 | released += xen_release_chunk(last_end, max_addr); | 139 | released += xen_release_chunk(last_end, max_addr); |
141 | 140 | ||
142 | printk(KERN_INFO "released %ld pages of unused memory\n", released); | 141 | printk(KERN_INFO "released %lu pages of unused memory\n", released); |
143 | return released; | 142 | return released; |
144 | } | 143 | } |
145 | 144 | ||
@@ -185,6 +184,31 @@ static unsigned long __init xen_set_identity(const struct e820entry *list, | |||
185 | PFN_UP(start_pci), PFN_DOWN(last)); | 184 | PFN_UP(start_pci), PFN_DOWN(last)); |
186 | return identity; | 185 | return identity; |
187 | } | 186 | } |
187 | |||
188 | static unsigned long __init xen_get_max_pages(void) | ||
189 | { | ||
190 | unsigned long max_pages = MAX_DOMAIN_PAGES; | ||
191 | domid_t domid = DOMID_SELF; | ||
192 | int ret; | ||
193 | |||
194 | /* | ||
195 | * For the initial domain we use the maximum reservation as | ||
196 | * the maximum page. | ||
197 | * | ||
198 | * For guest domains the current maximum reservation reflects | ||
199 | * the current maximum rather than the static maximum. In this | ||
200 | * case the e820 map provided to us will cover the static | ||
201 | * maximum region. | ||
202 | */ | ||
203 | if (xen_initial_domain()) { | ||
204 | ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid); | ||
205 | if (ret > 0) | ||
206 | max_pages = ret; | ||
207 | } | ||
208 | |||
209 | return min(max_pages, MAX_DOMAIN_PAGES); | ||
210 | } | ||
211 | |||
188 | /** | 212 | /** |
189 | * machine_specific_memory_setup - Hook for machine specific memory setup. | 213 | * machine_specific_memory_setup - Hook for machine specific memory setup. |
190 | **/ | 214 | **/ |
@@ -293,6 +317,14 @@ char * __init xen_memory_setup(void) | |||
293 | 317 | ||
294 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | 318 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); |
295 | 319 | ||
320 | extra_limit = xen_get_max_pages(); | ||
321 | if (max_pfn + extra_pages > extra_limit) { | ||
322 | if (extra_limit > max_pfn) | ||
323 | extra_pages = extra_limit - max_pfn; | ||
324 | else | ||
325 | extra_pages = 0; | ||
326 | } | ||
327 | |||
296 | extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820); | 328 | extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820); |
297 | 329 | ||
298 | /* | 330 | /* |
@@ -426,8 +458,8 @@ void __init xen_arch_setup(void) | |||
426 | #ifdef CONFIG_X86_32 | 458 | #ifdef CONFIG_X86_32 |
427 | boot_cpu_data.hlt_works_ok = 1; | 459 | boot_cpu_data.hlt_works_ok = 1; |
428 | #endif | 460 | #endif |
429 | pm_idle = default_idle; | 461 | disable_cpuidle(); |
430 | boot_option_idle_override = IDLE_HALT; | 462 | boot_option_idle_override = IDLE_HALT; |
431 | 463 | WARN_ON(set_pm_idle_to_default()); | |
432 | fiddle_vdso(); | 464 | fiddle_vdso(); |
433 | } | 465 | } |
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index b4533a86d7e..041d4fe9dfe 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <xen/page.h> | 32 | #include <xen/page.h> |
33 | #include <xen/events.h> | 33 | #include <xen/events.h> |
34 | 34 | ||
35 | #include <xen/hvc-console.h> | ||
35 | #include "xen-ops.h" | 36 | #include "xen-ops.h" |
36 | #include "mmu.h" | 37 | #include "mmu.h" |
37 | 38 | ||
@@ -207,6 +208,15 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus) | |||
207 | unsigned cpu; | 208 | unsigned cpu; |
208 | unsigned int i; | 209 | unsigned int i; |
209 | 210 | ||
211 | if (skip_ioapic_setup) { | ||
212 | char *m = (max_cpus == 0) ? | ||
213 | "The nosmp parameter is incompatible with Xen; " \ | ||
214 | "use Xen dom0_max_vcpus=1 parameter" : | ||
215 | "The noapic parameter is incompatible with Xen"; | ||
216 | |||
217 | xen_raw_printk(m); | ||
218 | panic(m); | ||
219 | } | ||
210 | xen_init_lock_cpu(0); | 220 | xen_init_lock_cpu(0); |
211 | 221 | ||
212 | smp_store_cpu_info(0); | 222 | smp_store_cpu_info(0); |
@@ -521,10 +531,7 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus) | |||
521 | native_smp_prepare_cpus(max_cpus); | 531 | native_smp_prepare_cpus(max_cpus); |
522 | WARN_ON(xen_smp_intr_init(0)); | 532 | WARN_ON(xen_smp_intr_init(0)); |
523 | 533 | ||
524 | if (!xen_have_vector_callback) | ||
525 | return; | ||
526 | xen_init_lock_cpu(0); | 534 | xen_init_lock_cpu(0); |
527 | xen_init_spinlocks(); | ||
528 | } | 535 | } |
529 | 536 | ||
530 | static int __cpuinit xen_hvm_cpu_up(unsigned int cpu) | 537 | static int __cpuinit xen_hvm_cpu_up(unsigned int cpu) |
@@ -546,6 +553,8 @@ static void xen_hvm_cpu_die(unsigned int cpu) | |||
546 | 553 | ||
547 | void __init xen_hvm_smp_init(void) | 554 | void __init xen_hvm_smp_init(void) |
548 | { | 555 | { |
556 | if (!xen_have_vector_callback) | ||
557 | return; | ||
549 | smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus; | 558 | smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus; |
550 | smp_ops.smp_send_reschedule = xen_smp_send_reschedule; | 559 | smp_ops.smp_send_reschedule = xen_smp_send_reschedule; |
551 | smp_ops.cpu_up = xen_hvm_cpu_up; | 560 | smp_ops.cpu_up = xen_hvm_cpu_up; |
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 5158c505bef..163b4679556 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c | |||
@@ -168,9 +168,10 @@ cycle_t xen_clocksource_read(void) | |||
168 | struct pvclock_vcpu_time_info *src; | 168 | struct pvclock_vcpu_time_info *src; |
169 | cycle_t ret; | 169 | cycle_t ret; |
170 | 170 | ||
171 | src = &get_cpu_var(xen_vcpu)->time; | 171 | preempt_disable_notrace(); |
172 | src = &__get_cpu_var(xen_vcpu)->time; | ||
172 | ret = pvclock_clocksource_read(src); | 173 | ret = pvclock_clocksource_read(src); |
173 | put_cpu_var(xen_vcpu); | 174 | preempt_enable_notrace(); |
174 | return ret; | 175 | return ret; |
175 | } | 176 | } |
176 | 177 | ||
diff --git a/arch/x86/xen/trace.c b/arch/x86/xen/trace.c new file mode 100644 index 00000000000..520022d1a18 --- /dev/null +++ b/arch/x86/xen/trace.c | |||
@@ -0,0 +1,62 @@ | |||
1 | #include <linux/ftrace.h> | ||
2 | #include <xen/interface/xen.h> | ||
3 | |||
4 | #define N(x) [__HYPERVISOR_##x] = "("#x")" | ||
5 | static const char *xen_hypercall_names[] = { | ||
6 | N(set_trap_table), | ||
7 | N(mmu_update), | ||
8 | N(set_gdt), | ||
9 | N(stack_switch), | ||
10 | N(set_callbacks), | ||
11 | N(fpu_taskswitch), | ||
12 | N(sched_op_compat), | ||
13 | N(dom0_op), | ||
14 | N(set_debugreg), | ||
15 | N(get_debugreg), | ||
16 | N(update_descriptor), | ||
17 | N(memory_op), | ||
18 | N(multicall), | ||
19 | N(update_va_mapping), | ||
20 | N(set_timer_op), | ||
21 | N(event_channel_op_compat), | ||
22 | N(xen_version), | ||
23 | N(console_io), | ||
24 | N(physdev_op_compat), | ||
25 | N(grant_table_op), | ||
26 | N(vm_assist), | ||
27 | N(update_va_mapping_otherdomain), | ||
28 | N(iret), | ||
29 | N(vcpu_op), | ||
30 | N(set_segment_base), | ||
31 | N(mmuext_op), | ||
32 | N(acm_op), | ||
33 | N(nmi_op), | ||
34 | N(sched_op), | ||
35 | N(callback_op), | ||
36 | N(xenoprof_op), | ||
37 | N(event_channel_op), | ||
38 | N(physdev_op), | ||
39 | N(hvm_op), | ||
40 | |||
41 | /* Architecture-specific hypercall definitions. */ | ||
42 | N(arch_0), | ||
43 | N(arch_1), | ||
44 | N(arch_2), | ||
45 | N(arch_3), | ||
46 | N(arch_4), | ||
47 | N(arch_5), | ||
48 | N(arch_6), | ||
49 | N(arch_7), | ||
50 | }; | ||
51 | #undef N | ||
52 | |||
53 | static const char *xen_hypercall_name(unsigned op) | ||
54 | { | ||
55 | if (op < ARRAY_SIZE(xen_hypercall_names) && xen_hypercall_names[op] != NULL) | ||
56 | return xen_hypercall_names[op]; | ||
57 | |||
58 | return ""; | ||
59 | } | ||
60 | |||
61 | #define CREATE_TRACE_POINTS | ||
62 | #include <trace/events/xen.h> | ||
diff --git a/arch/x86/xen/vga.c b/arch/x86/xen/vga.c new file mode 100644 index 00000000000..1cd7f4d11e2 --- /dev/null +++ b/arch/x86/xen/vga.c | |||
@@ -0,0 +1,67 @@ | |||
1 | #include <linux/screen_info.h> | ||
2 | #include <linux/init.h> | ||
3 | |||
4 | #include <asm/bootparam.h> | ||
5 | #include <asm/setup.h> | ||
6 | |||
7 | #include <xen/interface/xen.h> | ||
8 | |||
9 | #include "xen-ops.h" | ||
10 | |||
11 | void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size) | ||
12 | { | ||
13 | struct screen_info *screen_info = &boot_params.screen_info; | ||
14 | |||
15 | /* This is drawn from a dump from vgacon:startup in | ||
16 | * standard Linux. */ | ||
17 | screen_info->orig_video_mode = 3; | ||
18 | screen_info->orig_video_isVGA = 1; | ||
19 | screen_info->orig_video_lines = 25; | ||
20 | screen_info->orig_video_cols = 80; | ||
21 | screen_info->orig_video_ega_bx = 3; | ||
22 | screen_info->orig_video_points = 16; | ||
23 | screen_info->orig_y = screen_info->orig_video_lines - 1; | ||
24 | |||
25 | switch (info->video_type) { | ||
26 | case XEN_VGATYPE_TEXT_MODE_3: | ||
27 | if (size < offsetof(struct dom0_vga_console_info, u.text_mode_3) | ||
28 | + sizeof(info->u.text_mode_3)) | ||
29 | break; | ||
30 | screen_info->orig_video_lines = info->u.text_mode_3.rows; | ||
31 | screen_info->orig_video_cols = info->u.text_mode_3.columns; | ||
32 | screen_info->orig_x = info->u.text_mode_3.cursor_x; | ||
33 | screen_info->orig_y = info->u.text_mode_3.cursor_y; | ||
34 | screen_info->orig_video_points = | ||
35 | info->u.text_mode_3.font_height; | ||
36 | break; | ||
37 | |||
38 | case XEN_VGATYPE_VESA_LFB: | ||
39 | if (size < offsetof(struct dom0_vga_console_info, | ||
40 | u.vesa_lfb.gbl_caps)) | ||
41 | break; | ||
42 | screen_info->orig_video_isVGA = VIDEO_TYPE_VLFB; | ||
43 | screen_info->lfb_width = info->u.vesa_lfb.width; | ||
44 | screen_info->lfb_height = info->u.vesa_lfb.height; | ||
45 | screen_info->lfb_depth = info->u.vesa_lfb.bits_per_pixel; | ||
46 | screen_info->lfb_base = info->u.vesa_lfb.lfb_base; | ||
47 | screen_info->lfb_size = info->u.vesa_lfb.lfb_size; | ||
48 | screen_info->lfb_linelength = info->u.vesa_lfb.bytes_per_line; | ||
49 | screen_info->red_size = info->u.vesa_lfb.red_size; | ||
50 | screen_info->red_pos = info->u.vesa_lfb.red_pos; | ||
51 | screen_info->green_size = info->u.vesa_lfb.green_size; | ||
52 | screen_info->green_pos = info->u.vesa_lfb.green_pos; | ||
53 | screen_info->blue_size = info->u.vesa_lfb.blue_size; | ||
54 | screen_info->blue_pos = info->u.vesa_lfb.blue_pos; | ||
55 | screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size; | ||
56 | screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos; | ||
57 | if (size >= offsetof(struct dom0_vga_console_info, | ||
58 | u.vesa_lfb.gbl_caps) | ||
59 | + sizeof(info->u.vesa_lfb.gbl_caps)) | ||
60 | screen_info->capabilities = info->u.vesa_lfb.gbl_caps; | ||
61 | if (size >= offsetof(struct dom0_vga_console_info, | ||
62 | u.vesa_lfb.mode_attrs) | ||
63 | + sizeof(info->u.vesa_lfb.mode_attrs)) | ||
64 | screen_info->vesa_attributes = info->u.vesa_lfb.mode_attrs; | ||
65 | break; | ||
66 | } | ||
67 | } | ||
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S index 22a2093b586..b040b0e518c 100644 --- a/arch/x86/xen/xen-asm_32.S +++ b/arch/x86/xen/xen-asm_32.S | |||
@@ -113,11 +113,13 @@ xen_iret_start_crit: | |||
113 | 113 | ||
114 | /* | 114 | /* |
115 | * If there's something pending, mask events again so we can | 115 | * If there's something pending, mask events again so we can |
116 | * jump back into xen_hypervisor_callback | 116 | * jump back into xen_hypervisor_callback. Otherwise do not |
117 | * touch XEN_vcpu_info_mask. | ||
117 | */ | 118 | */ |
118 | sete XEN_vcpu_info_mask(%eax) | 119 | jne 1f |
120 | movb $1, XEN_vcpu_info_mask(%eax) | ||
119 | 121 | ||
120 | popl %eax | 122 | 1: popl %eax |
121 | 123 | ||
122 | /* | 124 | /* |
123 | * From this point on the registers are restored and the stack | 125 | * From this point on the registers are restored and the stack |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 97dfdc8757b..b095739ccd4 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -88,6 +88,17 @@ static inline void xen_uninit_lock_cpu(int cpu) | |||
88 | } | 88 | } |
89 | #endif | 89 | #endif |
90 | 90 | ||
91 | struct dom0_vga_console_info; | ||
92 | |||
93 | #ifdef CONFIG_XEN_DOM0 | ||
94 | void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size); | ||
95 | #else | ||
96 | static inline void __init xen_init_vga(const struct dom0_vga_console_info *info, | ||
97 | size_t size) | ||
98 | { | ||
99 | } | ||
100 | #endif | ||
101 | |||
91 | /* Declare an asm function, along with symbols needed to make it | 102 | /* Declare an asm function, along with symbols needed to make it |
92 | inlineable */ | 103 | inlineable */ |
93 | #define DECL_ASM(ret, name, ...) \ | 104 | #define DECL_ASM(ret, name, ...) \ |