x86: change irq functions to accomodate 64-bit
[sfrench/cifs-2.6.git] / include / asm-x86 / paravirt.h
index 9fa3fa9e62d15d77cc0aaa391f4500c7bdc7325a..0735a90f531b95a38fe694d7f9ea1b978d6574df 100644 (file)
@@ -5,6 +5,7 @@
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/page.h>
+#include <asm/asm.h>
 
 /* Bitmask of what can be clobbered: usually at least eax. */
 #define CLBR_NONE 0x0
 #include <linux/types.h>
 #include <linux/cpumask.h>
 #include <asm/kmap_types.h>
+#include <asm/desc_defs.h>
 
 struct page;
 struct thread_struct;
-struct Xgt_desc_struct;
+struct desc_ptr;
 struct tss_struct;
 struct mm_struct;
 struct desc_struct;
 
-/* Lazy mode for batching updates / context switch */
-enum paravirt_lazy_mode {
-       PARAVIRT_LAZY_NONE = 0,
-       PARAVIRT_LAZY_MMU = 1,
-       PARAVIRT_LAZY_CPU = 2,
-       PARAVIRT_LAZY_FLUSH = 3,
-};
-
-struct paravirt_ops
-{
+/* general info */
+struct pv_info {
        unsigned int kernel_rpl;
        int shared_kernel_pmd;
-       int paravirt_enabled;
+       int paravirt_enabled;
        const char *name;
+};
 
+struct pv_init_ops {
        /*
-        * Patch may replace one of the defined code sequences with arbitrary
-        * code, subject to the same register constraints.  This generally
-        * means the code is not free to clobber any registers other than EAX.
-        * The patch function should return the number of bytes of code
-        * generated, as we nop pad the rest in generic code.
+        * Patch may replace one of the defined code sequences with
+        * arbitrary code, subject to the same register constraints.
+        * This generally means the code is not free to clobber any
+        * registers other than EAX.  The patch function should return
+        * the number of bytes of code generated, as we nop pad the
+        * rest in generic code.
         */
        unsigned (*patch)(u8 type, u16 clobber, void *insnbuf,
                          unsigned long addr, unsigned len);
@@ -55,29 +52,29 @@ struct paravirt_ops
        char *(*memory_setup)(void);
        void (*post_allocator_init)(void);
 
-       void (*init_IRQ)(void);
-       void (*time_init)(void);
-
-       /*
-        * Called before/after init_mm pagetable setup. setup_start
-        * may reset %cr3, and may pre-install parts of the pagetable;
-        * pagetable setup is expected to preserve any existing
-        * mapping.
-        */
-       void (*pagetable_setup_start)(pgd_t *pgd_base);
-       void (*pagetable_setup_done)(pgd_t *pgd_base);
-
        /* Print a banner to identify the environment */
        void (*banner)(void);
+};
+
+
+struct pv_lazy_ops {
+       /* Set deferred update mode, used for batching operations. */
+       void (*enter)(void);
+       void (*leave)(void);
+};
+
+struct pv_time_ops {
+       void (*time_init)(void);
 
        /* Set and set time of day */
        unsigned long (*get_wallclock)(void);
        int (*set_wallclock)(unsigned long);
 
-       /* cpuid emulation, mostly so that caps bits can be disabled */
-       void (*cpuid)(unsigned int *eax, unsigned int *ebx,
-                     unsigned int *ecx, unsigned int *edx);
+       unsigned long long (*sched_clock)(void);
+       unsigned long (*get_cpu_khz)(void);
+};
 
+struct pv_cpu_ops {
        /* hooks for various privileged instructions */
        unsigned long (*get_debugreg)(int regno);
        void (*set_debugreg)(int regno, unsigned long value);
@@ -87,16 +84,55 @@ struct paravirt_ops
        unsigned long (*read_cr0)(void);
        void (*write_cr0)(unsigned long);
 
-       unsigned long (*read_cr2)(void);
-       void (*write_cr2)(unsigned long);
-
-       unsigned long (*read_cr3)(void);
-       void (*write_cr3)(unsigned long);
-
        unsigned long (*read_cr4_safe)(void);
        unsigned long (*read_cr4)(void);
        void (*write_cr4)(unsigned long);
 
+       /* Segment descriptor handling */
+       void (*load_tr_desc)(void);
+       void (*load_gdt)(const struct desc_ptr *);
+       void (*load_idt)(const struct desc_ptr *);
+       void (*store_gdt)(struct desc_ptr *);
+       void (*store_idt)(struct desc_ptr *);
+       void (*set_ldt)(const void *desc, unsigned entries);
+       unsigned long (*store_tr)(void);
+       void (*load_tls)(struct thread_struct *t, unsigned int cpu);
+       void (*write_ldt_entry)(struct desc_struct *ldt, int entrynum,
+                               const void *desc);
+       void (*write_gdt_entry)(struct desc_struct *,
+                               int entrynum, const void *desc, int size);
+       void (*write_idt_entry)(gate_desc *,
+                               int entrynum, const gate_desc *gate);
+       void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
+
+       void (*set_iopl_mask)(unsigned mask);
+
+       void (*wbinvd)(void);
+       void (*io_delay)(void);
+
+       /* cpuid emulation, mostly so that caps bits can be disabled */
+       void (*cpuid)(unsigned int *eax, unsigned int *ebx,
+                     unsigned int *ecx, unsigned int *edx);
+
+       /* MSR, PMC and TSR operations.
+          err = 0/-EFAULT.  wrmsr returns 0/-EFAULT. */
+       u64 (*read_msr)(unsigned int msr, int *err);
+       int (*write_msr)(unsigned int msr, unsigned low, unsigned high);
+
+       u64 (*read_tsc)(void);
+       u64 (*read_pmc)(int counter);
+       unsigned long long (*read_tscp)(unsigned int *aux);
+
+       /* These two are jmp to, not actually called. */
+       void (*irq_enable_syscall_ret)(void);
+       void (*iret)(void);
+
+       struct pv_lazy_ops lazy_mode;
+};
+
+struct pv_irq_ops {
+       void (*init_IRQ)(void);
+
        /*
         * Get/set interrupt state.  save_fl and restore_fl are only
         * expected to use X86_EFLAGS_IF; all other bits
@@ -109,38 +145,41 @@ struct paravirt_ops
        void (*irq_enable)(void);
        void (*safe_halt)(void);
        void (*halt)(void);
+};
 
-       void (*wbinvd)(void);
+struct pv_apic_ops {
+#ifdef CONFIG_X86_LOCAL_APIC
+       /*
+        * Direct APIC operations, principally for VMI.  Ideally
+        * these shouldn't be in this interface.
+        */
+       void (*apic_write)(unsigned long reg, u32 v);
+       void (*apic_write_atomic)(unsigned long reg, u32 v);
+       u32 (*apic_read)(unsigned long reg);
+       void (*setup_boot_clock)(void);
+       void (*setup_secondary_clock)(void);
 
-       /* MSR, PMC and TSR operations.
-          err = 0/-EFAULT.  wrmsr returns 0/-EFAULT. */
-       u64 (*read_msr)(unsigned int msr, int *err);
-       int (*write_msr)(unsigned int msr, u64 val);
+       void (*startup_ipi_hook)(int phys_apicid,
+                                unsigned long start_eip,
+                                unsigned long start_esp);
+#endif
+};
 
-       u64 (*read_tsc)(void);
-       u64 (*read_pmc)(void);
-       unsigned long long (*sched_clock)(void);
-       unsigned long (*get_cpu_khz)(void);
+struct pv_mmu_ops {
+       /*
+        * Called before/after init_mm pagetable setup. setup_start
+        * may reset %cr3, and may pre-install parts of the pagetable;
+        * pagetable setup is expected to preserve any existing
+        * mapping.
+        */
+       void (*pagetable_setup_start)(pgd_t *pgd_base);
+       void (*pagetable_setup_done)(pgd_t *pgd_base);
 
-       /* Segment descriptor handling */
-       void (*load_tr_desc)(void);
-       void (*load_gdt)(const struct Xgt_desc_struct *);
-       void (*load_idt)(const struct Xgt_desc_struct *);
-       void (*store_gdt)(struct Xgt_desc_struct *);
-       void (*store_idt)(struct Xgt_desc_struct *);
-       void (*set_ldt)(const void *desc, unsigned entries);
-       unsigned long (*store_tr)(void);
-       void (*load_tls)(struct thread_struct *t, unsigned int cpu);
-       void (*write_ldt_entry)(struct desc_struct *,
-                               int entrynum, u32 low, u32 high);
-       void (*write_gdt_entry)(struct desc_struct *,
-                               int entrynum, u32 low, u32 high);
-       void (*write_idt_entry)(struct desc_struct *,
-                               int entrynum, u32 low, u32 high);
-       void (*load_esp0)(struct tss_struct *tss, struct thread_struct *t);
+       unsigned long (*read_cr2)(void);
+       void (*write_cr2)(unsigned long);
 
-       void (*set_iopl_mask)(unsigned mask);
-       void (*io_delay)(void);
+       unsigned long (*read_cr3)(void);
+       void (*write_cr3)(unsigned long);
 
        /*
         * Hooks for intercepting the creation/use/destruction of an
@@ -152,21 +191,6 @@ struct paravirt_ops
                         struct mm_struct *mm);
        void (*exit_mmap)(struct mm_struct *mm);
 
-#ifdef CONFIG_X86_LOCAL_APIC
-       /*
-        * Direct APIC operations, principally for VMI.  Ideally
-        * these shouldn't be in this interface.
-        */
-       void (*apic_write)(unsigned long reg, unsigned long v);
-       void (*apic_write_atomic)(unsigned long reg, unsigned long v);
-       unsigned long (*apic_read)(unsigned long reg);
-       void (*setup_boot_clock)(void);
-       void (*setup_secondary_clock)(void);
-
-       void (*startup_ipi_hook)(int phys_apicid,
-                                unsigned long start_eip,
-                                unsigned long start_esp);
-#endif
 
        /* TLB operations */
        void (*flush_tlb_user)(void);
@@ -191,15 +215,12 @@ struct paravirt_ops
        void (*pte_update_defer)(struct mm_struct *mm,
                                 unsigned long addr, pte_t *ptep);
 
-#ifdef CONFIG_HIGHPTE
-       void *(*kmap_atomic_pte)(struct page *page, enum km_type type);
-#endif
-
 #ifdef CONFIG_X86_PAE
        void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
-       void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte);
+       void (*set_pte_present)(struct mm_struct *mm, unsigned long addr,
+                               pte_t *ptep, pte_t pte);
        void (*set_pud)(pud_t *pudp, pud_t pudval);
-       void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+       void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
        void (*pmd_clear)(pmd_t *pmdp);
 
        unsigned long long (*pte_val)(pte_t);
@@ -217,21 +238,40 @@ struct paravirt_ops
        pgd_t (*make_pgd)(unsigned long pgd);
 #endif
 
-       /* Set deferred update mode, used for batching operations. */
-       void (*set_lazy_mode)(enum paravirt_lazy_mode mode);
+#ifdef CONFIG_HIGHPTE
+       void *(*kmap_atomic_pte)(struct page *page, enum km_type type);
+#endif
 
-       /* These two are jmp to, not actually called. */
-       void (*irq_enable_sysexit)(void);
-       void (*iret)(void);
+       struct pv_lazy_ops lazy_mode;
 };
 
