Merge branch 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Aug 2011 03:46:24 +0000 (20:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Aug 2011 03:46:24 +0000 (20:46 -0700)
* 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-tip:
  x86-64: Rework vsyscall emulation and add vsyscall= parameter
  x86-64: Wire up getcpu syscall
  x86: Remove unnecessary compile flag tweaks for vsyscall code
  x86-64: Add vsyscall:emulate_vsyscall trace event
  x86-64: Add user_64bit_mode paravirt op
  x86-64, xen: Enable the vvar mapping
  x86-64: Work around gold bug 13023
  x86-64: Move the "user" vsyscall segment out of the data segment.
  x86-64: Pad vDSO to a page boundary

1  2 
Documentation/kernel-parameters.txt
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/paravirt_types.h
arch/x86/kernel/Makefile
arch/x86/kernel/entry_64.S
arch/x86/kernel/paravirt.c
arch/x86/kernel/traps.c
arch/x86/mm/fault.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c

@@@ -163,11 -163,6 +163,11 @@@ bytes respectively. Such letter suffixe
  
                        See also Documentation/power/pm.txt, pci=noacpi
  
 +      acpi_rsdp=      [ACPI,EFI,KEXEC]
 +                      Pass the RSDP address to the kernel, mostly used
 +                      on machines running EFI runtime service to boot the
 +                      second kernel for kdump.
 +
        acpi_apic_instance=     [ACPI, IOAPIC]
                        Format: <int>
                        2: use 2nd APIC table, if available
                        /proc/<pid>/coredump_filter.
                        See also Documentation/filesystems/proc.txt.
  
 +      cpuidle.off=1   [CPU_IDLE]
 +                      disable the cpuidle sub-system
 +
        cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver
                        Format:
                        <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
                        for all guests.
                        Default is 1 (enabled) if in 64bit or 32bit-PAE mode
  
 -      kvm-intel.bypass_guest_pf=
 -                      [KVM,Intel] Disables bypassing of guest page faults
 -                      on Intel chips. Default is 1 (enabled)
 -
        kvm-intel.ept=  [KVM,Intel] Disable extended page tables
                        (virtualized MMU) support on capable Intel chips.
                        Default is 1 (enabled)
        no-kvmapf       [X86,KVM] Disable paravirtualized asynchronous page
                        fault handling.
  
 +      no-steal-acc    [X86,KVM] Disable paravirtualized steal time accounting.
 +                      steal time is computed, but won't influence scheduler
 +                      behaviour
 +
        nolapic         [X86-32,APIC] Do not enable or use the local APIC.
  
        nolapic_timer   [X86-32,APIC] Do not use the local APIC timer.
                        See Documentation/sound/oss/oss-parameters.txt
  
        panic=          [KNL] Kernel behaviour on panic: delay <timeout>
 -                      seconds before rebooting
 +                      timeout > 0: seconds before rebooting
 +                      timeout = 0: wait forever
 +                      timeout < 0: reboot immediately
                        Format: <timeout>
  
        parkbd.port=    [HW] Parallel port number the keyboard adapter is
                        [HW,MOUSE] Controls Logitech smartscroll autorepeat.
                        0 = disabled, 1 = enabled (default).
  
 +      pstore.backend= Specify the name of the pstore backend to use
 +
        pt.             [PARIDE]
                        See Documentation/blockdev/paride.txt.
  
        ro              [KNL] Mount root device read-only on boot
  
        root=           [KNL] Root filesystem
 +                      See name_to_dev_t comment in init/do_mounts.c.
  
        rootdelay=      [KNL] Delay (in seconds) to pause before attempting to
                        mount the root filesystem
                        <port#>,<js1>,<js2>,<js3>,<js4>,<js5>,<js6>,<js7>
                        See also Documentation/input/joystick-parport.txt
  
 +      udbg-immortal   [PPC] When debugging early kernel crashes that
 +                      happen after console_init() and before a proper 
 +                      console driver takes over, this boot options might
 +                      help "seeing" what's going on.
 +
        uhash_entries=  [KNL,NET]
                        Set number of hash buckets for UDP/UDP-Lite connections
  
        unknown_nmi_panic
                        [X86] Cause panic on unknown NMI.
  
 +      usbcore.authorized_default=
 +                      [USB] Default USB device authorization:
 +                      (default -1 = authorized except for wireless USB,
 +                      0 = not authorized, 1 = authorized)
 +
        usbcore.autosuspend=
                        [USB] The autosuspend time delay (in seconds) used
                        for newly-detected USB devices (default 2).  This
        vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
                        Format: <command>
  
+       vsyscall=       [X86-64]
+                       Controls the behavior of vsyscalls (i.e. calls to
+                       fixed addresses of 0xffffffffff600x00 from legacy
+                       code).  Most statically-linked binaries and older
+                       versions of glibc use these calls.  Because these
+                       functions are at fixed addresses, they make nice
+                       targets for exploits that can control RIP.
+                       emulate     [default] Vsyscalls turn into traps and are
+                                   emulated reasonably safely.
+                       native      Vsyscalls are native syscall instructions.
+                                   This is a little bit faster than trapping
+                                   and makes a few dynamic recompilers work
+                                   better than they would in emulation mode.
+                                   It also makes exploits much easier to write.
+                       none        Vsyscalls don't work at all.  This makes
+                                   them quite hard to use for exploits but
+                                   might break your system.
        vt.cur_default= [VT] Default cursor shape.
                        Format: 0xCCBBAA, where AA, BB, and CC are the same as
                        the parameters of the <Esc>[?A;B;Cc escape sequence;
@@@ -17,7 -17,6 +17,6 @@@
   *  Vectors   0 ...  31 : system traps and exceptions - hardcoded events
   *  Vectors  32 ... 127 : device interrupts
   *  Vector  128         : legacy int80 syscall interface
-  *  Vector  204         : legacy x86_64 vsyscall emulation
   *  Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts
   *  Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts
   *
@@@ -51,9 -50,6 +50,6 @@@
  #ifdef CONFIG_X86_32
  # define SYSCALL_VECTOR                       0x80
  #endif
- #ifdef CONFIG_X86_64
- # define VSYSCALL_EMU_VECTOR          0xcc
- #endif
  
  /*
   * Vectors 0x30-0x3f are used for ISA interrupts.
  
  #define UV_BAU_MESSAGE                        0xf5
  
 -/*
 - * Self IPI vector for machine checks
 - */
 -#define MCE_SELF_VECTOR                       0xf4
 -
  /* Xen vector callback to receive events in a HVM domain */
  #define XEN_HVM_EVTCHN_CALLBACK               0xf3
  
@@@ -41,6 -41,7 +41,7 @@@
  
  #include <asm/desc_defs.h>
  #include <asm/kmap_types.h>
+ #include <asm/pgtable_types.h>
  
  struct page;
  struct thread_struct;
@@@ -63,6 -64,11 +64,11 @@@ struct paravirt_callee_save 
  struct pv_info {
        unsigned int kernel_rpl;
        int shared_kernel_pmd;
+ #ifdef CONFIG_X86_64
+       u16 extra_user_64bit_cs;  /* __USER_CS if none */
+ #endif
        int paravirt_enabled;
        const char *name;
  };
@@@ -89,7 -95,6 +95,7 @@@ struct pv_lazy_ops 
  
  struct pv_time_ops {
        unsigned long long (*sched_clock)(void);
 +      unsigned long long (*steal_clock)(int cpu);
        unsigned long (*get_tsc_khz)(void);
  };
  
diff --combined arch/x86/kernel/Makefile
@@@ -17,19 -17,6 +17,6 @@@ CFLAGS_REMOVE_ftrace.o = -p
  CFLAGS_REMOVE_early_printk.o = -pg
  endif
  
- #
- # vsyscalls (which work on the user stack) should have
- # no stack-protector checks:
- #
- nostackp := $(call cc-option, -fno-stack-protector)
- CFLAGS_vsyscall_64.o  := $(PROFILING) -g0 $(nostackp)
- CFLAGS_hpet.o         := $(nostackp)
- CFLAGS_paravirt.o     := $(nostackp)
- GCOV_PROFILE_vsyscall_64.o    := n
- GCOV_PROFILE_hpet.o           := n
- GCOV_PROFILE_tsc.o            := n
- GCOV_PROFILE_paravirt.o               := n
  obj-y                 := process_$(BITS).o signal.o entry_$(BITS).o
  obj-y                 += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
  obj-y                 += time.o ioport.o ldt.o dumpstack.o
@@@ -119,6 -106,7 +106,6 @@@ ifeq ($(CONFIG_X86_64),y
  
        obj-$(CONFIG_GART_IOMMU)        += amd_gart_64.o aperture_64.o
        obj-$(CONFIG_CALGARY_IOMMU)     += pci-calgary_64.o tce_64.o
 -      obj-$(CONFIG_AMD_IOMMU)         += amd_iommu_init.o amd_iommu.o
  
        obj-$(CONFIG_PCI_MMCONFIG)      += mmconf-fam10h_64.o
        obj-y                           += vsmp_64.o
@@@ -299,26 -299,27 +299,26 @@@ ENDPROC(native_usergs_sysret64
        .endm
  
  /* save partial stack frame */
 -      .pushsection .kprobes.text, "ax"
 -ENTRY(save_args)
 -      XCPT_FRAME
 +      .macro SAVE_ARGS_IRQ
        cld
 -      /*
 -       * start from rbp in pt_regs and jump over
 -       * return address.
 -       */
 -      movq_cfi rdi, RDI+8-RBP
 -      movq_cfi rsi, RSI+8-RBP
 -      movq_cfi rdx, RDX+8-RBP
 -      movq_cfi rcx, RCX+8-RBP
 -      movq_cfi rax, RAX+8-RBP
 -      movq_cfi  r8,  R8+8-RBP
 -      movq_cfi  r9,  R9+8-RBP
 -      movq_cfi r10, R10+8-RBP
 -      movq_cfi r11, R11+8-RBP
 -
 -      leaq -RBP+8(%rsp),%rdi  /* arg1 for handler */
 -      movq_cfi rbp, 8         /* push %rbp */
 -      leaq 8(%rsp), %rbp              /* mov %rsp, %ebp */
 +      /* start from rbp in pt_regs and jump over */
 +      movq_cfi rdi, RDI-RBP
 +      movq_cfi rsi, RSI-RBP
 +      movq_cfi rdx, RDX-RBP
 +      movq_cfi rcx, RCX-RBP
 +      movq_cfi rax, RAX-RBP
 +      movq_cfi  r8,  R8-RBP
 +      movq_cfi  r9,  R9-RBP
 +      movq_cfi r10, R10-RBP
 +      movq_cfi r11, R11-RBP
 +
 +      /* Save rbp so that we can unwind from get_irq_regs() */
 +      movq_cfi rbp, 0
 +
 +      /* Save previous stack value */
 +      movq %rsp, %rsi
 +
 +      leaq -RBP(%rsp),%rdi    /* arg1 for handler */
        testl $3, CS(%rdi)
        je 1f
        SWAPGS
         */
  1:    incl PER_CPU_VAR(irq_count)
        jne 2f
 -      popq_cfi %rax                   /* move return address... */
        mov PER_CPU_VAR(irq_stack_ptr),%rsp
        EMPTY_FRAME 0
 -      pushq_cfi %rbp                  /* backlink for unwinder */
 -      pushq_cfi %rax                  /* ... to the new stack */
 -      /*
 -       * We entered an interrupt context - irqs are off:
 -       */
 -2:    TRACE_IRQS_OFF
 -      ret
 -      CFI_ENDPROC
 -END(save_args)
 -      .popsection
 +
 +2:    /* Store previous stack value */
 +      pushq %rsi
 +      /* We entered an interrupt context - irqs are off: */
 +      TRACE_IRQS_OFF
 +      .endm
  
  ENTRY(save_rest)
        PARTIAL_FRAME 1 REST_SKIP+8
@@@ -469,7 -475,7 +469,7 @@@ ENTRY(system_call_after_swapgs
         * and short:
         */
        ENABLE_INTERRUPTS(CLBR_NONE)
 -      SAVE_ARGS 8,1
 +      SAVE_ARGS 8,0
        movq  %rax,ORIG_RAX-ARGOFFSET(%rsp)
        movq  %rcx,RIP-ARGOFFSET(%rsp)
        CFI_REL_OFFSET rip,RIP-ARGOFFSET
@@@ -504,7 -510,7 +504,7 @@@ sysret_check
        TRACE_IRQS_ON
        movq RIP-ARGOFFSET(%rsp),%rcx
        CFI_REGISTER    rip,rcx
 -      RESTORE_ARGS 0,-ARG_SKIP,1
 +      RESTORE_ARGS 1,-ARG_SKIP,0
        /*CFI_REGISTER  rflags,r11*/
        movq    PER_CPU_VAR(old_rsp), %rsp
        USERGS_SYSRET64
@@@ -787,7 -793,7 +787,7 @@@ END(interrupt
        /* reserve pt_regs for scratch regs and rbp */
        subq $ORIG_RAX-RBP, %rsp
        CFI_ADJUST_CFA_OFFSET ORIG_RAX-RBP
 -      call save_args
 +      SAVE_ARGS_IRQ
        PARTIAL_FRAME 0
        call \func
        .endm
@@@ -810,14 -816,15 +810,14 @@@ ret_from_intr
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
        decl PER_CPU_VAR(irq_count)
 -      leaveq
  
 -      CFI_RESTORE             rbp
 +      /* Restore saved previous stack */
 +      popq %rsi
 +      leaq 16(%rsi), %rsp
 +
        CFI_DEF_CFA_REGISTER    rsp
 -      CFI_ADJUST_CFA_OFFSET   -8
 +      CFI_ADJUST_CFA_OFFSET   -16
  
 -      /* we did not save rbx, restore only from ARGOFFSET */
 -      addq $8, %rsp
 -      CFI_ADJUST_CFA_OFFSET   -8
  exit_intr:
        GET_THREAD_INFO(%rcx)
        testl $3,CS-ARGOFFSET(%rsp)
@@@ -853,7 -860,7 +853,7 @@@ retint_restore_args:       /* return to kerne
         */
        TRACE_IRQS_IRETQ
  restore_args:
 -      RESTORE_ARGS 0,8,0
 +      RESTORE_ARGS 1,8,1
  
  irq_return:
        INTERRUPT_RETURN
@@@ -986,6 -993,11 +986,6 @@@ apicinterrupt THRESHOLD_APIC_VECTOR 
  apicinterrupt THERMAL_APIC_VECTOR \
        thermal_interrupt smp_thermal_interrupt
  
 -#ifdef CONFIG_X86_MCE
 -apicinterrupt MCE_SELF_VECTOR \
 -      mce_self_interrupt smp_mce_self_interrupt
 -#endif
 -
  #ifdef CONFIG_SMP
  apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
        call_function_single_interrupt smp_call_function_single_interrupt
@@@ -1111,7 -1123,6 +1111,6 @@@ zeroentry spurious_interrupt_bug do_spu
  zeroentry coprocessor_error do_coprocessor_error
  errorentry alignment_check do_alignment_check
  zeroentry simd_coprocessor_error do_simd_coprocessor_error
- zeroentry emulate_vsyscall do_emulate_vsyscall
  
  
        /* Reload gs selector with exception handling */
@@@ -202,14 -202,6 +202,14 @@@ static void native_flush_tlb_single(uns
        __native_flush_tlb_single(addr);
  }
  
 +struct jump_label_key paravirt_steal_enabled;
 +struct jump_label_key paravirt_steal_rq_enabled;
 +
 +static u64 native_steal_clock(int cpu)
 +{
 +      return 0;
 +}
 +
  /* These are in entry.S */
  extern void native_iret(void);
  extern void native_irq_enable_sysexit(void);
@@@ -307,6 -299,10 +307,10 @@@ struct pv_info pv_info = 
        .paravirt_enabled = 0,
        .kernel_rpl = 0,
        .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */
+ #ifdef CONFIG_X86_64
+       .extra_user_64bit_cs = __USER_CS,
+ #endif
  };
  
  struct pv_init_ops pv_init_ops = {
  
  struct pv_time_ops pv_time_ops = {
        .sched_clock = native_sched_clock,
 +      .steal_clock = native_steal_clock,
  };
  
  struct pv_irq_ops pv_irq_ops = {
diff --combined arch/x86/kernel/traps.c
@@@ -49,7 -49,7 +49,7 @@@
  #include <asm/stacktrace.h>
  #include <asm/processor.h>
  #include <asm/debugreg.h>
 -#include <asm/atomic.h>
 +#include <linux/atomic.h>
  #include <asm/system.h>
  #include <asm/traps.h>
  #include <asm/desc.h>
@@@ -872,12 -872,6 +872,6 @@@ void __init trap_init(void
        set_bit(SYSCALL_VECTOR, used_vectors);
  #endif
  
- #ifdef CONFIG_X86_64
-       BUG_ON(test_bit(VSYSCALL_EMU_VECTOR, used_vectors));
-       set_system_intr_gate(VSYSCALL_EMU_VECTOR, &emulate_vsyscall);
-       set_bit(VSYSCALL_EMU_VECTOR, used_vectors);
- #endif
        /*
         * Should be a barrier for any external CPU state:
         */
diff --combined arch/x86/mm/fault.c
@@@ -105,7 -105,7 +105,7 @@@ check_prefetch_opcode(struct pt_regs *r
                 * but for now it's good enough to assume that long
                 * mode only uses well known segments or kernel.
                 */
-               return (!user_mode(regs)) || (regs->cs == __USER_CS);
+               return (!user_mode(regs) || user_64bit_mode(regs));
  #endif
        case 0x60:
                /* 0x64 thru 0x67 are valid prefixes in all modes. */
@@@ -720,6 -720,18 +720,18 @@@ __bad_area_nosemaphore(struct pt_regs *
                if (is_errata100(regs, address))
                        return;
  
+ #ifdef CONFIG_X86_64
+               /*
+                * Instruction fetch faults in the vsyscall page might need
+                * emulation.
+                */
+               if (unlikely((error_code & PF_INSTR) &&
+                            ((address & ~0xfff) == VSYSCALL_START))) {
+                       if (emulate_vsyscall(regs, address))
+                               return;
+               }
+ #endif
                if (unlikely(show_unhandled_signals))
                        show_signal_msg(regs, error_code, address, tsk);
  
@@@ -1059,7 -1071,7 +1071,7 @@@ do_page_fault(struct pt_regs *regs, uns
        if (unlikely(error_code & PF_RSVD))
                pgtable_bad(regs, error_code, address);
  
 -      perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
 +      perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
  
        /*
         * If we're in an interrupt, have no user context or are running
@@@ -1161,11 -1173,11 +1173,11 @@@ good_area
        if (flags & FAULT_FLAG_ALLOW_RETRY) {
                if (fault & VM_FAULT_MAJOR) {
                        tsk->maj_flt++;
 -                      perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
 +                      perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
                                      regs, address);
                } else {
                        tsk->min_flt++;
 -                      perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
 +                      perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
                                      regs, address);
                }
                if (fault & VM_FAULT_RETRY) {
diff --combined arch/x86/xen/enlighten.c
@@@ -341,8 -341,6 +341,8 @@@ static void xen_set_ldt(const void *add
        struct mmuext_op *op;
        struct multicall_space mcs = xen_mc_entry(sizeof(*op));
  
 +      trace_xen_cpu_set_ldt(addr, entries);
 +
        op = mcs.args;
        op->cmd = MMUEXT_SET_LDT;
        op->arg1.linear_addr = (unsigned long)addr;
@@@ -498,8 -496,6 +498,8 @@@ static void xen_write_ldt_entry(struct 
        xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]);
        u64 entry = *(u64 *)ptr;
  
 +      trace_xen_cpu_write_ldt_entry(dt, entrynum, entry);
 +
        preempt_disable();
  
        xen_mc_flush();
@@@ -569,8 -565,6 +569,8 @@@ static void xen_write_idt_entry(gate_de
        unsigned long p = (unsigned long)&dt[entrynum];
        unsigned long start, end;
  
 +      trace_xen_cpu_write_idt_entry(dt, entrynum, g);
 +
        preempt_disable();
  
        start = __this_cpu_read(idt_desc.address);
@@@ -625,8 -619,6 +625,8 @@@ static void xen_load_idt(const struct d
        static DEFINE_SPINLOCK(lock);
        static struct trap_info traps[257];
  
 +      trace_xen_cpu_load_idt(desc);
 +
        spin_lock(&lock);
  
        __get_cpu_var(idt_desc) = *desc;
  static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
                                const void *desc, int type)
  {
 +      trace_xen_cpu_write_gdt_entry(dt, entry, desc, type);
 +
        preempt_disable();
  
        switch (type) {
  static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry,
                                            const void *desc, int type)
  {
 +      trace_xen_cpu_write_gdt_entry(dt, entry, desc, type);
 +
        switch (type) {
        case DESC_LDT:
        case DESC_TSS:
  static void xen_load_sp0(struct tss_struct *tss,
                         struct thread_struct *thread)
  {
 -      struct multicall_space mcs = xen_mc_entry(0);
 +      struct multicall_space mcs;
 +
 +      mcs = xen_mc_entry(0);
        MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0);
        xen_mc_issue(PARAVIRT_LAZY_CPU);
  }
@@@ -951,6 -937,10 +951,10 @@@ static const struct pv_info xen_info __
        .paravirt_enabled = 1,
        .shared_kernel_pmd = 0,
  
+ #ifdef CONFIG_X86_64
+       .extra_user_64bit_cs = FLAT_USER_CS64,
+ #endif
        .name = "Xen",
  };
  
@@@ -1262,14 -1252,6 +1266,14 @@@ asmlinkage void __init xen_start_kernel
                if (pci_xen)
                        x86_init.pci.arch_init = pci_xen_init;
        } else {
 +              const struct dom0_vga_console_info *info =
 +                      (void *)((char *)xen_start_info +
 +                               xen_start_info->console.dom0.info_off);
 +
 +              xen_init_vga(info, xen_start_info->console.dom0.info_size);
 +              xen_start_info->console.domU.mfn = 0;
 +              xen_start_info->console.domU.evtchn = 0;
 +
                /* Make sure ACS will be enabled */
                pci_request_acs();
        }
diff --combined arch/x86/xen/mmu.c
@@@ -48,8 -48,6 +48,8 @@@
  #include <linux/memblock.h>
  #include <linux/seq_file.h>
  
 +#include <trace/events/xen.h>
 +
  #include <asm/pgtable.h>
  #include <asm/tlbflush.h>
  #include <asm/fixmap.h>
@@@ -196,8 -194,6 +196,8 @@@ void xen_set_domain_pte(pte_t *ptep, pt
        struct multicall_space mcs;
        struct mmu_update *u;
  
 +      trace_xen_mmu_set_domain_pte(ptep, pteval, domid);
 +
        mcs = xen_mc_entry(sizeof(*u));
        u = mcs.args;
  
@@@ -229,24 -225,6 +229,24 @@@ static void xen_extend_mmu_update(cons
        *u = *update;
  }
  
 +static void xen_extend_mmuext_op(const struct mmuext_op *op)
 +{
 +      struct multicall_space mcs;
 +      struct mmuext_op *u;
 +
 +      mcs = xen_mc_extend_args(__HYPERVISOR_mmuext_op, sizeof(*u));
 +
 +      if (mcs.mc != NULL) {
 +              mcs.mc->args[1]++;
 +      } else {
 +              mcs = __xen_mc_entry(sizeof(*u));
 +              MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
 +      }
 +
 +      u = mcs.args;
 +      *u = *op;
 +}
 +
  static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
  {
        struct mmu_update u;
  
  static void xen_set_pmd(pmd_t *ptr, pmd_t val)
  {
 +      trace_xen_mmu_set_pmd(ptr, val);
 +
        /* If page is not pinned, we can just update the entry
           directly */
        if (!xen_page_pinned(ptr)) {
@@@ -306,30 -282,22 +306,30 @@@ static bool xen_batched_set_pte(pte_t *
        return true;
  }
  
 -static void xen_set_pte(pte_t *ptep, pte_t pteval)
 +static inline void __xen_set_pte(pte_t *ptep, pte_t pteval)
  {
        if (!xen_batched_set_pte(ptep, pteval))
                native_set_pte(ptep, pteval);
  }
  
 +static void xen_set_pte(pte_t *ptep, pte_t pteval)
 +{
 +      trace_xen_mmu_set_pte(ptep, pteval);
 +      __xen_set_pte(ptep, pteval);
 +}
 +
  static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
                    pte_t *ptep, pte_t pteval)
  {
 -      xen_set_pte(ptep, pteval);
 +      trace_xen_mmu_set_pte_at(mm, addr, ptep, pteval);
 +      __xen_set_pte(ptep, pteval);
  }
  
  pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
                                 unsigned long addr, pte_t *ptep)
  {
        /* Just return the pte as-is.  We preserve the bits on commit */
 +      trace_xen_mmu_ptep_modify_prot_start(mm, addr, ptep, *ptep);
        return *ptep;
  }
  
@@@ -338,7 -306,6 +338,7 @@@ void xen_ptep_modify_prot_commit(struc
  {
        struct mmu_update u;
  
 +      trace_xen_mmu_ptep_modify_prot_commit(mm, addr, ptep, pte);
        xen_mc_batch();
  
        u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
@@@ -563,8 -530,6 +563,8 @@@ static void xen_set_pud_hyper(pud_t *pt
  
  static void xen_set_pud(pud_t *ptr, pud_t val)
  {
 +      trace_xen_mmu_set_pud(ptr, val);
 +
        /* If page is not pinned, we can just update the entry
           directly */
        if (!xen_page_pinned(ptr)) {
  #ifdef CONFIG_X86_PAE
  static void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
  {
 +      trace_xen_mmu_set_pte_atomic(ptep, pte);
        set_64bit((u64 *)ptep, native_pte_val(pte));
  }
  
  static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
  {
 +      trace_xen_mmu_pte_clear(mm, addr, ptep);
        if (!xen_batched_set_pte(ptep, native_make_pte(0)))
                native_pte_clear(mm, addr, ptep);
  }
  
  static void xen_pmd_clear(pmd_t *pmdp)
  {
 +      trace_xen_mmu_pmd_clear(pmdp);
        set_pmd(pmdp, __pmd(0));
  }
  #endif        /* CONFIG_X86_PAE */
@@@ -667,8 -629,6 +667,8 @@@ static void xen_set_pgd(pgd_t *ptr, pgd
  {
        pgd_t *user_ptr = xen_get_user_pgd(ptr);
  
 +      trace_xen_mmu_set_pgd(ptr, user_ptr, val);
 +
        /* If page is not pinned, we can just update the entry
           directly */
        if (!xen_page_pinned(ptr)) {
@@@ -828,12 -788,14 +828,12 @@@ static void xen_pte_unlock(void *v
  
  static void xen_do_pin(unsigned level, unsigned long pfn)
  {
 -      struct mmuext_op *op;
 -      struct multicall_space mcs;
 +      struct mmuext_op op;
  
 -      mcs = __xen_mc_entry(sizeof(*op));
 -      op = mcs.args;
 -      op->cmd = level;
 -      op->arg1.mfn = pfn_to_mfn(pfn);
 -      MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 +      op.cmd = level;
 +      op.arg1.mfn = pfn_to_mfn(pfn);
 +
 +      xen_extend_mmuext_op(&op);
  }
  
  static int xen_pin_page(struct mm_struct *mm, struct page *page,
     read-only, and can be pinned. */
  static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
  {
 +      trace_xen_mmu_pgd_pin(mm, pgd);
 +
        xen_mc_batch();
  
        if (__xen_pgd_walk(mm, pgd, xen_pin_page, USER_LIMIT)) {
@@@ -1028,8 -988,6 +1028,8 @@@ static int xen_unpin_page(struct mm_str
  /* Release a pagetables pages back as normal RW */
  static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd)
  {
 +      trace_xen_mmu_pgd_unpin(mm, pgd);
 +
        xen_mc_batch();
  
        xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
@@@ -1238,8 -1196,6 +1238,8 @@@ static void xen_flush_tlb(void
        struct mmuext_op *op;
        struct multicall_space mcs;
  
 +      trace_xen_mmu_flush_tlb(0);
 +
        preempt_disable();
  
        mcs = xen_mc_entry(sizeof(*op));
@@@ -1258,8 -1214,6 +1258,8 @@@ static void xen_flush_tlb_single(unsign
        struct mmuext_op *op;
        struct multicall_space mcs;
  
 +      trace_xen_mmu_flush_tlb_single(addr);
 +
        preempt_disable();
  
        mcs = xen_mc_entry(sizeof(*op));
@@@ -1286,8 -1240,6 +1286,8 @@@ static void xen_flush_tlb_others(const 
        } *args;
        struct multicall_space mcs;
  
 +      trace_xen_mmu_flush_tlb_others(cpus, mm, va);
 +
        if (cpumask_empty(cpus))
                return;         /* nothing to do */
  
@@@ -1323,11 -1275,10 +1323,11 @@@ static void set_current_cr3(void *v
  
  static void __xen_write_cr3(bool kernel, unsigned long cr3)
  {
 -      struct mmuext_op *op;
 -      struct multicall_space mcs;
 +      struct mmuext_op op;
        unsigned long mfn;
  
 +      trace_xen_mmu_write_cr3(kernel, cr3);
 +
        if (cr3)
                mfn = pfn_to_mfn(PFN_DOWN(cr3));
        else
  
        WARN_ON(mfn == 0 && kernel);
  
 -      mcs = __xen_mc_entry(sizeof(*op));
 -
 -      op = mcs.args;
 -      op->cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR;
 -      op->arg1.mfn = mfn;
 +      op.cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR;
 +      op.arg1.mfn = mfn;
  
 -      MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 +      xen_extend_mmuext_op(&op);
  
        if (kernel) {
                percpu_write(xen_cr3, cr3);
@@@ -1497,52 -1451,19 +1497,52 @@@ static void __init xen_release_pmd_init
        make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
  }
  
 +static inline void __pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
 +{
 +      struct multicall_space mcs;
 +      struct mmuext_op *op;
 +
 +      mcs = __xen_mc_entry(sizeof(*op));
 +      op = mcs.args;
 +      op->cmd = cmd;
 +      op->arg1.mfn = pfn_to_mfn(pfn);
 +
 +      MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
 +}
 +
 +static inline void __set_pfn_prot(unsigned long pfn, pgprot_t prot)
 +{
 +      struct multicall_space mcs;
 +      unsigned long addr = (unsigned long)__va(pfn << PAGE_SHIFT);
 +
 +      mcs = __xen_mc_entry(0);
 +      MULTI_update_va_mapping(mcs.mc, (unsigned long)addr,
 +                              pfn_pte(pfn, prot), 0);
 +}
 +
  /* This needs to make sure the new pte page is pinned iff its being
     attached to a pinned pagetable. */
 -static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned level)
 +static inline void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn,
 +                                  unsigned level)
  {
 -      struct page *page = pfn_to_page(pfn);
 +      bool pinned = PagePinned(virt_to_page(mm->pgd));
 +
 +      trace_xen_mmu_alloc_ptpage(mm, pfn, level, pinned);
 +
 +      if (pinned) {
 +              struct page *page = pfn_to_page(pfn);
  
 -      if (PagePinned(virt_to_page(mm->pgd))) {
                SetPagePinned(page);
  
                if (!PageHighMem(page)) {
 -                      make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
 +                      xen_mc_batch();
 +
 +                      __set_pfn_prot(pfn, PAGE_KERNEL_RO);
 +
                        if (level == PT_PTE && USE_SPLIT_PTLOCKS)
 -                              pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
 +                              __pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
 +
 +                      xen_mc_issue(PARAVIRT_LAZY_MMU);
                } else {
                        /* make sure there are no stray mappings of
                           this page */
@@@ -1562,23 -1483,15 +1562,23 @@@ static void xen_alloc_pmd(struct mm_str
  }
  
  /* This should never happen until we're OK to use struct page */
 -static void xen_release_ptpage(unsigned long pfn, unsigned level)
 +static inline void xen_release_ptpage(unsigned long pfn, unsigned level)
  {
        struct page *page = pfn_to_page(pfn);
 +      bool pinned = PagePinned(page);
  
 -      if (PagePinned(page)) {
 +      trace_xen_mmu_release_ptpage(pfn, level, pinned);
 +
 +      if (pinned) {
                if (!PageHighMem(page)) {
 +                      xen_mc_batch();
 +
                        if (level == PT_PTE && USE_SPLIT_PTLOCKS)
 -                              pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
 -                      make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 +                              __pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
 +
 +                      __set_pfn_prot(pfn, PAGE_KERNEL);
 +
 +                      xen_mc_issue(PARAVIRT_LAZY_MMU);
                }
                ClearPagePinned(page);
        }
@@@ -1916,6 -1829,7 +1916,7 @@@ static void xen_set_fixmap(unsigned idx
  # endif
  #else
        case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE:
+       case VVAR_PAGE:
  #endif
        case FIX_TEXT_POKE0:
        case FIX_TEXT_POKE1:
  #ifdef CONFIG_X86_64
        /* Replicate changes to map the vsyscall page into the user
           pagetable vsyscall mapping. */
-       if (idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) {
+       if ((idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) ||
+           idx == VVAR_PAGE) {
                unsigned long vaddr = __fix_to_virt(idx);
                set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte);
        }