diff options
| author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-08-09 09:09:29 -0400 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-08-09 09:09:29 -0400 |
| commit | 054d5c9238f3c577ad51195c3ee7803613f322cc (patch) | |
| tree | ff7d9f5c0e0ddf14230ba28f28ef69a2c0a0debf /arch/x86 | |
| parent | 11e4afb49b7fa1fc8e1ffd850c1806dd86a08204 (diff) | |
| parent | 2192482ee5ce5d5d4a6cec0c351b2d3a744606eb (diff) | |
Merge branch 'devel-stable' into devel
Diffstat (limited to 'arch/x86')
| -rw-r--r-- | arch/x86/include/asm/hypervisor.h | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/irq_vectors.h | 3 | ||||
| -rw-r--r-- | arch/x86/include/asm/kgdb.h | 20 | ||||
| -rw-r--r-- | arch/x86/include/asm/setup.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/xen/hypercall.h | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/hypervisor.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_32.S | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/kgdb.c | 189 | ||||
| -rw-r--r-- | arch/x86/xen/Kconfig | 5 | ||||
| -rw-r--r-- | arch/x86/xen/Makefile | 2 | ||||
| -rw-r--r-- | arch/x86/xen/enlighten.c | 197 | ||||
| -rw-r--r-- | arch/x86/xen/mmu.c | 35 | ||||
| -rw-r--r-- | arch/x86/xen/mmu.h | 1 | ||||
| -rw-r--r-- | arch/x86/xen/platform-pci-unplug.c | 137 | ||||
| -rw-r--r-- | arch/x86/xen/setup.c | 72 | ||||
| -rw-r--r-- | arch/x86/xen/smp.c | 2 | ||||
| -rw-r--r-- | arch/x86/xen/suspend.c | 12 | ||||
| -rw-r--r-- | arch/x86/xen/time.c | 96 | ||||
| -rw-r--r-- | arch/x86/xen/xen-ops.h | 13 |
20 files changed, 629 insertions, 173 deletions
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h index 70abda7058c8..ff2546ce7178 100644 --- a/arch/x86/include/asm/hypervisor.h +++ b/arch/x86/include/asm/hypervisor.h | |||
| @@ -45,5 +45,6 @@ extern const struct hypervisor_x86 *x86_hyper; | |||
| 45 | /* Recognized hypervisors */ | 45 | /* Recognized hypervisors */ |
| 46 | extern const struct hypervisor_x86 x86_hyper_vmware; | 46 | extern const struct hypervisor_x86 x86_hyper_vmware; |
| 47 | extern const struct hypervisor_x86 x86_hyper_ms_hyperv; | 47 | extern const struct hypervisor_x86 x86_hyper_ms_hyperv; |
| 48 | extern const struct hypervisor_x86 x86_hyper_xen_hvm; | ||
| 48 | 49 | ||
| 49 | #endif | 50 | #endif |
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 8767d99c4f64..e2ca30092557 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h | |||
| @@ -125,6 +125,9 @@ | |||
| 125 | */ | 125 | */ |
| 126 | #define MCE_SELF_VECTOR 0xeb | 126 | #define MCE_SELF_VECTOR 0xeb |
| 127 | 127 | ||
| 128 | /* Xen vector callback to receive events in a HVM domain */ | ||
| 129 | #define XEN_HVM_EVTCHN_CALLBACK 0xe9 | ||
| 130 | |||
| 128 | #define NR_VECTORS 256 | 131 | #define NR_VECTORS 256 |
| 129 | 132 | ||
| 130 | #define FPU_IRQ 13 | 133 | #define FPU_IRQ 13 |
diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h index 006da3687cdc..396f5b5fc4d7 100644 --- a/arch/x86/include/asm/kgdb.h +++ b/arch/x86/include/asm/kgdb.h | |||
| @@ -39,9 +39,11 @@ enum regnames { | |||
| 39 | GDB_FS, /* 14 */ | 39 | GDB_FS, /* 14 */ |
| 40 | GDB_GS, /* 15 */ | 40 | GDB_GS, /* 15 */ |
| 41 | }; | 41 | }; |
| 42 | #define GDB_ORIG_AX 41 | ||
| 43 | #define DBG_MAX_REG_NUM 16 | ||
| 42 | #define NUMREGBYTES ((GDB_GS+1)*4) | 44 | #define NUMREGBYTES ((GDB_GS+1)*4) |
| 43 | #else /* ! CONFIG_X86_32 */ | 45 | #else /* ! CONFIG_X86_32 */ |
| 44 | enum regnames64 { | 46 | enum regnames { |
| 45 | GDB_AX, /* 0 */ | 47 | GDB_AX, /* 0 */ |
| 46 | GDB_BX, /* 1 */ | 48 | GDB_BX, /* 1 */ |
| 47 | GDB_CX, /* 2 */ | 49 | GDB_CX, /* 2 */ |
| @@ -59,15 +61,15 @@ enum regnames64 { | |||
| 59 | GDB_R14, /* 14 */ | 61 | GDB_R14, /* 14 */ |
| 60 | GDB_R15, /* 15 */ | 62 | GDB_R15, /* 15 */ |
| 61 | GDB_PC, /* 16 */ | 63 | GDB_PC, /* 16 */ |
| 64 | GDB_PS, /* 17 */ | ||
| 65 | GDB_CS, /* 18 */ | ||
| 66 | GDB_SS, /* 19 */ | ||
| 62 | }; | 67 | }; |
| 63 | 68 | #define GDB_ORIG_AX 57 | |
| 64 | enum regnames32 { | 69 | #define DBG_MAX_REG_NUM 20 |
| 65 | GDB_PS = 34, | 70 | /* 17 64 bit regs and 3 32 bit regs */ |
| 66 | GDB_CS, | 71 | #define NUMREGBYTES ((17 * 8) + (3 * 4)) |
| 67 | GDB_SS, | 72 | #endif /* ! CONFIG_X86_32 */ |
| 68 | }; | ||
| 69 | #define NUMREGBYTES ((GDB_SS+1)*4) | ||
| 70 | #endif /* CONFIG_X86_32 */ | ||
| 71 | 73 | ||
| 72 | static inline void arch_kgdb_breakpoint(void) | 74 | static inline void arch_kgdb_breakpoint(void) |
| 73 | { | 75 | { |
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index 86b1506f4179..ef292c792d74 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h | |||
| @@ -82,7 +82,7 @@ void *extend_brk(size_t size, size_t align); | |||
| 82 | * executable.) | 82 | * executable.) |
| 83 | */ | 83 | */ |
| 84 | #define RESERVE_BRK(name,sz) \ | 84 | #define RESERVE_BRK(name,sz) \ |
| 85 | static void __section(.discard) __used \ | 85 | static void __section(.discard.text) __used \ |
| 86 | __brk_reservation_fn_##name##__(void) { \ | 86 | __brk_reservation_fn_##name##__(void) { \ |
| 87 | asm volatile ( \ | 87 | asm volatile ( \ |
| 88 | ".pushsection .brk_reservation,\"aw\",@nobits;" \ | 88 | ".pushsection .brk_reservation,\"aw\",@nobits;" \ |
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index 9c371e4a9fa6..7fda040a76cd 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h | |||
| @@ -417,6 +417,12 @@ HYPERVISOR_nmi_op(unsigned long op, unsigned long arg) | |||
| 417 | return _hypercall2(int, nmi_op, op, arg); | 417 | return _hypercall2(int, nmi_op, op, arg); |
| 418 | } | 418 | } |
| 419 | 419 | ||
| 420 | static inline unsigned long __must_check | ||
| 421 | HYPERVISOR_hvm_op(int op, void *arg) | ||
| 422 | { | ||
| 423 | return _hypercall2(unsigned long, hvm_op, op, arg); | ||
| 424 | } | ||
| 425 | |||
| 420 | static inline void | 426 | static inline void |
| 421 | MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set) | 427 | MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set) |
| 422 | { | 428 | { |
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index dd531cc56a8f..8095f8611f8a 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c | |||
| @@ -34,6 +34,9 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] = | |||
| 34 | { | 34 | { |
| 35 | &x86_hyper_vmware, | 35 | &x86_hyper_vmware, |
| 36 | &x86_hyper_ms_hyperv, | 36 | &x86_hyper_ms_hyperv, |
| 37 | #ifdef CONFIG_XEN_PVHVM | ||
| 38 | &x86_hyper_xen_hvm, | ||
| 39 | #endif | ||
| 37 | }; | 40 | }; |
| 38 | 41 | ||
| 39 | const struct hypervisor_x86 *x86_hyper; | 42 | const struct hypervisor_x86 *x86_hyper; |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index cd49141cf153..6b196834a0dd 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
| @@ -1166,6 +1166,9 @@ ENTRY(xen_failsafe_callback) | |||
| 1166 | .previous | 1166 | .previous |
| 1167 | ENDPROC(xen_failsafe_callback) | 1167 | ENDPROC(xen_failsafe_callback) |
| 1168 | 1168 | ||
| 1169 | BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK, | ||
| 1170 | xen_evtchn_do_upcall) | ||
| 1171 | |||
| 1169 | #endif /* CONFIG_XEN */ | 1172 | #endif /* CONFIG_XEN */ |
| 1170 | 1173 | ||
| 1171 | #ifdef CONFIG_FUNCTION_TRACER | 1174 | #ifdef CONFIG_FUNCTION_TRACER |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 4db7c4d12ffa..649ed17f7009 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -1329,6 +1329,9 @@ ENTRY(xen_failsafe_callback) | |||
| 1329 | CFI_ENDPROC | 1329 | CFI_ENDPROC |
| 1330 | END(xen_failsafe_callback) | 1330 | END(xen_failsafe_callback) |
| 1331 | 1331 | ||
| 1332 | apicinterrupt XEN_HVM_EVTCHN_CALLBACK \ | ||
| 1333 | xen_hvm_callback_vector xen_evtchn_do_upcall | ||
| 1334 | |||
| 1332 | #endif /* CONFIG_XEN */ | 1335 | #endif /* CONFIG_XEN */ |
| 1333 | 1336 | ||
| 1334 | /* | 1337 | /* |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 01ab17ae2ae7..ef10940e1af0 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
| @@ -49,55 +49,94 @@ | |||
| 49 | #include <asm/system.h> | 49 | #include <asm/system.h> |
| 50 | #include <asm/apic.h> | 50 | #include <asm/apic.h> |
| 51 | 51 | ||
| 52 | /** | 52 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
| 53 | * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs | ||
| 54 | * @gdb_regs: A pointer to hold the registers in the order GDB wants. | ||
| 55 | * @regs: The &struct pt_regs of the current process. | ||
| 56 | * | ||
| 57 | * Convert the pt_regs in @regs into the format for registers that | ||
| 58 | * GDB expects, stored in @gdb_regs. | ||
| 59 | */ | ||
| 60 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 61 | { | 53 | { |
| 62 | #ifndef CONFIG_X86_32 | 54 | #ifdef CONFIG_X86_32 |
| 63 | u32 *gdb_regs32 = (u32 *)gdb_regs; | 55 | { "ax", 4, offsetof(struct pt_regs, ax) }, |
| 56 | { "cx", 4, offsetof(struct pt_regs, cx) }, | ||
| 57 | { "dx", 4, offsetof(struct pt_regs, dx) }, | ||
| 58 | { "bx", 4, offsetof(struct pt_regs, bx) }, | ||
| 59 | { "sp", 4, offsetof(struct pt_regs, sp) }, | ||
| 60 | { "bp", 4, offsetof(struct pt_regs, bp) }, | ||
| 61 | { "si", 4, offsetof(struct pt_regs, si) }, | ||
| 62 | { "di", 4, offsetof(struct pt_regs, di) }, | ||
| 63 | { "ip", 4, offsetof(struct pt_regs, ip) }, | ||
| 64 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
| 65 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
| 66 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
| 67 | { "ds", 4, offsetof(struct pt_regs, ds) }, | ||
| 68 | { "es", 4, offsetof(struct pt_regs, es) }, | ||
| 69 | { "fs", 4, -1 }, | ||
| 70 | { "gs", 4, -1 }, | ||
| 71 | #else | ||
| 72 | { "ax", 8, offsetof(struct pt_regs, ax) }, | ||
| 73 | { "bx", 8, offsetof(struct pt_regs, bx) }, | ||
| 74 | { "cx", 8, offsetof(struct pt_regs, cx) }, | ||
| 75 | { "dx", 8, offsetof(struct pt_regs, dx) }, | ||
| 76 | { "si", 8, offsetof(struct pt_regs, dx) }, | ||
| 77 | { "di", 8, offsetof(struct pt_regs, di) }, | ||
| 78 | { "bp", 8, offsetof(struct pt_regs, bp) }, | ||
| 79 | { "sp", 8, offsetof(struct pt_regs, sp) }, | ||
| 80 | { "r8", 8, offsetof(struct pt_regs, r8) }, | ||
| 81 | { "r9", 8, offsetof(struct pt_regs, r9) }, | ||
| 82 | { "r10", 8, offsetof(struct pt_regs, r10) }, | ||
| 83 | { "r11", 8, offsetof(struct pt_regs, r11) }, | ||
| 84 | { "r12", 8, offsetof(struct pt_regs, r12) }, | ||
| 85 | { "r13", 8, offsetof(struct pt_regs, r13) }, | ||
| 86 | { "r14", 8, offsetof(struct pt_regs, r14) }, | ||
| 87 | { "r15", 8, offsetof(struct pt_regs, r15) }, | ||
| 88 | { "ip", 8, offsetof(struct pt_regs, ip) }, | ||
| 89 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
| 90 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
| 91 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
| 64 | #endif | 92 | #endif |
| 65 | gdb_regs[GDB_AX] = regs->ax; | 93 | }; |
| 66 | gdb_regs[GDB_BX] = regs->bx; | 94 | |
| 67 | gdb_regs[GDB_CX] = regs->cx; | 95 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
| 68 | gdb_regs[GDB_DX] = regs->dx; | 96 | { |
| 69 | gdb_regs[GDB_SI] = regs->si; | 97 | if ( |
| 70 | gdb_regs[GDB_DI] = regs->di; | ||
| 71 | gdb_regs[GDB_BP] = regs->bp; | ||
| 72 | gdb_regs[GDB_PC] = regs->ip; | ||
| 73 | #ifdef CONFIG_X86_32 | 98 | #ifdef CONFIG_X86_32 |
| 74 | gdb_regs[GDB_PS] = regs->flags; | 99 | regno == GDB_SS || regno == GDB_FS || regno == GDB_GS || |
| 75 | gdb_regs[GDB_DS] = regs->ds; | 100 | #endif |
| 76 | gdb_regs[GDB_ES] = regs->es; | 101 | regno == GDB_SP || regno == GDB_ORIG_AX) |
| 77 | gdb_regs[GDB_CS] = regs->cs; | 102 | return 0; |
| 78 | gdb_regs[GDB_FS] = 0xFFFF; | 103 | |
| 79 | gdb_regs[GDB_GS] = 0xFFFF; | 104 | if (dbg_reg_def[regno].offset != -1) |
| 80 | if (user_mode_vm(regs)) { | 105 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
| 81 | gdb_regs[GDB_SS] = regs->ss; | 106 | dbg_reg_def[regno].size); |
| 82 | gdb_regs[GDB_SP] = regs->sp; | 107 | return 0; |
| 83 | } else { | 108 | } |
| 84 | gdb_regs[GDB_SS] = __KERNEL_DS; | 109 | |
| 85 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 110 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
| 111 | { | ||
| 112 | if (regno == GDB_ORIG_AX) { | ||
| 113 | memcpy(mem, ®s->orig_ax, sizeof(regs->orig_ax)); | ||
| 114 | return "orig_ax"; | ||
| 86 | } | 115 | } |
| 87 | #else | 116 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
| 88 | gdb_regs[GDB_R8] = regs->r8; | 117 | return NULL; |
| 89 | gdb_regs[GDB_R9] = regs->r9; | 118 | |
| 90 | gdb_regs[GDB_R10] = regs->r10; | 119 | if (dbg_reg_def[regno].offset != -1) |
| 91 | gdb_regs[GDB_R11] = regs->r11; | 120 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
| 92 | gdb_regs[GDB_R12] = regs->r12; | 121 | dbg_reg_def[regno].size); |
| 93 | gdb_regs[GDB_R13] = regs->r13; | 122 | |
| 94 | gdb_regs[GDB_R14] = regs->r14; | 123 | switch (regno) { |
| 95 | gdb_regs[GDB_R15] = regs->r15; | 124 | #ifdef CONFIG_X86_32 |
| 96 | gdb_regs32[GDB_PS] = regs->flags; | 125 | case GDB_SS: |
| 97 | gdb_regs32[GDB_CS] = regs->cs; | 126 | if (!user_mode_vm(regs)) |
| 98 | gdb_regs32[GDB_SS] = regs->ss; | 127 | *(unsigned long *)mem = __KERNEL_DS; |
| 99 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 128 | break; |
| 129 | case GDB_SP: | ||
| 130 | if (!user_mode_vm(regs)) | ||
| 131 | *(unsigned long *)mem = kernel_stack_pointer(regs); | ||
| 132 | break; | ||
| 133 | case GDB_GS: | ||
| 134 | case GDB_FS: | ||
| 135 | *(unsigned long *)mem = 0xFFFF; | ||
| 136 | break; | ||
| 100 | #endif | 137 | #endif |
| 138 | } | ||
| 139 | return dbg_reg_def[regno].name; | ||
| 101 | } | 140 | } |
| 102 | 141 | ||
| 103 | /** | 142 | /** |
| @@ -150,54 +189,13 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
| 150 | gdb_regs[GDB_SP] = p->thread.sp; | 189 | gdb_regs[GDB_SP] = p->thread.sp; |
| 151 | } | 190 | } |
| 152 | 191 | ||
| 153 | /** | ||
| 154 | * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. | ||
| 155 | * @gdb_regs: A pointer to hold the registers we've received from GDB. | ||
| 156 | * @regs: A pointer to a &struct pt_regs to hold these values in. | ||
| 157 | * | ||
| 158 | * Convert the GDB regs in @gdb_regs into the pt_regs, and store them | ||
| 159 | * in @regs. | ||
| 160 | */ | ||
| 161 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 162 | { | ||
| 163 | #ifndef CONFIG_X86_32 | ||
| 164 | u32 *gdb_regs32 = (u32 *)gdb_regs; | ||
| 165 | #endif | ||
| 166 | regs->ax = gdb_regs[GDB_AX]; | ||
| 167 | regs->bx = gdb_regs[GDB_BX]; | ||
| 168 | regs->cx = gdb_regs[GDB_CX]; | ||
| 169 | regs->dx = gdb_regs[GDB_DX]; | ||
| 170 | regs->si = gdb_regs[GDB_SI]; | ||
| 171 | regs->di = gdb_regs[GDB_DI]; | ||
| 172 | regs->bp = gdb_regs[GDB_BP]; | ||
| 173 | regs->ip = gdb_regs[GDB_PC]; | ||
| 174 | #ifdef CONFIG_X86_32 | ||
| 175 | regs->flags = gdb_regs[GDB_PS]; | ||
| 176 | regs->ds = gdb_regs[GDB_DS]; | ||
| 177 | regs->es = gdb_regs[GDB_ES]; | ||
| 178 | regs->cs = gdb_regs[GDB_CS]; | ||
| 179 | #else | ||
| 180 | regs->r8 = gdb_regs[GDB_R8]; | ||
| 181 | regs->r9 = gdb_regs[GDB_R9]; | ||
| 182 | regs->r10 = gdb_regs[GDB_R10]; | ||
| 183 | regs->r11 = gdb_regs[GDB_R11]; | ||
| 184 | regs->r12 = gdb_regs[GDB_R12]; | ||
| 185 | regs->r13 = gdb_regs[GDB_R13]; | ||
| 186 | regs->r14 = gdb_regs[GDB_R14]; | ||
| 187 | regs->r15 = gdb_regs[GDB_R15]; | ||
| 188 | regs->flags = gdb_regs32[GDB_PS]; | ||
| 189 | regs->cs = gdb_regs32[GDB_CS]; | ||
| 190 | regs->ss = gdb_regs32[GDB_SS]; | ||
| 191 | #endif | ||
| 192 | } | ||
| 193 | |||
| 194 | static struct hw_breakpoint { | 192 | static struct hw_breakpoint { |
| 195 | unsigned enabled; | 193 | unsigned enabled; |
| 196 | unsigned long addr; | 194 | unsigned long addr; |
| 197 | int len; | 195 | int len; |
| 198 | int type; | 196 | int type; |
| 199 | struct perf_event **pev; | 197 | struct perf_event **pev; |
| 200 | } breakinfo[4]; | 198 | } breakinfo[HBP_NUM]; |
| 201 | 199 | ||
| 202 | static unsigned long early_dr7; | 200 | static unsigned long early_dr7; |
| 203 | 201 | ||
| @@ -205,7 +203,7 @@ static void kgdb_correct_hw_break(void) | |||
| 205 | { | 203 | { |
| 206 | int breakno; | 204 | int breakno; |
| 207 | 205 | ||
| 208 | for (breakno = 0; breakno < 4; breakno++) { | 206 | for (breakno = 0; breakno < HBP_NUM; breakno++) { |
| 209 | struct perf_event *bp; | 207 | struct perf_event *bp; |
| 210 | struct arch_hw_breakpoint *info; | 208 | struct arch_hw_breakpoint *info; |
| 211 | int val; | 209 | int val; |
| @@ -292,10 +290,10 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
| 292 | { | 290 | { |
| 293 | int i; | 291 | int i; |
| 294 | 292 | ||
| 295 | for (i = 0; i < 4; i++) | 293 | for (i = 0; i < HBP_NUM; i++) |
| 296 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) | 294 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) |
| 297 | break; | 295 | break; |
| 298 | if (i == 4) | 296 | if (i == HBP_NUM) |
| 299 | return -1; | 297 | return -1; |
| 300 | 298 | ||
| 301 | if (hw_break_release_slot(i)) { | 299 | if (hw_break_release_slot(i)) { |
| @@ -313,7 +311,7 @@ static void kgdb_remove_all_hw_break(void) | |||
| 313 | int cpu = raw_smp_processor_id(); | 311 | int cpu = raw_smp_processor_id(); |
| 314 | struct perf_event *bp; | 312 | struct perf_event *bp; |
| 315 | 313 | ||
| 316 | for (i = 0; i < 4; i++) { | 314 | for (i = 0; i < HBP_NUM; i++) { |
| 317 | if (!breakinfo[i].enabled) | 315 | if (!breakinfo[i].enabled) |
| 318 | continue; | 316 | continue; |
| 319 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | 317 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); |
| @@ -333,10 +331,10 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
| 333 | { | 331 | { |
| 334 | int i; | 332 | int i; |
| 335 | 333 | ||
| 336 | for (i = 0; i < 4; i++) | 334 | for (i = 0; i < HBP_NUM; i++) |
| 337 | if (!breakinfo[i].enabled) | 335 | if (!breakinfo[i].enabled) |
| 338 | break; | 336 | break; |
| 339 | if (i == 4) | 337 | if (i == HBP_NUM) |
| 340 | return -1; | 338 | return -1; |
| 341 | 339 | ||
| 342 | switch (bptype) { | 340 | switch (bptype) { |
| @@ -397,7 +395,7 @@ void kgdb_disable_hw_debug(struct pt_regs *regs) | |||
| 397 | 395 | ||
| 398 | /* Disable hardware debugging while we are in kgdb: */ | 396 | /* Disable hardware debugging while we are in kgdb: */ |
| 399 | set_debugreg(0UL, 7); | 397 | set_debugreg(0UL, 7); |
| 400 | for (i = 0; i < 4; i++) { | 398 | for (i = 0; i < HBP_NUM; i++) { |
| 401 | if (!breakinfo[i].enabled) | 399 | if (!breakinfo[i].enabled) |
| 402 | continue; | 400 | continue; |
| 403 | if (dbg_is_early) { | 401 | if (dbg_is_early) { |
| @@ -458,7 +456,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
| 458 | { | 456 | { |
| 459 | unsigned long addr; | 457 | unsigned long addr; |
| 460 | char *ptr; | 458 | char *ptr; |
| 461 | int newPC; | ||
| 462 | 459 | ||
| 463 | switch (remcomInBuffer[0]) { | 460 | switch (remcomInBuffer[0]) { |
| 464 | case 'c': | 461 | case 'c': |
| @@ -469,8 +466,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
| 469 | linux_regs->ip = addr; | 466 | linux_regs->ip = addr; |
| 470 | case 'D': | 467 | case 'D': |
| 471 | case 'k': | 468 | case 'k': |
| 472 | newPC = linux_regs->ip; | ||
| 473 | |||
| 474 | /* clear the trace bit */ | 469 | /* clear the trace bit */ |
| 475 | linux_regs->flags &= ~X86_EFLAGS_TF; | 470 | linux_regs->flags &= ~X86_EFLAGS_TF; |
| 476 | atomic_set(&kgdb_cpu_doing_single_step, -1); | 471 | atomic_set(&kgdb_cpu_doing_single_step, -1); |
| @@ -645,7 +640,7 @@ void kgdb_arch_late(void) | |||
| 645 | attr.bp_len = HW_BREAKPOINT_LEN_1; | 640 | attr.bp_len = HW_BREAKPOINT_LEN_1; |
| 646 | attr.bp_type = HW_BREAKPOINT_W; | 641 | attr.bp_type = HW_BREAKPOINT_W; |
| 647 | attr.disabled = 1; | 642 | attr.disabled = 1; |
| 648 | for (i = 0; i < 4; i++) { | 643 | for (i = 0; i < HBP_NUM; i++) { |
| 649 | if (breakinfo[i].pev) | 644 | if (breakinfo[i].pev) |
| 650 | continue; | 645 | continue; |
| 651 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); | 646 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); |
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index b83e119fbeb0..68128a1b401a 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig | |||
| @@ -13,6 +13,11 @@ config XEN | |||
| 13 | kernel to boot in a paravirtualized environment under the | 13 | kernel to boot in a paravirtualized environment under the |
| 14 | Xen hypervisor. | 14 | Xen hypervisor. |
| 15 | 15 | ||
| 16 | config XEN_PVHVM | ||
| 17 | def_bool y | ||
| 18 | depends on XEN | ||
| 19 | depends on X86_LOCAL_APIC | ||
| 20 | |||
| 16 | config XEN_MAX_DOMAIN_MEMORY | 21 | config XEN_MAX_DOMAIN_MEMORY |
| 17 | int "Maximum allowed size of a domain in gigabytes" | 22 | int "Maximum allowed size of a domain in gigabytes" |
| 18 | default 8 if X86_32 | 23 | default 8 if X86_32 |
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 3bb4fc21f4f2..930954685980 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile | |||
| @@ -12,7 +12,7 @@ CFLAGS_mmu.o := $(nostackp) | |||
| 12 | 12 | ||
| 13 | obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ | 13 | obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ |
| 14 | time.o xen-asm.o xen-asm_$(BITS).o \ | 14 | time.o xen-asm.o xen-asm_$(BITS).o \ |
| 15 | grant-table.o suspend.o | 15 | grant-table.o suspend.o platform-pci-unplug.o |
| 16 | 16 | ||
| 17 | obj-$(CONFIG_SMP) += smp.o | 17 | obj-$(CONFIG_SMP) += smp.o |
| 18 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o | 18 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 65d8d79b46a8..d4ff5e83621d 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 | 11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/cpu.h> | ||
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 16 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
| @@ -35,8 +36,10 @@ | |||
| 35 | #include <xen/interface/version.h> | 36 | #include <xen/interface/version.h> |
| 36 | #include <xen/interface/physdev.h> | 37 | #include <xen/interface/physdev.h> |
| 37 | #include <xen/interface/vcpu.h> | 38 | #include <xen/interface/vcpu.h> |
| 39 | #include <xen/interface/memory.h> | ||
| 38 | #include <xen/features.h> | 40 | #include <xen/features.h> |
| 39 | #include <xen/page.h> | 41 | #include <xen/page.h> |
| 42 | #include <xen/hvm.h> | ||
| 40 | #include <xen/hvc-console.h> | 43 | #include <xen/hvc-console.h> |
| 41 | 44 | ||
| 42 | #include <asm/paravirt.h> | 45 | #include <asm/paravirt.h> |
| @@ -55,7 +58,9 @@ | |||
| 55 | #include <asm/pgtable.h> | 58 | #include <asm/pgtable.h> |
| 56 | #include <asm/tlbflush.h> | 59 | #include <asm/tlbflush.h> |
| 57 | #include <asm/reboot.h> | 60 | #include <asm/reboot.h> |
| 61 | #include <asm/setup.h> | ||
| 58 | #include <asm/stackprotector.h> | 62 | #include <asm/stackprotector.h> |
| 63 | #include <asm/hypervisor.h> | ||
| 59 | 64 | ||
| 60 | #include "xen-ops.h" | 65 | #include "xen-ops.h" |
| 61 | #include "mmu.h" | 66 | #include "mmu.h" |
| @@ -76,6 +81,10 @@ struct shared_info xen_dummy_shared_info; | |||
| 76 | 81 | ||
| 77 | void *xen_initial_gdt; | 82 | void *xen_initial_gdt; |
| 78 | 83 | ||
| 84 | RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); | ||
| 85 | __read_mostly int xen_have_vector_callback; | ||
| 86 | EXPORT_SYMBOL_GPL(xen_have_vector_callback); | ||
| 87 | |||
| 79 | /* | 88 | /* |
| 80 | * Point at some empty memory to start with. We map the real shared_info | 89 | * Point at some empty memory to start with. We map the real shared_info |
| 81 | * page as soon as fixmap is up and running. | 90 | * page as soon as fixmap is up and running. |
| @@ -97,6 +106,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; | |||
| 97 | */ | 106 | */ |
| 98 | static int have_vcpu_info_placement = 1; | 107 | static int have_vcpu_info_placement = 1; |
| 99 | 108 | ||
| 109 | static void clamp_max_cpus(void) | ||
| 110 | { | ||
| 111 | #ifdef CONFIG_SMP | ||
| 112 | if (setup_max_cpus > MAX_VIRT_CPUS) | ||
| 113 | setup_max_cpus = MAX_VIRT_CPUS; | ||
| 114 | #endif | ||
| 115 | } | ||
| 116 | |||
| 100 | static void xen_vcpu_setup(int cpu) | 117 | static void xen_vcpu_setup(int cpu) |
| 101 | { | 118 | { |
| 102 | struct vcpu_register_vcpu_info info; | 119 | struct vcpu_register_vcpu_info info; |
| @@ -104,13 +121,17 @@ static void xen_vcpu_setup(int cpu) | |||
| 104 | struct vcpu_info *vcpup; | 121 | struct vcpu_info *vcpup; |
| 105 | 122 | ||
| 106 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); | 123 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); |
| 107 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
| 108 | 124 | ||
| 109 | if (!have_vcpu_info_placement) | 125 | if (cpu < MAX_VIRT_CPUS) |
| 110 | return; /* already tested, not available */ | 126 | per_cpu(xen_vcpu,cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; |
| 111 | 127 | ||
| 112 | vcpup = &per_cpu(xen_vcpu_info, cpu); | 128 | if (!have_vcpu_info_placement) { |
| 129 | if (cpu >= MAX_VIRT_CPUS) | ||
| 130 | clamp_max_cpus(); | ||
| 131 | return; | ||
| 132 | } | ||
| 113 | 133 | ||
| 134 | vcpup = &per_cpu(xen_vcpu_info, cpu); | ||
| 114 | info.mfn = arbitrary_virt_to_mfn(vcpup); | 135 | info.mfn = arbitrary_virt_to_mfn(vcpup); |
| 115 | info.offset = offset_in_page(vcpup); | 136 | info.offset = offset_in_page(vcpup); |
| 116 | 137 | ||
| @@ -125,6 +146,7 @@ static void xen_vcpu_setup(int cpu) | |||
| 125 | if (err) { | 146 | if (err) { |
| 126 | printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err); | 147 | printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err); |
| 127 | have_vcpu_info_placement = 0; | 148 | have_vcpu_info_placement = 0; |
| 149 | clamp_max_cpus(); | ||
| 128 | } else { | 150 | } else { |
| 129 | /* This cpu is using the registered vcpu info, even if | 151 | /* This cpu is using the registered vcpu info, even if |
| 130 | later ones fail to. */ | 152 | later ones fail to. */ |
| @@ -731,7 +753,6 @@ static void set_xen_basic_apic_ops(void) | |||
| 731 | 753 | ||
| 732 | #endif | 754 | #endif |
| 733 | 755 | ||
| 734 | |||
| 735 | static void xen_clts(void) | 756 | static void xen_clts(void) |
| 736 | { | 757 | { |
| 737 | struct multicall_space mcs; | 758 | struct multicall_space mcs; |
| @@ -926,10 +947,6 @@ static const struct pv_init_ops xen_init_ops __initdata = { | |||
| 926 | .patch = xen_patch, | 947 | .patch = xen_patch, |
| 927 | }; | 948 | }; |
| 928 | 949 | ||
| 929 | static const struct pv_time_ops xen_time_ops __initdata = { | ||
| 930 | .sched_clock = xen_sched_clock, | ||
| 931 | }; | ||
| 932 | |||
| 933 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { | 950 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { |
| 934 | .cpuid = xen_cpuid, | 951 | .cpuid = xen_cpuid, |
| 935 | 952 | ||
| @@ -1028,6 +1045,23 @@ static void xen_crash_shutdown(struct pt_regs *regs) | |||
| 1028 | xen_reboot(SHUTDOWN_crash); | 1045 | xen_reboot(SHUTDOWN_crash); |
| 1029 | } | 1046 | } |
| 1030 | 1047 | ||
| 1048 | static int | ||
| 1049 | xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) | ||
| 1050 | { | ||
| 1051 | xen_reboot(SHUTDOWN_crash); | ||
| 1052 | return NOTIFY_DONE; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | static struct notifier_block xen_panic_block = { | ||
| 1056 | .notifier_call= xen_panic_event, | ||
| 1057 | }; | ||
| 1058 | |||
| 1059 | int xen_panic_handler_init(void) | ||
| 1060 | { | ||
| 1061 | atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); | ||
| 1062 | return 0; | ||
| 1063 | } | ||
| 1064 | |||
| 1031 | static const struct machine_ops __initdata xen_machine_ops = { | 1065 | static const struct machine_ops __initdata xen_machine_ops = { |
| 1032 | .restart = xen_restart, | 1066 | .restart = xen_restart, |
| 1033 | .halt = xen_machine_halt, | 1067 | .halt = xen_machine_halt, |
| @@ -1067,7 +1101,6 @@ asmlinkage void __init xen_start_kernel(void) | |||
| 1067 | /* Install Xen paravirt ops */ | 1101 | /* Install Xen paravirt ops */ |
| 1068 | pv_info = xen_info; | 1102 | pv_info = xen_info; |
| 1069 | pv_init_ops = xen_init_ops; | 1103 | pv_init_ops = xen_init_ops; |
| 1070 | pv_time_ops = xen_time_ops; | ||
| 1071 | pv_cpu_ops = xen_cpu_ops; | 1104 | pv_cpu_ops = xen_cpu_ops; |
| 1072 | pv_apic_ops = xen_apic_ops; | 1105 | pv_apic_ops = xen_apic_ops; |
| 1073 | 1106 | ||
| @@ -1075,13 +1108,7 @@ asmlinkage void __init xen_start_kernel(void) | |||
| 1075 | x86_init.oem.arch_setup = xen_arch_setup; | 1108 | x86_init.oem.arch_setup = xen_arch_setup; |
| 1076 | x86_init.oem.banner = xen_banner; | 1109 | x86_init.oem.banner = xen_banner; |
| 1077 | 1110 | ||
| 1078 | x86_init.timers.timer_init = xen_time_init; | 1111 | xen_init_time_ops(); |
| 1079 | x86_init.timers.setup_percpu_clockev = x86_init_noop; | ||
| 1080 | x86_cpuinit.setup_percpu_clockev = x86_init_noop; | ||
| 1081 | |||
| 1082 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
| 1083 | x86_platform.get_wallclock = xen_get_wallclock; | ||
| 1084 | x86_platform.set_wallclock = xen_set_wallclock; | ||
| 1085 | 1112 | ||
| 1086 | /* | 1113 | /* |
| 1087 | * Set up some pagetable state before starting to set any ptes. | 1114 | * Set up some pagetable state before starting to set any ptes. |
| @@ -1206,3 +1233,139 @@ asmlinkage void __init xen_start_kernel(void) | |||
| 1206 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); | 1233 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); |
| 1207 | #endif | 1234 | #endif |
| 1208 | } | 1235 | } |
| 1236 | |||
| 1237 | static uint32_t xen_cpuid_base(void) | ||
| 1238 | { | ||
| 1239 | uint32_t base, eax, ebx, ecx, edx; | ||
| 1240 | char signature[13]; | ||
| 1241 | |||
| 1242 | for (base = 0x40000000; base < 0x40010000; base += 0x100) { | ||
| 1243 | cpuid(base, &eax, &ebx, &ecx, &edx); | ||
| 1244 | *(uint32_t *)(signature + 0) = ebx; | ||
| 1245 | *(uint32_t *)(signature + 4) = ecx; | ||
| 1246 | *(uint32_t *)(signature + 8) = edx; | ||
| 1247 | signature[12] = 0; | ||
| 1248 | |||
| 1249 | if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2)) | ||
| 1250 | return base; | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | return 0; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | static int init_hvm_pv_info(int *major, int *minor) | ||
| 1257 | { | ||
| 1258 | uint32_t eax, ebx, ecx, edx, pages, msr, base; | ||
| 1259 | u64 pfn; | ||
| 1260 | |||
| 1261 | base = xen_cpuid_base(); | ||
| 1262 | cpuid(base + 1, &eax, &ebx, &ecx, &edx); | ||
| 1263 | |||
| 1264 | *major = eax >> 16; | ||
| 1265 | *minor = eax & 0xffff; | ||
| 1266 | printk(KERN_INFO "Xen version %d.%d.\n", *major, *minor); | ||
| 1267 | |||
| 1268 | cpuid(base + 2, &pages, &msr, &ecx, &edx); | ||
| 1269 | |||
| 1270 | pfn = __pa(hypercall_page); | ||
| 1271 | wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); | ||
| 1272 | |||
| 1273 | xen_setup_features(); | ||
| 1274 | |||
| 1275 | pv_info = xen_info; | ||
| 1276 | pv_info.kernel_rpl = 0; | ||
| 1277 | |||
| 1278 | xen_domain_type = XEN_HVM_DOMAIN; | ||
| 1279 | |||
| 1280 | return 0; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | void xen_hvm_init_shared_info(void) | ||
| 1284 | { | ||
| 1285 | int cpu; | ||
| 1286 | struct xen_add_to_physmap xatp; | ||
| 1287 | static struct shared_info *shared_info_page = 0; | ||
| 1288 | |||
| 1289 | if (!shared_info_page) | ||
| 1290 | shared_info_page = (struct shared_info *) | ||
| 1291 | extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
| 1292 | xatp.domid = DOMID_SELF; | ||
| 1293 | xatp.idx = 0; | ||
| 1294 | xatp.space = XENMAPSPACE_shared_info; | ||
| 1295 | xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; | ||
| 1296 | if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) | ||
| 1297 | BUG(); | ||
| 1298 | |||
| 1299 | HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; | ||
| 1300 | |||
| 1301 | /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info | ||
| 1302 | * page, we use it in the event channel upcall and in some pvclock | ||
| 1303 | * related functions. We don't need the vcpu_info placement | ||
| 1304 | * optimizations because we don't use any pv_mmu or pv_irq op on | ||
| 1305 | * HVM. | ||
| 1306 | * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is | ||
| 1307 | * online but xen_hvm_init_shared_info is run at resume time too and | ||
| 1308 | * in that case multiple vcpus might be online. */ | ||
| 1309 | for_each_online_cpu(cpu) { | ||
| 1310 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
| 1311 | } | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | #ifdef CONFIG_XEN_PVHVM | ||
| 1315 | static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, | ||
| 1316 | unsigned long action, void *hcpu) | ||
| 1317 | { | ||
| 1318 | int cpu = (long)hcpu; | ||
| 1319 | switch (action) { | ||
| 1320 | case CPU_UP_PREPARE: | ||
| 1321 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
| 1322 | break; | ||
| 1323 | default: | ||
| 1324 | break; | ||
| 1325 | } | ||
| 1326 | return NOTIFY_OK; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = { | ||
| 1330 | .notifier_call = xen_hvm_cpu_notify, | ||
| 1331 | }; | ||
| 1332 | |||
| 1333 | static void __init xen_hvm_guest_init(void) | ||
| 1334 | { | ||
| 1335 | int r; | ||
| 1336 | int major, minor; | ||
| 1337 | |||
| 1338 | r = init_hvm_pv_info(&major, &minor); | ||
| 1339 | if (r < 0) | ||
| 1340 | return; | ||
| 1341 | |||
| 1342 | xen_hvm_init_shared_info(); | ||
| 1343 | |||
| 1344 | if (xen_feature(XENFEAT_hvm_callback_vector)) | ||
| 1345 | xen_have_vector_callback = 1; | ||
| 1346 | register_cpu_notifier(&xen_hvm_cpu_notifier); | ||
| 1347 | xen_unplug_emulated_devices(); | ||
| 1348 | have_vcpu_info_placement = 0; | ||
| 1349 | x86_init.irqs.intr_init = xen_init_IRQ; | ||
| 1350 | xen_hvm_init_time_ops(); | ||
| 1351 | xen_hvm_init_mmu_ops(); | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | static bool __init xen_hvm_platform(void) | ||
| 1355 | { | ||
| 1356 | if (xen_pv_domain()) | ||
| 1357 | return false; | ||
| 1358 | |||
| 1359 | if (!xen_cpuid_base()) | ||
| 1360 | return false; | ||
| 1361 | |||
| 1362 | return true; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = { | ||
| 1366 | .name = "Xen HVM", | ||
| 1367 | .detect = xen_hvm_platform, | ||
| 1368 | .init_platform = xen_hvm_guest_init, | ||
| 1369 | }; | ||
| 1370 | EXPORT_SYMBOL(x86_hyper_xen_hvm); | ||
| 1371 | #endif | ||
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 914f04695ce5..413b19b3d0fe 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
| @@ -58,6 +58,7 @@ | |||
| 58 | 58 | ||
| 59 | #include <xen/page.h> | 59 | #include <xen/page.h> |
| 60 | #include <xen/interface/xen.h> | 60 | #include <xen/interface/xen.h> |
| 61 | #include <xen/interface/hvm/hvm_op.h> | ||
| 61 | #include <xen/interface/version.h> | 62 | #include <xen/interface/version.h> |
| 62 | #include <xen/hvc-console.h> | 63 | #include <xen/hvc-console.h> |
| 63 | 64 | ||
| @@ -1941,6 +1942,40 @@ void __init xen_init_mmu_ops(void) | |||
| 1941 | pv_mmu_ops = xen_mmu_ops; | 1942 | pv_mmu_ops = xen_mmu_ops; |
| 1942 | } | 1943 | } |
| 1943 | 1944 | ||
| 1945 | #ifdef CONFIG_XEN_PVHVM | ||
| 1946 | static void xen_hvm_exit_mmap(struct mm_struct *mm) | ||
| 1947 | { | ||
| 1948 | struct xen_hvm_pagetable_dying a; | ||
| 1949 | int rc; | ||
| 1950 | |||
| 1951 | a.domid = DOMID_SELF; | ||
| 1952 | a.gpa = __pa(mm->pgd); | ||
| 1953 | rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a); | ||
| 1954 | WARN_ON_ONCE(rc < 0); | ||
| 1955 | } | ||
| 1956 | |||
| 1957 | static int is_pagetable_dying_supported(void) | ||
| 1958 | { | ||
| 1959 | struct xen_hvm_pagetable_dying a; | ||
| 1960 | int rc = 0; | ||
| 1961 | |||
| 1962 | a.domid = DOMID_SELF; | ||
| 1963 | a.gpa = 0x00; | ||
| 1964 | rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a); | ||
| 1965 | if (rc < 0) { | ||
| 1966 | printk(KERN_DEBUG "HVMOP_pagetable_dying not supported\n"); | ||
| 1967 | return 0; | ||
| 1968 | } | ||
| 1969 | return 1; | ||
| 1970 | } | ||
| 1971 | |||
| 1972 | void __init xen_hvm_init_mmu_ops(void) | ||
| 1973 | { | ||
| 1974 | if (is_pagetable_dying_supported()) | ||
| 1975 | pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap; | ||
| 1976 | } | ||
| 1977 | #endif | ||
| 1978 | |||
| 1944 | #ifdef CONFIG_XEN_DEBUG_FS | 1979 | #ifdef CONFIG_XEN_DEBUG_FS |
| 1945 | 1980 | ||
| 1946 | static struct dentry *d_mmu_debug; | 1981 | static struct dentry *d_mmu_debug; |
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h index 5fe6bc7f5ecf..fa938c4aa2f7 100644 --- a/arch/x86/xen/mmu.h +++ b/arch/x86/xen/mmu.h | |||
| @@ -60,4 +60,5 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, | |||
| 60 | unsigned long xen_read_cr2_direct(void); | 60 | unsigned long xen_read_cr2_direct(void); |
| 61 | 61 | ||
| 62 | extern void xen_init_mmu_ops(void); | 62 | extern void xen_init_mmu_ops(void); |
| 63 | extern void xen_hvm_init_mmu_ops(void); | ||
| 63 | #endif /* _XEN_MMU_H */ | 64 | #endif /* _XEN_MMU_H */ |
diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c new file mode 100644 index 000000000000..554c002a1e1a --- /dev/null +++ b/arch/x86/xen/platform-pci-unplug.c | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * platform-pci-unplug.c | ||
| 3 | * | ||
| 4 | * Xen platform PCI device driver | ||
| 5 | * Copyright (c) 2010, Citrix | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
| 18 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/io.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | |||
| 26 | #include <xen/platform_pci.h> | ||
| 27 | |||
| 28 | #define XEN_PLATFORM_ERR_MAGIC -1 | ||
| 29 | #define XEN_PLATFORM_ERR_PROTOCOL -2 | ||
| 30 | #define XEN_PLATFORM_ERR_BLACKLIST -3 | ||
| 31 | |||
| 32 | /* store the value of xen_emul_unplug after the unplug is done */ | ||
| 33 | int xen_platform_pci_unplug; | ||
| 34 | EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); | ||
| 35 | #ifdef CONFIG_XEN_PVHVM | ||
| 36 | static int xen_emul_unplug; | ||
| 37 | |||
| 38 | static int __init check_platform_magic(void) | ||
| 39 | { | ||
| 40 | short magic; | ||
| 41 | char protocol; | ||
| 42 | |||
| 43 | magic = inw(XEN_IOPORT_MAGIC); | ||
| 44 | if (magic != XEN_IOPORT_MAGIC_VAL) { | ||
| 45 | printk(KERN_ERR "Xen Platform PCI: unrecognised magic value\n"); | ||
| 46 | return XEN_PLATFORM_ERR_MAGIC; | ||
| 47 | } | ||
| 48 | |||
| 49 | protocol = inb(XEN_IOPORT_PROTOVER); | ||
| 50 | |||
| 51 | printk(KERN_DEBUG "Xen Platform PCI: I/O protocol version %d\n", | ||
| 52 | protocol); | ||
| 53 | |||
| 54 | switch (protocol) { | ||
| 55 | case 1: | ||
| 56 | outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM); | ||
| 57 | outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER); | ||
| 58 | if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) { | ||
| 59 | printk(KERN_ERR "Xen Platform: blacklisted by host\n"); | ||
| 60 | return XEN_PLATFORM_ERR_BLACKLIST; | ||
| 61 | } | ||
| 62 | break; | ||
| 63 | default: | ||
| 64 | printk(KERN_WARNING "Xen Platform PCI: unknown I/O protocol version"); | ||
| 65 | return XEN_PLATFORM_ERR_PROTOCOL; | ||
| 66 | } | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | void __init xen_unplug_emulated_devices(void) | ||
| 72 | { | ||
| 73 | int r; | ||
| 74 | |||
| 75 | /* check the version of the xen platform PCI device */ | ||
| 76 | r = check_platform_magic(); | ||
| 77 | /* If the version matches enable the Xen platform PCI driver. | ||
| 78 | * Also enable the Xen platform PCI driver if the version is really old | ||
| 79 | * and the user told us to ignore it. */ | ||
| 80 | if (r && !(r == XEN_PLATFORM_ERR_MAGIC && | ||
| 81 | (xen_emul_unplug & XEN_UNPLUG_IGNORE))) | ||
| 82 | return; | ||
| 83 | /* Set the default value of xen_emul_unplug depending on whether or | ||
| 84 | * not the Xen PV frontends and the Xen platform PCI driver have | ||
| 85 | * been compiled for this kernel (modules or built-in are both OK). */ | ||
| 86 | if (!xen_emul_unplug) { | ||
| 87 | if (xen_must_unplug_nics()) { | ||
| 88 | printk(KERN_INFO "Netfront and the Xen platform PCI driver have " | ||
| 89 | "been compiled for this kernel: unplug emulated NICs.\n"); | ||
| 90 | xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; | ||
| 91 | } | ||
| 92 | if (xen_must_unplug_disks()) { | ||
| 93 | printk(KERN_INFO "Blkfront and the Xen platform PCI driver have " | ||
| 94 | "been compiled for this kernel: unplug emulated disks.\n" | ||
| 95 | "You might have to change the root device\n" | ||
| 96 | "from /dev/hd[a-d] to /dev/xvd[a-d]\n" | ||
| 97 | "in your root= kernel command line option\n"); | ||
| 98 | xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | /* Now unplug the emulated devices */ | ||
| 102 | if (!(xen_emul_unplug & XEN_UNPLUG_IGNORE)) | ||
| 103 | outw(xen_emul_unplug, XEN_IOPORT_UNPLUG); | ||
| 104 | xen_platform_pci_unplug = xen_emul_unplug; | ||
| 105 | } | ||
| 106 | |||
| 107 | static int __init parse_xen_emul_unplug(char *arg) | ||
| 108 | { | ||
| 109 | char *p, *q; | ||
| 110 | int l; | ||
| 111 | |||
| 112 | for (p = arg; p; p = q) { | ||
| 113 | q = strchr(p, ','); | ||
| 114 | if (q) { | ||
| 115 | l = q - p; | ||
| 116 | q++; | ||
| 117 | } else { | ||
| 118 | l = strlen(p); | ||
| 119 | } | ||
| 120 | if (!strncmp(p, "all", l)) | ||
| 121 | xen_emul_unplug |= XEN_UNPLUG_ALL; | ||
| 122 | else if (!strncmp(p, "ide-disks", l)) | ||
| 123 | xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS; | ||
| 124 | else if (!strncmp(p, "aux-ide-disks", l)) | ||
| 125 | xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS; | ||
| 126 | else if (!strncmp(p, "nics", l)) | ||
| 127 | xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; | ||
| 128 | else if (!strncmp(p, "ignore", l)) | ||
| 129 | xen_emul_unplug |= XEN_UNPLUG_IGNORE; | ||
| 130 | else | ||
| 131 | printk(KERN_WARNING "unrecognised option '%s' " | ||
| 132 | "in parameter 'xen_emul_unplug'\n", p); | ||
| 133 | } | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | early_param("xen_emul_unplug", parse_xen_emul_unplug); | ||
| 137 | #endif | ||
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index ad0047f47cd4..328b00305426 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <xen/page.h> | 20 | #include <xen/page.h> |
| 21 | #include <xen/interface/callback.h> | 21 | #include <xen/interface/callback.h> |
| 22 | #include <xen/interface/physdev.h> | 22 | #include <xen/interface/physdev.h> |
| 23 | #include <xen/interface/memory.h> | ||
| 23 | #include <xen/features.h> | 24 | #include <xen/features.h> |
| 24 | 25 | ||
| 25 | #include "xen-ops.h" | 26 | #include "xen-ops.h" |
| @@ -32,6 +33,73 @@ extern void xen_sysenter_target(void); | |||
| 32 | extern void xen_syscall_target(void); | 33 | extern void xen_syscall_target(void); |
| 33 | extern void xen_syscall32_target(void); | 34 | extern void xen_syscall32_target(void); |
| 34 | 35 | ||
| 36 | static unsigned long __init xen_release_chunk(phys_addr_t start_addr, | ||
| 37 | phys_addr_t end_addr) | ||
| 38 | { | ||
| 39 | struct xen_memory_reservation reservation = { | ||
| 40 | .address_bits = 0, | ||
| 41 | .extent_order = 0, | ||
| 42 | .domid = DOMID_SELF | ||
| 43 | }; | ||
| 44 | unsigned long start, end; | ||
| 45 | unsigned long len = 0; | ||
| 46 | unsigned long pfn; | ||
| 47 | int ret; | ||
| 48 | |||
| 49 | start = PFN_UP(start_addr); | ||
| 50 | end = PFN_DOWN(end_addr); | ||
| 51 | |||
| 52 | if (end <= start) | ||
| 53 | return 0; | ||
| 54 | |||
| 55 | printk(KERN_INFO "xen_release_chunk: looking at area pfn %lx-%lx: ", | ||
| 56 | start, end); | ||
| 57 | for(pfn = start; pfn < end; pfn++) { | ||
| 58 | unsigned long mfn = pfn_to_mfn(pfn); | ||
| 59 | |||
| 60 | /* Make sure pfn exists to start with */ | ||
| 61 | if (mfn == INVALID_P2M_ENTRY || mfn_to_pfn(mfn) != pfn) | ||
| 62 | continue; | ||
| 63 | |||
| 64 | set_xen_guest_handle(reservation.extent_start, &mfn); | ||
| 65 | reservation.nr_extents = 1; | ||
| 66 | |||
| 67 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, | ||
| 68 | &reservation); | ||
| 69 | WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n", | ||
| 70 | start, end, ret); | ||
| 71 | if (ret == 1) { | ||
| 72 | set_phys_to_machine(pfn, INVALID_P2M_ENTRY); | ||
| 73 | len++; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | printk(KERN_CONT "%ld pages freed\n", len); | ||
| 77 | |||
| 78 | return len; | ||
| 79 | } | ||
| 80 | |||
| 81 | static unsigned long __init xen_return_unused_memory(unsigned long max_pfn, | ||
| 82 | const struct e820map *e820) | ||
| 83 | { | ||
| 84 | phys_addr_t max_addr = PFN_PHYS(max_pfn); | ||
| 85 | phys_addr_t last_end = 0; | ||
| 86 | unsigned long released = 0; | ||
| 87 | int i; | ||
| 88 | |||
| 89 | for (i = 0; i < e820->nr_map && last_end < max_addr; i++) { | ||
| 90 | phys_addr_t end = e820->map[i].addr; | ||
| 91 | end = min(max_addr, end); | ||
| 92 | |||
| 93 | released += xen_release_chunk(last_end, end); | ||
| 94 | last_end = e820->map[i].addr + e820->map[i].size; | ||
| 95 | } | ||
| 96 | |||
| 97 | if (last_end < max_addr) | ||
| 98 | released += xen_release_chunk(last_end, max_addr); | ||
| 99 | |||
| 100 | printk(KERN_INFO "released %ld pages of unused memory\n", released); | ||
| 101 | return released; | ||
| 102 | } | ||
| 35 | 103 | ||
| 36 | /** | 104 | /** |
| 37 | * machine_specific_memory_setup - Hook for machine specific memory setup. | 105 | * machine_specific_memory_setup - Hook for machine specific memory setup. |
| @@ -67,6 +135,8 @@ char * __init xen_memory_setup(void) | |||
| 67 | 135 | ||
| 68 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | 136 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); |
| 69 | 137 | ||
| 138 | xen_return_unused_memory(xen_start_info->nr_pages, &e820); | ||
| 139 | |||
| 70 | return "Xen"; | 140 | return "Xen"; |
| 71 | } | 141 | } |
| 72 | 142 | ||
| @@ -156,6 +226,8 @@ void __init xen_arch_setup(void) | |||
| 156 | struct physdev_set_iopl set_iopl; | 226 | struct physdev_set_iopl set_iopl; |
| 157 | int rc; | 227 | int rc; |
| 158 | 228 | ||
| 229 | xen_panic_handler_init(); | ||
| 230 | |||
| 159 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); | 231 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); |
| 160 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); | 232 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); |
| 161 | 233 | ||
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index a29693fd3138..25f232b18a82 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c | |||
| @@ -394,6 +394,8 @@ static void stop_self(void *v) | |||
| 394 | load_cr3(swapper_pg_dir); | 394 | load_cr3(swapper_pg_dir); |
| 395 | /* should set up a minimal gdt */ | 395 | /* should set up a minimal gdt */ |
| 396 | 396 | ||
| 397 | set_cpu_online(cpu, false); | ||
| 398 | |||
| 397 | HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL); | 399 | HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL); |
| 398 | BUG(); | 400 | BUG(); |
| 399 | } | 401 | } |
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index a9c661108034..1d789d56877c 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c | |||
| @@ -26,6 +26,18 @@ void xen_pre_suspend(void) | |||
| 26 | BUG(); | 26 | BUG(); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | void xen_hvm_post_suspend(int suspend_cancelled) | ||
| 30 | { | ||
| 31 | int cpu; | ||
| 32 | xen_hvm_init_shared_info(); | ||
| 33 | xen_callback_vector(); | ||
| 34 | if (xen_feature(XENFEAT_hvm_safe_pvclock)) { | ||
| 35 | for_each_online_cpu(cpu) { | ||
| 36 | xen_setup_runstate_info(cpu); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 29 | void xen_post_suspend(int suspend_cancelled) | 41 | void xen_post_suspend(int suspend_cancelled) |
| 30 | { | 42 | { |
| 31 | xen_build_mfn_list_list(); | 43 | xen_build_mfn_list_list(); |
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index b3c6c59ed302..1a5353a753fc 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <asm/xen/hypercall.h> | 20 | #include <asm/xen/hypercall.h> |
| 21 | 21 | ||
| 22 | #include <xen/events.h> | 22 | #include <xen/events.h> |
| 23 | #include <xen/features.h> | ||
| 23 | #include <xen/interface/xen.h> | 24 | #include <xen/interface/xen.h> |
| 24 | #include <xen/interface/vcpu.h> | 25 | #include <xen/interface/vcpu.h> |
| 25 | 26 | ||
| @@ -155,47 +156,8 @@ static void do_stolen_accounting(void) | |||
| 155 | account_idle_ticks(ticks); | 156 | account_idle_ticks(ticks); |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 158 | /* | ||
| 159 | * Xen sched_clock implementation. Returns the number of unstolen | ||
| 160 | * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED | ||
| 161 | * states. | ||
| 162 | */ | ||
| 163 | unsigned long long xen_sched_clock(void) | ||
| 164 | { | ||
| 165 | struct vcpu_runstate_info state; | ||
| 166 | cycle_t now; | ||
| 167 | u64 ret; | ||
| 168 | s64 offset; | ||
| 169 | |||
| 170 | /* | ||
| 171 | * Ideally sched_clock should be called on a per-cpu basis | ||
| 172 | * anyway, so preempt should already be disabled, but that's | ||
| 173 | * not current practice at the moment. | ||
| 174 | */ | ||
| 175 | preempt_disable(); | ||
| 176 | |||
| 177 | now = xen_clocksource_read(); | ||
| 178 | |||
| 179 | get_runstate_snapshot(&state); | ||
| 180 | |||
| 181 | WARN_ON(state.state != RUNSTATE_running); | ||
| 182 | |||
| 183 | offset = now - state.state_entry_time; | ||
| 184 | if (offset < 0) | ||
| 185 | offset = 0; | ||
| 186 | |||
| 187 | ret = state.time[RUNSTATE_blocked] + | ||
| 188 | state.time[RUNSTATE_running] + | ||
| 189 | offset; | ||
| 190 | |||
| 191 | preempt_enable(); | ||
| 192 | |||
| 193 | return ret; | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | /* Get the TSC speed from Xen */ | 159 | /* Get the TSC speed from Xen */ |
| 198 | unsigned long xen_tsc_khz(void) | 160 | static unsigned long xen_tsc_khz(void) |
| 199 | { | 161 | { |
| 200 | struct pvclock_vcpu_time_info *info = | 162 | struct pvclock_vcpu_time_info *info = |
| 201 | &HYPERVISOR_shared_info->vcpu_info[0].time; | 163 | &HYPERVISOR_shared_info->vcpu_info[0].time; |
| @@ -230,7 +192,7 @@ static void xen_read_wallclock(struct timespec *ts) | |||
| 230 | put_cpu_var(xen_vcpu); | 192 | put_cpu_var(xen_vcpu); |
| 231 | } | 193 | } |
| 232 | 194 | ||
| 233 | unsigned long xen_get_wallclock(void) | 195 | static unsigned long xen_get_wallclock(void) |
| 234 | { | 196 | { |
| 235 | struct timespec ts; | 197 | struct timespec ts; |
| 236 | 198 | ||
| @@ -238,7 +200,7 @@ unsigned long xen_get_wallclock(void) | |||
| 238 | return ts.tv_sec; | 200 | return ts.tv_sec; |
| 239 | } | 201 | } |
| 240 | 202 | ||
| 241 | int xen_set_wallclock(unsigned long now) | 203 | static int xen_set_wallclock(unsigned long now) |
| 242 | { | 204 | { |
| 243 | /* do nothing for domU */ | 205 | /* do nothing for domU */ |
| 244 | return -1; | 206 | return -1; |
| @@ -473,7 +435,11 @@ void xen_timer_resume(void) | |||
| 473 | } | 435 | } |
| 474 | } | 436 | } |
| 475 | 437 | ||
| 476 | __init void xen_time_init(void) | 438 | static const struct pv_time_ops xen_time_ops __initdata = { |
| 439 | .sched_clock = xen_clocksource_read, | ||
| 440 | }; | ||
| 441 | |||
| 442 | static __init void xen_time_init(void) | ||
| 477 | { | 443 | { |
| 478 | int cpu = smp_processor_id(); | 444 | int cpu = smp_processor_id(); |
| 479 | struct timespec tp; | 445 | struct timespec tp; |
| @@ -497,3 +463,47 @@ __init void xen_time_init(void) | |||
| 497 | xen_setup_timer(cpu); | 463 | xen_setup_timer(cpu); |
| 498 | xen_setup_cpu_clockevents(); | 464 | xen_setup_cpu_clockevents(); |
| 499 | } | 465 | } |
| 466 | |||
| 467 | __init void xen_init_time_ops(void) | ||
| 468 | { | ||
| 469 | pv_time_ops = xen_time_ops; | ||
| 470 | |||
| 471 | x86_init.timers.timer_init = xen_time_init; | ||
| 472 | x86_init.timers.setup_percpu_clockev = x86_init_noop; | ||
| 473 | x86_cpuinit.setup_percpu_clockev = x86_init_noop; | ||
| 474 | |||
| 475 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
| 476 | x86_platform.get_wallclock = xen_get_wallclock; | ||
| 477 | x86_platform.set_wallclock = xen_set_wallclock; | ||
| 478 | } | ||
| 479 | |||
| 480 | #ifdef CONFIG_XEN_PVHVM | ||
| 481 | static void xen_hvm_setup_cpu_clockevents(void) | ||
| 482 | { | ||
| 483 | int cpu = smp_processor_id(); | ||
| 484 | xen_setup_runstate_info(cpu); | ||
| 485 | xen_setup_timer(cpu); | ||
| 486 | xen_setup_cpu_clockevents(); | ||
| 487 | } | ||
| 488 | |||
| 489 | __init void xen_hvm_init_time_ops(void) | ||
| 490 | { | ||
| 491 | /* vector callback is needed otherwise we cannot receive interrupts | ||
| 492 | * on cpu > 0 */ | ||
| 493 | if (!xen_have_vector_callback && num_present_cpus() > 1) | ||
| 494 | return; | ||
| 495 | if (!xen_feature(XENFEAT_hvm_safe_pvclock)) { | ||
| 496 | printk(KERN_INFO "Xen doesn't support pvclock on HVM," | ||
| 497 | "disable pv timer\n"); | ||
| 498 | return; | ||
| 499 | } | ||
| 500 | |||
| 501 | pv_time_ops = xen_time_ops; | ||
| 502 | x86_init.timers.setup_percpu_clockev = xen_time_init; | ||
| 503 | x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents; | ||
| 504 | |||
| 505 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
| 506 | x86_platform.get_wallclock = xen_get_wallclock; | ||
| 507 | x86_platform.set_wallclock = xen_set_wallclock; | ||
| 508 | } | ||
| 509 | #endif | ||
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index f9153a300bce..7c8ab86163e9 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
| @@ -38,6 +38,10 @@ void xen_enable_sysenter(void); | |||
| 38 | void xen_enable_syscall(void); | 38 | void xen_enable_syscall(void); |
| 39 | void xen_vcpu_restore(void); | 39 | void xen_vcpu_restore(void); |
| 40 | 40 | ||
| 41 | void xen_callback_vector(void); | ||
| 42 | void xen_hvm_init_shared_info(void); | ||
| 43 | void __init xen_unplug_emulated_devices(void); | ||
| 44 | |||
| 41 | void __init xen_build_dynamic_phys_to_machine(void); | 45 | void __init xen_build_dynamic_phys_to_machine(void); |
| 42 | 46 | ||
| 43 | void xen_init_irq_ops(void); | 47 | void xen_init_irq_ops(void); |
| @@ -46,11 +50,8 @@ void xen_setup_runstate_info(int cpu); | |||
| 46 | void xen_teardown_timer(int cpu); | 50 | void xen_teardown_timer(int cpu); |
| 47 | cycle_t xen_clocksource_read(void); | 51 | cycle_t xen_clocksource_read(void); |
| 48 | void xen_setup_cpu_clockevents(void); | 52 | void xen_setup_cpu_clockevents(void); |
| 49 | unsigned long xen_tsc_khz(void); | 53 | void __init xen_init_time_ops(void); |
| 50 | void __init xen_time_init(void); | 54 | void __init xen_hvm_init_time_ops(void); |
| 51 | unsigned long xen_get_wallclock(void); | ||
| 52 | int xen_set_wallclock(unsigned long time); | ||
| 53 | unsigned long long xen_sched_clock(void); | ||
| 54 | 55 | ||
| 55 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id); | 56 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id); |
| 56 | 57 | ||
| @@ -101,4 +102,6 @@ void xen_sysret32(void); | |||
| 101 | void xen_sysret64(void); | 102 | void xen_sysret64(void); |
| 102 | void xen_adjust_exception_frame(void); | 103 | void xen_adjust_exception_frame(void); |
| 103 | 104 | ||
| 105 | extern int xen_panic_handler_init(void); | ||
| 106 | |||
| 104 | #endif /* XEN_OPS_H */ | 107 | #endif /* XEN_OPS_H */ |