-extern struct paravirt_ops paravirt_ops;
+/* This contains all the paravirt structures: we get a convenient
+ * number for each function using the offset which we use to indicate
+ * what to patch. */
+struct paravirt_patch_template
+{
+       struct pv_init_ops pv_init_ops;
+       struct pv_time_ops pv_time_ops;
+       struct pv_cpu_ops pv_cpu_ops;
+       struct pv_irq_ops pv_irq_ops;
+       struct pv_apic_ops pv_apic_ops;
+       struct pv_mmu_ops pv_mmu_ops;
+};
+
+extern struct pv_info pv_info;
+extern struct pv_init_ops pv_init_ops;
+extern struct pv_time_ops pv_time_ops;
+extern struct pv_cpu_ops pv_cpu_ops;
+extern struct pv_irq_ops pv_irq_ops;
+extern struct pv_apic_ops pv_apic_ops;
+extern struct pv_mmu_ops pv_mmu_ops;
 
 #define PARAVIRT_PATCH(x)                                      \
-       (offsetof(struct paravirt_ops, x) / sizeof(void *))
+       (offsetof(struct paravirt_patch_template, x) / sizeof(void *))
 
-#define paravirt_type(type)                                    \
-       [paravirt_typenum] "i" (PARAVIRT_PATCH(type))
+#define paravirt_type(op)                              \
+       [paravirt_typenum] "i" (PARAVIRT_PATCH(op)),    \
+       [paravirt_opptr] "m" (op)
 #define paravirt_clobber(clobber)              \
        [paravirt_clobber] "i" (clobber)
 
@@ -242,7 +282,8 @@ extern struct paravirt_ops paravirt_ops;
 #define _paravirt_alt(insn_string, type, clobber)      \
        "771:\n\t" insn_string "\n" "772:\n"            \
        ".pushsection .parainstructions,\"a\"\n"        \
-       "  .long 771b\n"                                \
+       _ASM_ALIGN "\n"                                 \
+       _ASM_PTR " 771b\n"                              \
        "  .byte " type "\n"                            \
        "  .byte 772b-771b\n"                           \
        "  .short " clobber "\n"                        \
@@ -258,7 +299,7 @@ unsigned paravirt_patch_call(void *insnbuf,
                             const void *target, u16 tgt_clobbers,
                             unsigned long addr, u16 site_clobbers,
                             unsigned len);
-unsigned paravirt_patch_jmp(const void *target, void *insnbuf,
+unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
                            unsigned long addr, unsigned len);
 unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
                                unsigned long addr, unsigned len);
@@ -271,18 +312,18 @@ int paravirt_disable_iospace(void);
 /*
  * This generates an indirect call based on the operation type number.
  * The type number, computed in PARAVIRT_PATCH, is derived from the
- * offset into the paravirt_ops structure, and can therefore be freely
- * converted back into a structure offset.
+ * offset into the paravirt_patch_template structure, and can therefore be
+ * freely converted back into a structure offset.
  */
-#define PARAVIRT_CALL  "call *(paravirt_ops+%c[paravirt_typenum]*4);"
+#define PARAVIRT_CALL  "call *%[paravirt_opptr];"
 
 /*
- * These macros are intended to wrap calls into a paravirt_ops
- * operation, so that they can be later identified and patched at
+ * These macros are intended to wrap calls through one of the paravirt
+ * ops structs, so that they can be later identified and patched at
  * runtime.
  *
  * Normally, a call to a pv_op function is a simple indirect call:
- * (paravirt_ops.operations)(args...).
+ * (pv_op_struct.operations)(args...).
  *
  * Unfortunately, this is a relatively slow operation for modern CPUs,
  * because it cannot necessarily determine what the destination
@@ -292,16 +333,22 @@ int paravirt_disable_iospace(void);
  * calls are essentially free, because the call and return addresses
  * are completely predictable.)
  *
- * These macros rely on the standard gcc "regparm(3)" calling
+ * For i386, these macros rely on the standard gcc "regparm(3)" calling
  * convention, in which the first three arguments are placed in %eax,
  * %edx, %ecx (in that order), and the remaining arguments are placed
  * on the stack.  All caller-save registers (eax,edx,ecx) are expected
  * to be modified (either clobbered or used for return values).
+ * X86_64, on the other hand, already specifies a register-based calling
+ * conventions, returning at %rax, with parameteres going on %rdi, %rsi,
+ * %rdx, and %rcx. Note that for this reason, x86_64 does not need any
+ * special handling for dealing with 4 arguments, unlike i386.
+ * However, x86_64 also have to clobber all caller saved registers, which
+ * unfortunately, are quite a bit (r8 - r11)
  *
  * The call instruction itself is marked by placing its start address
  * and size into the .parainstructions section, so that
  * apply_paravirt() in arch/i386/kernel/alternative.c can do the
- * appropriate patching under the control of the backend paravirt_ops
+ * appropriate patching under the control of the backend pv_init_ops
  * implementation.
  *
  * Unfortunately there's no way to get gcc to generate the args setup
@@ -319,10 +366,12 @@ int paravirt_disable_iospace(void);
  * the return type.  The macro then uses sizeof() on that type to
  * determine whether its a 32 or 64 bit value, and places the return
  * in the right register(s) (just %eax for 32-bit, and %edx:%eax for
- * 64-bit).
+ * 64-bit). For x86_64 machines, it just returns at %rax regardless of
+ * the return value size.
  *
  * 64-bit arguments are passed as a pair of adjacent 32-bit arguments
- * in low,high order.
+ * i386 also passes 64-bit arguments as a pair of adjacent 32-bit arguments
+ * in low,high order
  *
  * Small structures are passed and returned in registers.  The macro
  * calling convention can't directly deal with this, so the wrapper
@@ -332,46 +381,67 @@ int paravirt_disable_iospace(void);
  * means that all uses must be wrapped in inline functions.  This also
  * makes sure the incoming and outgoing types are always correct.
  */
+#ifdef CONFIG_X86_32
+#define PVOP_VCALL_ARGS                        unsigned long __eax, __edx, __ecx
+#define PVOP_CALL_ARGS                 PVOP_VCALL_ARGS
+#define PVOP_VCALL_CLOBBERS            "=a" (__eax), "=d" (__edx),     \
+                                       "=c" (__ecx)
+#define PVOP_CALL_CLOBBERS             PVOP_VCALL_CLOBBERS
+#define EXTRA_CLOBBERS
+#define VEXTRA_CLOBBERS
+#else
+#define PVOP_VCALL_ARGS                unsigned long __edi, __esi, __edx, __ecx
+#define PVOP_CALL_ARGS         PVOP_VCALL_ARGS, __eax
+#define PVOP_VCALL_CLOBBERS    "=D" (__edi),                           \
+                               "=S" (__esi), "=d" (__edx),             \
+                               "=c" (__ecx)
+
+#define PVOP_CALL_CLOBBERS     PVOP_VCALL_CLOBBERS, "=a" (__eax)
+
+#define EXTRA_CLOBBERS  , "r8", "r9", "r10", "r11"
+#define VEXTRA_CLOBBERS         , "rax", "r8", "r9", "r10", "r11"
+#endif
+
 #define __PVOP_CALL(rettype, op, pre, post, ...)                       \
        ({                                                              \
                rettype __ret;                                          \
-               unsigned long __eax, __edx, __ecx;                      \
+               PVOP_CALL_ARGS;                                 \
+               /* This is 32-bit specific, but is okay in 64-bit */    \
+               /* since this condition will never hold */              \
                if (sizeof(rettype) > sizeof(unsigned long)) {          \
                        asm volatile(pre                                \
                                     paravirt_alt(PARAVIRT_CALL)        \
                                     post                               \
-                                    : "=a" (__eax), "=d" (__edx),      \
-                                      "=c" (__ecx)                     \
+                                    : PVOP_CALL_CLOBBERS               \
                                     : paravirt_type(op),               \
                                       paravirt_clobber(CLBR_ANY),      \
                                       ##__VA_ARGS__                    \
-                                    : "memory", "cc");                 \
+                                    : "memory", "cc" EXTRA_CLOBBERS);  \
                        __ret = (rettype)((((u64)__edx) << 32) | __eax); \
                } else {                                                \
                        asm volatile(pre                                \
                                     paravirt_alt(PARAVIRT_CALL)        \
                                     post                               \
-                                    : "=a" (__eax), "=d" (__edx),      \
-                                      "=c" (__ecx)                     \
+                                    : PVOP_CALL_CLOBBERS               \
                                     : paravirt_type(op),               \
                                       paravirt_clobber(CLBR_ANY),      \
                                       ##__VA_ARGS__                    \
-                                    : "memory", "cc");                 \
+                                    : "memory", "cc" EXTRA_CLOBBERS);  \
                        __ret = (rettype)__eax;                         \
                }                                                       \
                __ret;                                                  \
        })
 #define __PVOP_VCALL(op, pre, post, ...)                               \
        ({                                                              \
-               unsigned long __eax, __edx, __ecx;                      \
+               PVOP_VCALL_ARGS;                                        \
                asm volatile(pre                                        \
                             paravirt_alt(PARAVIRT_CALL)                \
                             post                                       \
-                            : "=a" (__eax), "=d" (__edx), "=c" (__ecx) \
+                            : PVOP_VCALL_CLOBBERS                      \
                             : paravirt_type(op),                       \
                               paravirt_clobber(CLBR_ANY),              \
                               ##__VA_ARGS__                            \
-                            : "memory", "cc");                         \
+                            : "memory", "cc" VEXTRA_CLOBBERS);         \
        })
 
 #define PVOP_CALL0(rettype, op)                                                \
@@ -380,22 +450,26 @@ int paravirt_disable_iospace(void);
        __PVOP_VCALL(op, "", "")
 
 #define PVOP_CALL1(rettype, op, arg1)                                  \
-       __PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)))
+       __PVOP_CALL(rettype, op, "", "", "0" ((unsigned long)(arg1)))
 #define PVOP_VCALL1(op, arg1)                                          \
-       __PVOP_VCALL(op, "", "", "0" ((u32)(arg1)))
+       __PVOP_VCALL(op, "", "", "0" ((unsigned long)(arg1)))
 
 #define PVOP_CALL2(rettype, op, arg1, arg2)                            \
-       __PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)), "1" ((u32)(arg2)))
+       __PVOP_CALL(rettype, op, "", "", "0" ((unsigned long)(arg1)),   \
+       "1" ((unsigned long)(arg2)))
 #define PVOP_VCALL2(op, arg1, arg2)                                    \
-       __PVOP_VCALL(op, "", "", "0" ((u32)(arg1)), "1" ((u32)(arg2)))
+       __PVOP_VCALL(op, "", "", "0" ((unsigned long)(arg1)),           \
+       "1" ((unsigned long)(arg2)))
 
 #define PVOP_CALL3(rettype, op, arg1, arg2, arg3)                      \
-       __PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)),             \
-                   "1"((u32)(arg2)), "2"((u32)(arg3)))
+       __PVOP_CALL(rettype, op, "", "", "0" ((unsigned long)(arg1)),   \
+       "1"((unsigned long)(arg2)), "2"((unsigned long)(arg3)))
 #define PVOP_VCALL3(op, arg1, arg2, arg3)                              \
-       __PVOP_VCALL(op, "", "", "0" ((u32)(arg1)), "1"((u32)(arg2)),   \
-                    "2"((u32)(arg3)))
+       __PVOP_VCALL(op, "", "", "0" ((unsigned long)(arg1)),           \
+       "1"((unsigned long)(arg2)), "2"((unsigned long)(arg3)))
 
+/* This is the only difference in x86_64. We can make it much simpler */
+#ifdef CONFIG_X86_32
 #define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4)                        \
        __PVOP_CALL(rettype, op,                                        \
                    "push %[_arg4];", "lea 4(%%esp),%%esp;",            \
@@ -406,39 +480,49 @@ int paravirt_disable_iospace(void);
                    "push %[_arg4];", "lea 4(%%esp),%%esp;",            \
                    "0" ((u32)(arg1)), "1" ((u32)(arg2)),               \
                    "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4)))
+#else
+#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4)                        \
+       __PVOP_CALL(rettype, op, "", "", "0" ((unsigned long)(arg1)),   \
+       "1"((unsigned long)(arg2)), "2"((unsigned long)(arg3)),         \
+       "3"((unsigned long)(arg4)))
+#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4)                                \
+       __PVOP_VCALL(op, "", "", "0" ((unsigned long)(arg1)),           \
+       "1"((unsigned long)(arg2)), "2"((unsigned long)(arg3)),         \
+       "3"((unsigned long)(arg4)))
+#endif
 
 static inline int paravirt_enabled(void)
 {
-       return paravirt_ops.paravirt_enabled;
+       return pv_info.paravirt_enabled;
 }
 
-static inline void load_esp0(struct tss_struct *tss,
+static inline void load_sp0(struct tss_struct *tss,
                             struct thread_struct *thread)
 {
-       PVOP_VCALL2(load_esp0, tss, thread);
+       PVOP_VCALL2(pv_cpu_ops.load_sp0, tss, thread);
 }
 
-#define ARCH_SETUP                     paravirt_ops.arch_setup();
+#define ARCH_SETUP                     pv_init_ops.arch_setup();
 static inline unsigned long get_wallclock(void)
 {
-       return PVOP_CALL0(unsigned long, get_wallclock);
+       return PVOP_CALL0(unsigned long, pv_time_ops.get_wallclock);
 }
 
 static inline int set_wallclock(unsigned long nowtime)
 {
-       return PVOP_CALL1(int, set_wallclock, nowtime);
+       return PVOP_CALL1(int, pv_time_ops.set_wallclock, nowtime);
 }
 
 static inline void (*choose_time_init(void))(void)
 {
-       return paravirt_ops.time_init;
+       return pv_time_ops.time_init;
 }
 
 /* The paravirtualized CPUID instruction. */
 static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
                           unsigned int *ecx, unsigned int *edx)
 {
-       PVOP_VCALL4(cpuid, eax, ebx, ecx, edx);
+       PVOP_VCALL4(pv_cpu_ops.cpuid, eax, ebx, ecx, edx);
 }
 
 /*
@@ -446,87 +530,87 @@ static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
  */
 static inline unsigned long paravirt_get_debugreg(int reg)
 {
-       return PVOP_CALL1(unsigned long, get_debugreg, reg);
+       return PVOP_CALL1(unsigned long, pv_cpu_ops.get_debugreg, reg);
 }
 #define get_debugreg(var, reg) var = paravirt_get_debugreg(reg)
 static inline void set_debugreg(unsigned long val, int reg)
 {
-       PVOP_VCALL2(set_debugreg, reg, val);
+       PVOP_VCALL2(pv_cpu_ops.set_debugreg, reg, val);
 }
 
 static inline void clts(void)
 {
-       PVOP_VCALL0(clts);
+       PVOP_VCALL0(pv_cpu_ops.clts);
 }
 
 static inline unsigned long read_cr0(void)
 {
-       return PVOP_CALL0(unsigned long, read_cr0);
+       return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr0);
 }
 
 static inline void write_cr0(unsigned long x)
 {
-       PVOP_VCALL1(write_cr0, x);
+       PVOP_VCALL1(pv_cpu_ops.write_cr0, x);
 }
 
 static inline unsigned long read_cr2(void)
 {
-       return PVOP_CALL0(unsigned long, read_cr2);
+       return PVOP_CALL0(unsigned long, pv_mmu_ops.read_cr2);
 }
 
 static inline void write_cr2(unsigned long x)
 {
-       PVOP_VCALL1(write_cr2, x);
+       PVOP_VCALL1(pv_mmu_ops.write_cr2, x);
 }
 
 static inline unsigned long read_cr3(void)
 {
-       return PVOP_CALL0(unsigned long, read_cr3);
+       return PVOP_CALL0(unsigned long, pv_mmu_ops.read_cr3);
 }
 
 static inline void write_cr3(unsigned long x)
 {
-       PVOP_VCALL1(write_cr3, x);
+       PVOP_VCALL1(pv_mmu_ops.write_cr3, x);
 }
 
 static inline unsigned long read_cr4(void)
 {
-       return PVOP_CALL0(unsigned long, read_cr4);
+       return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr4);
 }
 static inline unsigned long read_cr4_safe(void)
 {
-       return PVOP_CALL0(unsigned long, read_cr4_safe);
+       return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr4_safe);
 }
 
 static inline void write_cr4(unsigned long x)
 {
-       PVOP_VCALL1(write_cr4, x);
+       PVOP_VCALL1(pv_cpu_ops.write_cr4, x);
 }
 
 static inline void raw_safe_halt(void)
 {
-       PVOP_VCALL0(safe_halt);
+       PVOP_VCALL0(pv_irq_ops.safe_halt);
 }
 
 static inline void halt(void)
 {
-       PVOP_VCALL0(safe_halt);
+       PVOP_VCALL0(pv_irq_ops.safe_halt);
 }
 
 static inline void wbinvd(void)
 {
-       PVOP_VCALL0(wbinvd);
+       PVOP_VCALL0(pv_cpu_ops.wbinvd);
 }
 
-#define get_kernel_rpl()  (paravirt_ops.kernel_rpl)
+#define get_kernel_rpl()  (pv_info.kernel_rpl)
 
 static inline u64 paravirt_read_msr(unsigned msr, int *err)
 {
-       return PVOP_CALL2(u64, read_msr, msr, err);
+       return PVOP_CALL2(u64, pv_cpu_ops.read_msr, msr, err);
 }
 static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high)
 {
-       return PVOP_CALL3(int, write_msr, msr, low, high);
+       return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high);
 }
 
 /* These should all do BUG_ON(_err), but our headers are too tangled. */
@@ -560,7 +644,7 @@ static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high)
 
 static inline u64 paravirt_read_tsc(void)
 {
-       return PVOP_CALL0(u64, read_tsc);
+       return PVOP_CALL0(u64, pv_cpu_ops.read_tsc);
 }
 
 #define rdtscl(low) do {                       \
@@ -572,15 +656,13 @@ static inline u64 paravirt_read_tsc(void)
 
 static inline unsigned long long paravirt_sched_clock(void)
 {
-       return PVOP_CALL0(unsigned long long, sched_clock);
+       return PVOP_CALL0(unsigned long long, pv_time_ops.sched_clock);
 }
-#define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
-
-#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
+#define calculate_cpu_khz() (pv_time_ops.get_cpu_khz())
 
 static inline unsigned long long paravirt_read_pmc(int counter)
 {
-       return PVOP_CALL1(u64, read_pmc, counter);
+       return PVOP_CALL1(u64, pv_cpu_ops.read_pmc, counter);
 }
 
 #define rdpmc(counter,low,high) do {           \
@@ -589,63 +671,89 @@ static inline unsigned long long paravirt_read_pmc(int counter)
        high = _l >> 32;                        \
 } while(0)
 
+static inline unsigned long long paravirt_rdtscp(unsigned int *aux)
+{
+       return PVOP_CALL1(u64, pv_cpu_ops.read_tscp, aux);
+}
+
+#define rdtscp(low, high, aux)                         \
+do {                                                   \
+       int __aux;                                      \
+       unsigned long __val = paravirt_rdtscp(&__aux);  \
+       (low) = (u32)__val;                             \
+       (high) = (u32)(__val >> 32);                    \
+       (aux) = __aux;                                  \
+} while (0)
+
+#define rdtscpll(val, aux)                             \
+do {                                                   \
+       unsigned long __aux;                            \
+       val = paravirt_rdtscp(&__aux);                  \
+       (aux) = __aux;                                  \
+} while (0)
+
 static inline void load_TR_desc(void)
 {
-       PVOP_VCALL0(load_tr_desc);
+       PVOP_VCALL0(pv_cpu_ops.load_tr_desc);
 }
-static inline void load_gdt(const struct Xgt_desc_struct *dtr)
+static inline void load_gdt(const struct desc_ptr *dtr)
 {
-       PVOP_VCALL1(load_gdt, dtr);
+       PVOP_VCALL1(pv_cpu_ops.load_gdt, dtr);
 }
-static inline void load_idt(const struct Xgt_desc_struct *dtr)
+static inline void load_idt(const struct desc_ptr *dtr)
 {
-       PVOP_VCALL1(load_idt, dtr);
+       PVOP_VCALL1(pv_cpu_ops.load_idt, dtr);
 }
 static inline void set_ldt(const void *addr, unsigned entries)
 {
-       PVOP_VCALL2(set_ldt, addr, entries);
+       PVOP_VCALL2(pv_cpu_ops.set_ldt, addr, entries);
 }
-static inline void store_gdt(struct Xgt_desc_struct *dtr)
+static inline void store_gdt(struct desc_ptr *dtr)
 {
-       PVOP_VCALL1(store_gdt, dtr);
+       PVOP_VCALL1(pv_cpu_ops.store_gdt, dtr);
 }
-static inline void store_idt(struct Xgt_desc_struct *dtr)
+static inline void store_idt(struct desc_ptr *dtr)
 {
-       PVOP_VCALL1(store_idt, dtr);
+       PVOP_VCALL1(pv_cpu_ops.store_idt, dtr);
 }
 static inline unsigned long paravirt_store_tr(void)
 {
-       return PVOP_CALL0(unsigned long, store_tr);
+       return PVOP_CALL0(unsigned long, pv_cpu_ops.store_tr);
 }
 #define store_tr(tr)   ((tr) = paravirt_store_tr())
 static inline void load_TLS(struct thread_struct *t, unsigned cpu)
 {
-       PVOP_VCALL2(load_tls, t, cpu);
+       PVOP_VCALL2(pv_cpu_ops.load_tls, t, cpu);
 }
-static inline void write_ldt_entry(void *dt, int entry, u32 low, u32 high)
+
+static inline void write_ldt_entry(struct desc_struct *dt, int entry,
+                                  const void *desc)
 {
-       PVOP_VCALL4(write_ldt_entry, dt, entry, low, high);
+       PVOP_VCALL3(pv_cpu_ops.write_ldt_entry, dt, entry, desc);
 }
-static inline void write_gdt_entry(void *dt, int entry, u32 low, u32 high)
+
+static inline void write_gdt_entry(struct desc_struct *dt, int entry,
+                                  void *desc, int type)
 {
-       PVOP_VCALL4(write_gdt_entry, dt, entry, low, high);
+       PVOP_VCALL4(pv_cpu_ops.write_gdt_entry, dt, entry, desc, type);
 }
-static inline void write_idt_entry(void *dt, int entry, u32 low, u32 high)
+
+static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
 {
-       PVOP_VCALL4(write_idt_entry, dt, entry, low, high);
+       PVOP_VCALL3(pv_cpu_ops.write_idt_entry, dt, entry, g);
 }
 static inline void set_iopl_mask(unsigned mask)
 {
-       PVOP_VCALL1(set_iopl_mask, mask);
+       PVOP_VCALL1(pv_cpu_ops.set_iopl_mask, mask);
 }
 
 /* The paravirtualized I/O functions */
 static inline void slow_down_io(void) {
-       paravirt_ops.io_delay();
+       pv_cpu_ops.io_delay();
 #ifdef REALLY_SLOW_IO
-       paravirt_ops.io_delay();
-       paravirt_ops.io_delay();
-       paravirt_ops.io_delay();
+       pv_cpu_ops.io_delay();
+       pv_cpu_ops.io_delay();
+       pv_cpu_ops.io_delay();
 #endif
 }
 
@@ -653,123 +761,122 @@ static inline void slow_down_io(void) {
 /*
  * Basic functions accessing APICs.
  */
-static inline void apic_write(unsigned long reg, unsigned long v)
+static inline void apic_write(unsigned long reg, u32 v)
 {
-       PVOP_VCALL2(apic_write, reg, v);
+       PVOP_VCALL2(pv_apic_ops.apic_write, reg, v);
 }
 
-static inline void apic_write_atomic(unsigned long reg, unsigned long v)
+static inline void apic_write_atomic(unsigned long reg, u32 v)
 {
-       PVOP_VCALL2(apic_write_atomic, reg, v);
+       PVOP_VCALL2(pv_apic_ops.apic_write_atomic, reg, v);
 }
 
-static inline unsigned long apic_read(unsigned long reg)
+static inline u32 apic_read(unsigned long reg)
 {
-       return PVOP_CALL1(unsigned long, apic_read, reg);
+       return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg);
 }
 
 static inline void setup_boot_clock(void)
 {
-       PVOP_VCALL0(setup_boot_clock);
+       PVOP_VCALL0(pv_apic_ops.setup_boot_clock);
 }
 
 static inline void setup_secondary_clock(void)
 {
-       PVOP_VCALL0(setup_secondary_clock);
+       PVOP_VCALL0(pv_apic_ops.setup_secondary_clock);
 }
 #endif
 
 static inline void paravirt_post_allocator_init(void)
 {
-       if (paravirt_ops.post_allocator_init)
-               (*paravirt_ops.post_allocator_init)();
+       if (pv_init_ops.post_allocator_init)
+               (*pv_init_ops.post_allocator_init)();
 }
 
 static inline void paravirt_pagetable_setup_start(pgd_t *base)
 {
-       if (paravirt_ops.pagetable_setup_start)
-               (*paravirt_ops.pagetable_setup_start)(base);
+       (*pv_mmu_ops.pagetable_setup_start)(base);
 }
 
 static inline void paravirt_pagetable_setup_done(pgd_t *base)
 {
-       if (paravirt_ops.pagetable_setup_done)
-               (*paravirt_ops.pagetable_setup_done)(base);
+       (*pv_mmu_ops.pagetable_setup_done)(base);
 }
 
 #ifdef CONFIG_SMP
 static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip,
                                    unsigned long start_esp)
 {
-       PVOP_VCALL3(startup_ipi_hook, phys_apicid, start_eip, start_esp);
+       PVOP_VCALL3(pv_apic_ops.startup_ipi_hook,
+                   phys_apicid, start_eip, start_esp);
 }
 #endif
 
 static inline void paravirt_activate_mm(struct mm_struct *prev,
                                        struct mm_struct *next)
 {
-       PVOP_VCALL2(activate_mm, prev, next);
+       PVOP_VCALL2(pv_mmu_ops.activate_mm, prev, next);
 }
 
 static inline void arch_dup_mmap(struct mm_struct *oldmm,
                                 struct mm_struct *mm)
 {
-       PVOP_VCALL2(dup_mmap, oldmm, mm);
+       PVOP_VCALL2(pv_mmu_ops.dup_mmap, oldmm, mm);
 }
 
 static inline void arch_exit_mmap(struct mm_struct *mm)
 {
-       PVOP_VCALL1(exit_mmap, mm);
+       PVOP_VCALL1(pv_mmu_ops.exit_mmap, mm);
 }
 
 static inline void __flush_tlb(void)
 {
-       PVOP_VCALL0(flush_tlb_user);
+       PVOP_VCALL0(pv_mmu_ops.flush_tlb_user);
 }
 static inline void __flush_tlb_global(void)
 {
-       PVOP_VCALL0(flush_tlb_kernel);
+       PVOP_VCALL0(pv_mmu_ops.flush_tlb_kernel);
 }
 static inline void __flush_tlb_single(unsigned long addr)
 {
-       PVOP_VCALL1(flush_tlb_single, addr);
+       PVOP_VCALL1(pv_mmu_ops.flush_tlb_single, addr);
 }
 
 static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
                                    unsigned long va)
 {
-       PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
+       PVOP_VCALL3(pv_mmu_ops.flush_tlb_others, &cpumask, mm, va);
 }
 
 static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn)
 {
-       PVOP_VCALL2(alloc_pt, mm, pfn);
+       PVOP_VCALL2(pv_mmu_ops.alloc_pt, mm, pfn);
 }
 static inline void paravirt_release_pt(unsigned pfn)
 {
-       PVOP_VCALL1(release_pt, pfn);
+       PVOP_VCALL1(pv_mmu_ops.release_pt, pfn);
 }
 
 static inline void paravirt_alloc_pd(unsigned pfn)
 {
-       PVOP_VCALL1(alloc_pd, pfn);
+       PVOP_VCALL1(pv_mmu_ops.alloc_pd, pfn);
 }
 
 static inline void paravirt_alloc_pd_clone(unsigned pfn, unsigned clonepfn,
                                           unsigned start, unsigned count)
 {
-       PVOP_VCALL4(alloc_pd_clone, pfn, clonepfn, start, count);
+       PVOP_VCALL4(pv_mmu_ops.alloc_pd_clone, pfn, clonepfn, start, count);
 }
 static inline void paravirt_release_pd(unsigned pfn)
 {
-       PVOP_VCALL1(release_pd, pfn);
+       PVOP_VCALL1(pv_mmu_ops.release_pd, pfn);
 }
 
 #ifdef CONFIG_HIGHPTE
 static inline void *kmap_atomic_pte(struct page *page, enum km_type type)
 {
        unsigned long ret;
-       ret = PVOP_CALL2(unsigned long, kmap_atomic_pte, page, type);
+       ret = PVOP_CALL2(unsigned long, pv_mmu_ops.kmap_atomic_pte, page, type);
        return (void *)ret;
 }
 #endif
@@ -777,162 +884,191 @@ static inline void *kmap_atomic_pte(struct page *page, enum km_type type)
 static inline void pte_update(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep)
 {
-       PVOP_VCALL3(pte_update, mm, addr, ptep);
+       PVOP_VCALL3(pv_mmu_ops.pte_update, mm, addr, ptep);
 }
 
 static inline void pte_update_defer(struct mm_struct *mm, unsigned long addr,
                                    pte_t *ptep)
 {
-       PVOP_VCALL3(pte_update_defer, mm, addr, ptep);
+       PVOP_VCALL3(pv_mmu_ops.pte_update_defer, mm, addr, ptep);
 }
 
 #ifdef CONFIG_X86_PAE
 static inline pte_t __pte(unsigned long long val)
 {
-       unsigned long long ret = PVOP_CALL2(unsigned long long, make_pte,
+       unsigned long long ret = PVOP_CALL2(unsigned long long,
+                                           pv_mmu_ops.make_pte,
                                            val, val >> 32);
        return (pte_t) { ret, ret >> 32 };
 }
 
 static inline pmd_t __pmd(unsigned long long val)
 {
-       return (pmd_t) { PVOP_CALL2(unsigned long long, make_pmd, val, val >> 32) };
+       return (pmd_t) { PVOP_CALL2(unsigned long long, pv_mmu_ops.make_pmd,
+                                   val, val >> 32) };
 }
 
 static inline pgd_t __pgd(unsigned long long val)
 {
-       return (pgd_t) { PVOP_CALL2(unsigned long long, make_pgd, val, val >> 32) };
+       return (pgd_t) { PVOP_CALL2(unsigned long long, pv_mmu_ops.make_pgd,
+                                   val, val >> 32) };
 }
 
 static inline unsigned long long pte_val(pte_t x)
 {
-       return PVOP_CALL2(unsigned long long, pte_val, x.pte_low, x.pte_high);
+       return PVOP_CALL2(unsigned long long, pv_mmu_ops.pte_val,
+                         x.pte_low, x.pte_high);
 }
 
 static inline unsigned long long pmd_val(pmd_t x)
 {
-       return PVOP_CALL2(unsigned long long, pmd_val, x.pmd, x.pmd >> 32);
+       return PVOP_CALL2(unsigned long long, pv_mmu_ops.pmd_val,
+                         x.pmd, x.pmd >> 32);
 }
 
 static inline unsigned long long pgd_val(pgd_t x)
 {
-       return PVOP_CALL2(unsigned long long, pgd_val, x.pgd, x.pgd >> 32);
+       return PVOP_CALL2(unsigned long long, pv_mmu_ops.pgd_val,
+                         x.pgd, x.pgd >> 32);
 }
 
 static inline void set_pte(pte_t *ptep, pte_t pteval)
 {
-       PVOP_VCALL3(set_pte, ptep, pteval.pte_low, pteval.pte_high);
+       PVOP_VCALL3(pv_mmu_ops.set_pte, ptep, pteval.pte_low, pteval.pte_high);
 }
 
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pteval)
 {
        /* 5 arg words */
-       paravirt_ops.set_pte_at(mm, addr, ptep, pteval);
+       pv_mmu_ops.set_pte_at(mm, addr, ptep, pteval);
 }
 
 static inline void set_pte_atomic(pte_t *ptep, pte_t pteval)
 {
-       PVOP_VCALL3(set_pte_atomic, ptep, pteval.pte_low, pteval.pte_high);
+       PVOP_VCALL3(pv_mmu_ops.set_pte_atomic, ptep,
+                   pteval.pte_low, pteval.pte_high);
 }
 
 static inline void set_pte_present(struct mm_struct *mm, unsigned long addr,
                                   pte_t *ptep, pte_t pte)
 {
        /* 5 arg words */
-       paravirt_ops.set_pte_present(mm, addr, ptep, pte);
+       pv_mmu_ops.set_pte_present(mm, addr, ptep, pte);
 }
 
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
-       PVOP_VCALL3(set_pmd, pmdp, pmdval.pmd, pmdval.pmd >> 32);
+       PVOP_VCALL3(pv_mmu_ops.set_pmd, pmdp,
+                   pmdval.pmd, pmdval.pmd >> 32);
 }
 
 static inline void set_pud(pud_t *pudp, pud_t pudval)
 {
-       PVOP_VCALL3(set_pud, pudp, pudval.pgd.pgd, pudval.pgd.pgd >> 32);
+       PVOP_VCALL3(pv_mmu_ops.set_pud, pudp,
+                   pudval.pgd.pgd, pudval.pgd.pgd >> 32);
 }
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-       PVOP_VCALL3(pte_clear, mm, addr, ptep);
+       PVOP_VCALL3(pv_mmu_ops.pte_clear, mm, addr, ptep);
 }
 
 static inline void pmd_clear(pmd_t *pmdp)
 {
-       PVOP_VCALL1(pmd_clear, pmdp);
+       PVOP_VCALL1(pv_mmu_ops.pmd_clear, pmdp);
 }
 
 #else  /* !CONFIG_X86_PAE */
 
 static inline pte_t __pte(unsigned long val)
 {
-       return (pte_t) { PVOP_CALL1(unsigned long, make_pte, val) };
+       return (pte_t) { PVOP_CALL1(unsigned long, pv_mmu_ops.make_pte, val) };
 }
 
 static inline pgd_t __pgd(unsigned long val)
 {
-       return (pgd_t) { PVOP_CALL1(unsigned long, make_pgd, val) };
+       return (pgd_t) { PVOP_CALL1(unsigned long, pv_mmu_ops.make_pgd, val) };
 }
 
 static inline unsigned long pte_val(pte_t x)
 {
-       return PVOP_CALL1(unsigned long, pte_val, x.pte_low);
+       return PVOP_CALL1(unsigned long, pv_mmu_ops.pte_val, x.pte_low);
 }
 
 static inline unsigned long pgd_val(pgd_t x)
 {
-       return PVOP_CALL1(unsigned long, pgd_val, x.pgd);
+       return PVOP_CALL1(unsigned long, pv_mmu_ops.pgd_val, x.pgd);
 }
 
 static inline void set_pte(pte_t *ptep, pte_t pteval)
 {
-       PVOP_VCALL2(set_pte, ptep, pteval.pte_low);
+       PVOP_VCALL2(pv_mmu_ops.set_pte, ptep, pteval.pte_low);
 }
 
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pteval)
 {
-       PVOP_VCALL4(set_pte_at, mm, addr, ptep, pteval.pte_low);
+       PVOP_VCALL4(pv_mmu_ops.set_pte_at, mm, addr, ptep, pteval.pte_low);
 }
 
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
-       PVOP_VCALL2(set_pmd, pmdp, pmdval.pud.pgd.pgd);
+       PVOP_VCALL2(pv_mmu_ops.set_pmd, pmdp, pmdval.pud.pgd.pgd);
 }
 #endif /* CONFIG_X86_PAE */
 
+/* Lazy mode for batching updates / context switch */
+enum paravirt_lazy_mode {
+       PARAVIRT_LAZY_NONE,
+       PARAVIRT_LAZY_MMU,
+       PARAVIRT_LAZY_CPU,
+};
+
+enum paravirt_lazy_mode paravirt_get_lazy_mode(void);
+void paravirt_enter_lazy_cpu(void);
+void paravirt_leave_lazy_cpu(void);
+void paravirt_enter_lazy_mmu(void);
+void paravirt_leave_lazy_mmu(void);
+void paravirt_leave_lazy(enum paravirt_lazy_mode mode);
+
 #define  __HAVE_ARCH_ENTER_LAZY_CPU_MODE
 static inline void arch_enter_lazy_cpu_mode(void)
 {
-       PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_CPU);
+       PVOP_VCALL0(pv_cpu_ops.lazy_mode.enter);
 }
 
 static inline void arch_leave_lazy_cpu_mode(void)
 {
-       PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_NONE);
+       PVOP_VCALL0(pv_cpu_ops.lazy_mode.leave);
 }
 
 static inline void arch_flush_lazy_cpu_mode(void)
 {
-       PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_FLUSH);
+       if (unlikely(paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU)) {
+               arch_leave_lazy_cpu_mode();
+               arch_enter_lazy_cpu_mode();
+       }
 }
 
 
 #define  __HAVE_ARCH_ENTER_LAZY_MMU_MODE
 static inline void arch_enter_lazy_mmu_mode(void)
 {
-       PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_MMU);
+       PVOP_VCALL0(pv_mmu_ops.lazy_mode.enter);
 }
 
 static inline void arch_leave_lazy_mmu_mode(void)
 {
-       PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_NONE);
+       PVOP_VCALL0(pv_mmu_ops.lazy_mode.leave);
 }
 
 static inline void arch_flush_lazy_mmu_mode(void)
 {
-       PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_FLUSH);
+       if (unlikely(paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU)) {
+               arch_leave_lazy_mmu_mode();
+               arch_enter_lazy_mmu_mode();
+       }
 }
 
 void _paravirt_nop(void);
@@ -949,52 +1085,68 @@ struct paravirt_patch_site {
 extern struct paravirt_patch_site __parainstructions[],
        __parainstructions_end[];
 
+#ifdef CONFIG_X86_32
+#define PV_SAVE_REGS "pushl %%ecx; pushl %%edx;"
+#define PV_RESTORE_REGS "popl %%edx; popl %%ecx"
+#define PV_FLAGS_ARG "0"
+#define PV_EXTRA_CLOBBERS
+#define PV_VEXTRA_CLOBBERS
+#else
+/* We save some registers, but all of them, that's too much. We clobber all
+ * caller saved registers but the argument parameter */
+#define PV_SAVE_REGS "pushq %%rdi;"
+#define PV_RESTORE_REGS "popq %%rdi;"
+#define PV_EXTRA_CLOBBERS EXTRA_CLOBBERS, "rcx" , "rdx"
+#define PV_VEXTRA_CLOBBERS EXTRA_CLOBBERS, "rdi", "rcx" , "rdx"
+#define PV_FLAGS_ARG "D"
+#endif
+
 static inline unsigned long __raw_local_save_flags(void)
 {
        unsigned long f;
 
-       asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+       asm volatile(paravirt_alt(PV_SAVE_REGS
                                  PARAVIRT_CALL
-                                 "popl %%edx; popl %%ecx")
+                                 PV_RESTORE_REGS)
                     : "=a"(f)
-                    : paravirt_type(save_fl),
+                    : paravirt_type(pv_irq_ops.save_fl),
                       paravirt_clobber(CLBR_EAX)
-                    : "memory", "cc");
+                    : "memory", "cc" PV_VEXTRA_CLOBBERS);
        return f;
 }
 
 static inline void raw_local_irq_restore(unsigned long f)
 {
-       asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+       asm volatile(paravirt_alt(PV_SAVE_REGS
                                  PARAVIRT_CALL
-                                 "popl %%edx; popl %%ecx")
+                                 PV_RESTORE_REGS)
                     : "=a"(f)
-                    : "0"(f),
-                      paravirt_type(restore_fl),
+                    : PV_FLAGS_ARG(f),
+                      paravirt_type(pv_irq_ops.restore_fl),
                       paravirt_clobber(CLBR_EAX)
-                    : "memory", "cc");
+                    : "memory", "cc" PV_EXTRA_CLOBBERS);
 }
 
 static inline void raw_local_irq_disable(void)
 {
-       asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+       asm volatile(paravirt_alt(PV_SAVE_REGS
                                  PARAVIRT_CALL
-                                 "popl %%edx; popl %%ecx")
+                                 PV_RESTORE_REGS)
                     :
-                    : paravirt_type(irq_disable),
+                    : paravirt_type(pv_irq_ops.irq_disable),
                       paravirt_clobber(CLBR_EAX)
-                    : "memory", "eax", "cc");
+                    : "memory", "eax", "cc" PV_EXTRA_CLOBBERS);
 }
 
 static inline void raw_local_irq_enable(void)
 {
-       asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+       asm volatile(paravirt_alt(PV_SAVE_REGS
                                  PARAVIRT_CALL
-                                 "popl %%edx; popl %%ecx")
+                                 PV_RESTORE_REGS)
                     :
-                    : paravirt_type(irq_enable),
+                    : paravirt_type(pv_irq_ops.irq_enable),
                       paravirt_clobber(CLBR_EAX)
-                    : "memory", "eax", "cc");
+                    : "memory", "eax", "cc" PV_EXTRA_CLOBBERS);
 }
 
 static inline unsigned long __raw_local_irq_save(void)
@@ -1006,25 +1158,6 @@ static inline unsigned long __raw_local_irq_save(void)
        return f;
 }
 
-#define CLI_STRING                                                     \
-       _paravirt_alt("pushl %%ecx; pushl %%edx;"                       \
-                     "call *paravirt_ops+%c[paravirt_cli_type]*4;"     \
-                     "popl %%edx; popl %%ecx",                         \
-                     "%c[paravirt_cli_type]", "%c[paravirt_clobber]")
-
-#define STI_STRING                                                     \
-       _paravirt_alt("pushl %%ecx; pushl %%edx;"                       \
-                     "call *paravirt_ops+%c[paravirt_sti_type]*4;"     \
-                     "popl %%edx; popl %%ecx",                         \
-                     "%c[paravirt_sti_type]", "%c[paravirt_clobber]")
-
-#define CLI_STI_CLOBBERS , "%eax"
-#define CLI_STI_INPUT_ARGS                                             \
-       ,                                                               \
-       [paravirt_cli_type] "i" (PARAVIRT_PATCH(irq_disable)),          \
-       [paravirt_sti_type] "i" (PARAVIRT_PATCH(irq_enable)),           \
-       paravirt_clobber(CLBR_EAX)
-
 /* Make sure as little as possible of this mess escapes. */
 #undef PARAVIRT_CALL
 #undef __PVOP_CALL
@@ -1042,43 +1175,59 @@ static inline unsigned long __raw_local_irq_save(void)
 
 #else  /* __ASSEMBLY__ */
 
-#define PARA_PATCH(off)        ((off) / 4)
-
-#define PARA_SITE(ptype, clobbers, ops)                \
+#define _PVSITE(ptype, clobbers, ops, word, algn)      \
 771:;                                          \
        ops;                                    \
 772:;                                          \
        .pushsection .parainstructions,"a";     \
-        .long 771b;                            \
+        .align algn;                           \
+        word 771b;                             \
         .byte ptype;                           \
         .byte 772b-771b;                       \
         .short clobbers;                       \
        .popsection
 
-#define INTERRUPT_RETURN                                       \
-       PARA_SITE(PARA_PATCH(PARAVIRT_iret), CLBR_NONE,         \
-                 jmp *%cs:paravirt_ops+PARAVIRT_iret)
+
+#ifdef CONFIG_X86_64
+#define PV_SAVE_REGS   pushq %rax; pushq %rdi; pushq %rcx; pushq %rdx
+#define PV_RESTORE_REGS popq %rdx; popq %rcx; popq %rdi; popq %rax
+#define PARA_PATCH(struct, off)        ((PARAVIRT_PATCH_##struct + (off)) / 8)
+#define PARA_SITE(ptype, clobbers, ops) _PVSITE(ptype, clobbers, ops, .quad, 8)
+#else
+#define PV_SAVE_REGS   pushl %eax; pushl %edi; pushl %ecx; pushl %edx
+#define PV_RESTORE_REGS popl %edx; popl %ecx; popl %edi; popl %eax
+#define PARA_PATCH(struct, off)        ((PARAVIRT_PATCH_##struct + (off)) / 4)
+#define PARA_SITE(ptype, clobbers, ops) _PVSITE(ptype, clobbers, ops, .long, 4)
+#endif
+
+#define INTERRUPT_RETURN                                               \
+       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_iret), CLBR_NONE,       \
+                 jmp *%cs:pv_cpu_ops+PV_CPU_iret)
 
 #define DISABLE_INTERRUPTS(clobbers)                                   \
-       PARA_SITE(PARA_PATCH(PARAVIRT_irq_disable), clobbers,           \
-                 pushl %eax; pushl %ecx; pushl %edx;                   \
-                 call *%cs:paravirt_ops+PARAVIRT_irq_disable;          \
-                 popl %edx; popl %ecx; popl %eax)                      \
+       PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_disable), clobbers, \
+                 PV_SAVE_REGS;                 \
+                 call *%cs:pv_irq_ops+PV_IRQ_irq_disable;              \
+                 PV_RESTORE_REGS;)                     \
 
 #define ENABLE_INTERRUPTS(clobbers)                                    \
-       PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable), clobbers,            \
-                 pushl %eax; pushl %ecx; pushl %edx;                   \
-                 call *%cs:paravirt_ops+PARAVIRT_irq_enable;           \
-                 popl %edx; popl %ecx; popl %eax)
+       PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_enable), clobbers,  \
+                 PV_SAVE_REGS;                 \
+                 call *%cs:pv_irq_ops+PV_IRQ_irq_enable;               \
+                 PV_RESTORE_REGS;)
 
-#define ENABLE_INTERRUPTS_SYSEXIT                                      \
-       PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable_sysexit), CLBR_NONE,   \
-                 jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit)
+#define ENABLE_INTERRUPTS_SYSCALL_RET                                  \
+       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_syscall_ret),\
+                 CLBR_NONE,                                            \
+                 jmp *%cs:pv_cpu_ops+PV_CPU_irq_enable_syscall_ret)
 
+
+#ifdef CONFIG_X86_32
 #define GET_CR0_INTO_EAX                       \
        push %ecx; push %edx;                   \
-       call *paravirt_ops+PARAVIRT_read_cr0;   \
+       call *pv_cpu_ops+PV_CPU_read_cr0;       \
        pop %edx; pop %ecx
+#endif
 
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_PARAVIRT */