diff options
| -rw-r--r-- | arch/x86/include/asm/lguest_hcall.h | 29 | ||||
| -rw-r--r-- | arch/x86/lguest/boot.c | 61 | ||||
| -rw-r--r-- | arch/x86/lguest/i386_head.S | 2 | ||||
| -rw-r--r-- | drivers/lguest/lguest_device.c | 4 | ||||
| -rw-r--r-- | drivers/lguest/x86/core.c | 12 |
5 files changed, 68 insertions, 40 deletions
diff --git a/arch/x86/include/asm/lguest_hcall.h b/arch/x86/include/asm/lguest_hcall.h index ba0eed8aa1a6..b60f2924c413 100644 --- a/arch/x86/include/asm/lguest_hcall.h +++ b/arch/x86/include/asm/lguest_hcall.h | |||
| @@ -28,22 +28,39 @@ | |||
| 28 | 28 | ||
| 29 | #ifndef __ASSEMBLY__ | 29 | #ifndef __ASSEMBLY__ |
| 30 | #include <asm/hw_irq.h> | 30 | #include <asm/hw_irq.h> |
| 31 | #include <asm/kvm_para.h> | ||
| 32 | 31 | ||
| 33 | /*G:030 | 32 | /*G:030 |
| 34 | * But first, how does our Guest contact the Host to ask for privileged | 33 | * But first, how does our Guest contact the Host to ask for privileged |
| 35 | * operations? There are two ways: the direct way is to make a "hypercall", | 34 | * operations? There are two ways: the direct way is to make a "hypercall", |
| 36 | * to make requests of the Host Itself. | 35 | * to make requests of the Host Itself. |
| 37 | * | 36 | * |
| 38 | * We use the KVM hypercall mechanism, though completely different hypercall | 37 | * Our hypercall mechanism uses the highest unused trap code (traps 32 and |
| 39 | * numbers. Seventeen hypercalls are available: the hypercall number is put in | 38 | * above are used by real hardware interrupts). Seventeen hypercalls are |
| 40 | * the %eax register, and the arguments (when required) are placed in %ebx, | 39 | * available: the hypercall number is put in the %eax register, and the |
| 41 | * %ecx, %edx and %esi. If a return value makes sense, it's returned in %eax. | 40 | * arguments (when required) are placed in %ebx, %ecx, %edx and %esi. |
| 41 | * If a return value makes sense, it's returned in %eax. | ||
| 42 | * | 42 | * |
| 43 | * Grossly invalid calls result in Sudden Death at the hands of the vengeful | 43 | * Grossly invalid calls result in Sudden Death at the hands of the vengeful |
| 44 | * Host, rather than returning failure. This reflects Winston Churchill's | 44 | * Host, rather than returning failure. This reflects Winston Churchill's |
| 45 | * definition of a gentleman: "someone who is only rude intentionally". | 45 | * definition of a gentleman: "someone who is only rude intentionally". |
| 46 | :*/ | 46 | */ |
| 47 | static inline unsigned long | ||
| 48 | hcall(unsigned long call, | ||
| 49 | unsigned long arg1, unsigned long arg2, unsigned long arg3, | ||
| 50 | unsigned long arg4) | ||
| 51 | { | ||
| 52 | /* "int" is the Intel instruction to trigger a trap. */ | ||
| 53 | asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY) | ||
| 54 | /* The call in %eax (aka "a") might be overwritten */ | ||
| 55 | : "=a"(call) | ||
| 56 | /* The arguments are in %eax, %ebx, %ecx, %edx & %esi */ | ||
| 57 | : "a"(call), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4) | ||
| 58 | /* "memory" means this might write somewhere in memory. | ||
| 59 | * This isn't true for all calls, but it's safe to tell | ||
| 60 | * gcc that it might happen so it doesn't get clever. */ | ||
| 61 | : "memory"); | ||
| 62 | return call; | ||
| 63 | } | ||
| 47 | 64 | ||
| 48 | /* Can't use our min() macro here: needs to be a constant */ | 65 | /* Can't use our min() macro here: needs to be a constant */ |
| 49 | #define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32) | 66 | #define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32) |
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 7e59dc1d3fc2..2bdf628066bd 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c | |||
| @@ -115,7 +115,7 @@ static void async_hcall(unsigned long call, unsigned long arg1, | |||
| 115 | local_irq_save(flags); | 115 | local_irq_save(flags); |
| 116 | if (lguest_data.hcall_status[next_call] != 0xFF) { | 116 | if (lguest_data.hcall_status[next_call] != 0xFF) { |
| 117 | /* Table full, so do normal hcall which will flush table. */ | 117 | /* Table full, so do normal hcall which will flush table. */ |
| 118 | kvm_hypercall4(call, arg1, arg2, arg3, arg4); | 118 | hcall(call, arg1, arg2, arg3, arg4); |
| 119 | } else { | 119 | } else { |
| 120 | lguest_data.hcalls[next_call].arg0 = call; | 120 | lguest_data.hcalls[next_call].arg0 = call; |
| 121 | lguest_data.hcalls[next_call].arg1 = arg1; | 121 | lguest_data.hcalls[next_call].arg1 = arg1; |
| @@ -145,46 +145,45 @@ static void async_hcall(unsigned long call, unsigned long arg1, | |||
| 145 | * So, when we're in lazy mode, we call async_hcall() to store the call for | 145 | * So, when we're in lazy mode, we call async_hcall() to store the call for |
| 146 | * future processing: | 146 | * future processing: |
| 147 | */ | 147 | */ |
| 148 | static void lazy_hcall1(unsigned long call, | 148 | static void lazy_hcall1(unsigned long call, unsigned long arg1) |
| 149 | unsigned long arg1) | ||
| 150 | { | 149 | { |
| 151 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) | 150 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) |
| 152 | kvm_hypercall1(call, arg1); | 151 | hcall(call, arg1, 0, 0, 0); |
| 153 | else | 152 | else |
| 154 | async_hcall(call, arg1, 0, 0, 0); | 153 | async_hcall(call, arg1, 0, 0, 0); |
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | /* You can imagine what lazy_hcall2, 3 and 4 look like. :*/ | 156 | /* You can imagine what lazy_hcall2, 3 and 4 look like. :*/ |
| 158 | static void lazy_hcall2(unsigned long call, | 157 | static void lazy_hcall2(unsigned long call, |
| 159 | unsigned long arg1, | 158 | unsigned long arg1, |
| 160 | unsigned long arg2) | 159 | unsigned long arg2) |
| 161 | { | 160 | { |
| 162 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) | 161 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) |
| 163 | kvm_hypercall2(call, arg1, arg2); | 162 | hcall(call, arg1, arg2, 0, 0); |
| 164 | else | 163 | else |
| 165 | async_hcall(call, arg1, arg2, 0, 0); | 164 | async_hcall(call, arg1, arg2, 0, 0); |
| 166 | } | 165 | } |
| 167 | 166 | ||
| 168 | static void lazy_hcall3(unsigned long call, | 167 | static void lazy_hcall3(unsigned long call, |
| 169 | unsigned long arg1, | 168 | unsigned long arg1, |
| 170 | unsigned long arg2, | 169 | unsigned long arg2, |
| 171 | unsigned long arg3) | 170 | unsigned long arg3) |
| 172 | { | 171 | { |
| 173 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) | 172 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) |
| 174 | kvm_hypercall3(call, arg1, arg2, arg3); | 173 | hcall(call, arg1, arg2, arg3, 0); |
| 175 | else | 174 | else |
| 176 | async_hcall(call, arg1, arg2, arg3, 0); | 175 | async_hcall(call, arg1, arg2, arg3, 0); |
| 177 | } | 176 | } |
| 178 | 177 | ||
| 179 | #ifdef CONFIG_X86_PAE | 178 | #ifdef CONFIG_X86_PAE |
| 180 | static void lazy_hcall4(unsigned long call, | 179 | static void lazy_hcall4(unsigned long call, |
| 181 | unsigned long arg1, | 180 | unsigned long arg1, |
| 182 | unsigned long arg2, | 181 | unsigned long arg2, |
| 183 | unsigned long arg3, | 182 | unsigned long arg3, |
| 184 | unsigned long arg4) | 183 | unsigned long arg4) |
| 185 | { | 184 | { |
| 186 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) | 185 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) |
| 187 | kvm_hypercall4(call, arg1, arg2, arg3, arg4); | 186 | hcall(call, arg1, arg2, arg3, arg4); |
| 188 | else | 187 | else |
| 189 | async_hcall(call, arg1, arg2, arg3, arg4); | 188 | async_hcall(call, arg1, arg2, arg3, arg4); |
| 190 | } | 189 | } |
| @@ -196,13 +195,13 @@ static void lazy_hcall4(unsigned long call, | |||
| 196 | :*/ | 195 | :*/ |
| 197 | static void lguest_leave_lazy_mmu_mode(void) | 196 | static void lguest_leave_lazy_mmu_mode(void) |
| 198 | { | 197 | { |
| 199 | kvm_hypercall0(LHCALL_FLUSH_ASYNC); | 198 | hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0, 0); |
| 200 | paravirt_leave_lazy_mmu(); | 199 | paravirt_leave_lazy_mmu(); |
| 201 | } | 200 | } |
| 202 | 201 | ||
| 203 | static void lguest_end_context_switch(struct task_struct *next) | 202 | static void lguest_end_context_switch(struct task_struct *next) |
| 204 | { | 203 | { |
| 205 | kvm_hypercall0(LHCALL_FLUSH_ASYNC); | 204 | hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0, 0); |
| 206 | paravirt_end_context_switch(next); | 205 | paravirt_end_context_switch(next); |
| 207 | } | 206 | } |
| 208 | 207 | ||
| @@ -286,7 +285,7 @@ static void lguest_write_idt_entry(gate_desc *dt, | |||
| 286 | /* Keep the local copy up to date. */ | 285 | /* Keep the local copy up to date. */ |
| 287 | native_write_idt_entry(dt, entrynum, g); | 286 | native_write_idt_entry(dt, entrynum, g); |
| 288 | /* Tell Host about this new entry. */ | 287 | /* Tell Host about this new entry. */ |
| 289 | kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); | 288 | hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1], 0); |
| 290 | } | 289 | } |
| 291 | 290 | ||
| 292 | /* | 291 | /* |
| @@ -300,7 +299,7 @@ static void lguest_load_idt(const struct desc_ptr *desc) | |||
| 300 | struct desc_struct *idt = (void *)desc->address; | 299 | struct desc_struct *idt = (void *)desc->address; |
| 301 | 300 | ||
| 302 | for (i = 0; i < (desc->size+1)/8; i++) | 301 | for (i = 0; i < (desc->size+1)/8; i++) |
| 303 | kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b); | 302 | hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b, 0); |
| 304 | } | 303 | } |
| 305 | 304 | ||
| 306 | /* | 305 | /* |
| @@ -321,7 +320,7 @@ static void lguest_load_gdt(const struct desc_ptr *desc) | |||
| 321 | struct desc_struct *gdt = (void *)desc->address; | 320 | struct desc_struct *gdt = (void *)desc->address; |
| 322 | 321 | ||
| 323 | for (i = 0; i < (desc->size+1)/8; i++) | 322 | for (i = 0; i < (desc->size+1)/8; i++) |
| 324 | kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, i, gdt[i].a, gdt[i].b); | 323 | hcall(LHCALL_LOAD_GDT_ENTRY, i, gdt[i].a, gdt[i].b, 0); |
| 325 | } | 324 | } |
| 326 | 325 | ||
| 327 | /* | 326 | /* |
| @@ -334,8 +333,8 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum, | |||
| 334 | { | 333 | { |
| 335 | native_write_gdt_entry(dt, entrynum, desc, type); | 334 | native_write_gdt_entry(dt, entrynum, desc, type); |
| 336 | /* Tell Host about this new entry. */ | 335 | /* Tell Host about this new entry. */ |
| 337 | kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, entrynum, | 336 | hcall(LHCALL_LOAD_GDT_ENTRY, entrynum, |
| 338 | dt[entrynum].a, dt[entrynum].b); | 337 | dt[entrynum].a, dt[entrynum].b, 0); |
| 339 | } | 338 | } |
| 340 | 339 | ||
| 341 | /* | 340 | /* |
| @@ -931,7 +930,7 @@ static int lguest_clockevent_set_next_event(unsigned long delta, | |||
| 931 | } | 930 | } |
| 932 | 931 | ||
| 933 | /* Please wake us this far in the future. */ | 932 | /* Please wake us this far in the future. */ |
| 934 | kvm_hypercall1(LHCALL_SET_CLOCKEVENT, delta); | 933 | hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0, 0); |
| 935 | return 0; | 934 | return 0; |
| 936 | } | 935 | } |
| 937 | 936 | ||
| @@ -942,7 +941,7 @@ static void lguest_clockevent_set_mode(enum clock_event_mode mode, | |||
| 942 | case CLOCK_EVT_MODE_UNUSED: | 941 | case CLOCK_EVT_MODE_UNUSED: |
| 943 | case CLOCK_EVT_MODE_SHUTDOWN: | 942 | case CLOCK_EVT_MODE_SHUTDOWN: |
| 944 | /* A 0 argument shuts the clock down. */ | 943 | /* A 0 argument shuts the clock down. */ |
| 945 | kvm_hypercall0(LHCALL_SET_CLOCKEVENT); | 944 | hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0, 0); |
| 946 | break; | 945 | break; |
| 947 | case CLOCK_EVT_MODE_ONESHOT: | 946 | case CLOCK_EVT_MODE_ONESHOT: |
| 948 | /* This is what we expect. */ | 947 | /* This is what we expect. */ |
| @@ -1100,7 +1099,7 @@ static void set_lguest_basic_apic_ops(void) | |||
| 1100 | /* STOP! Until an interrupt comes in. */ | 1099 | /* STOP! Until an interrupt comes in. */ |
| 1101 | static void lguest_safe_halt(void) | 1100 | static void lguest_safe_halt(void) |
| 1102 | { | 1101 | { |
| 1103 | kvm_hypercall0(LHCALL_HALT); | 1102 | hcall(LHCALL_HALT, 0, 0, 0, 0); |
| 1104 | } | 1103 | } |
| 1105 | 1104 | ||
| 1106 | /* | 1105 | /* |
| @@ -1112,8 +1111,8 @@ static void lguest_safe_halt(void) | |||
| 1112 | */ | 1111 | */ |
| 1113 | static void lguest_power_off(void) | 1112 | static void lguest_power_off(void) |
| 1114 | { | 1113 | { |
| 1115 | kvm_hypercall2(LHCALL_SHUTDOWN, __pa("Power down"), | 1114 | hcall(LHCALL_SHUTDOWN, __pa("Power down"), |
| 1116 | LGUEST_SHUTDOWN_POWEROFF); | 1115 | LGUEST_SHUTDOWN_POWEROFF, 0, 0); |
| 1117 | } | 1116 | } |
| 1118 | 1117 | ||
| 1119 | /* | 1118 | /* |
| @@ -1123,7 +1122,7 @@ static void lguest_power_off(void) | |||
| 1123 | */ | 1122 | */ |
| 1124 | static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) | 1123 | static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) |
| 1125 | { | 1124 | { |
| 1126 | kvm_hypercall2(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF); | 1125 | hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0, 0); |
| 1127 | /* The hcall won't return, but to keep gcc happy, we're "done". */ | 1126 | /* The hcall won't return, but to keep gcc happy, we're "done". */ |
| 1128 | return NOTIFY_DONE; | 1127 | return NOTIFY_DONE; |
| 1129 | } | 1128 | } |
| @@ -1162,7 +1161,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) | |||
| 1162 | len = sizeof(scratch) - 1; | 1161 | len = sizeof(scratch) - 1; |
| 1163 | scratch[len] = '\0'; | 1162 | scratch[len] = '\0'; |
| 1164 | memcpy(scratch, buf, len); | 1163 | memcpy(scratch, buf, len); |
| 1165 | kvm_hypercall1(LHCALL_NOTIFY, __pa(scratch)); | 1164 | hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0, 0); |
| 1166 | 1165 | ||
| 1167 | /* This routine returns the number of bytes actually written. */ | 1166 | /* This routine returns the number of bytes actually written. */ |
| 1168 | return len; | 1167 | return len; |
| @@ -1174,7 +1173,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) | |||
| 1174 | */ | 1173 | */ |
| 1175 | static void lguest_restart(char *reason) | 1174 | static void lguest_restart(char *reason) |
| 1176 | { | 1175 | { |
| 1177 | kvm_hypercall2(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART); | 1176 | hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0, 0); |
| 1178 | } | 1177 | } |
| 1179 | 1178 | ||
| 1180 | /*G:050 | 1179 | /*G:050 |
diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/i386_head.S index 27eac0faee48..4f420c2f2d55 100644 --- a/arch/x86/lguest/i386_head.S +++ b/arch/x86/lguest/i386_head.S | |||
| @@ -32,7 +32,7 @@ ENTRY(lguest_entry) | |||
| 32 | */ | 32 | */ |
| 33 | movl $LHCALL_LGUEST_INIT, %eax | 33 | movl $LHCALL_LGUEST_INIT, %eax |
| 34 | movl $lguest_data - __PAGE_OFFSET, %ebx | 34 | movl $lguest_data - __PAGE_OFFSET, %ebx |
| 35 | .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */ | 35 | int $LGUEST_TRAP_ENTRY |
| 36 | 36 | ||
| 37 | /* Set up the initial stack so we can run C code. */ | 37 | /* Set up the initial stack so we can run C code. */ |
| 38 | movl $(init_thread_union+THREAD_SIZE),%esp | 38 | movl $(init_thread_union+THREAD_SIZE),%esp |
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 07090f379c63..69c84a1d88ea 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
| @@ -178,7 +178,7 @@ static void set_status(struct virtio_device *vdev, u8 status) | |||
| 178 | 178 | ||
| 179 | /* We set the status. */ | 179 | /* We set the status. */ |
| 180 | to_lgdev(vdev)->desc->status = status; | 180 | to_lgdev(vdev)->desc->status = status; |
| 181 | kvm_hypercall1(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset); | 181 | hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0); |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | static void lg_set_status(struct virtio_device *vdev, u8 status) | 184 | static void lg_set_status(struct virtio_device *vdev, u8 status) |
| @@ -229,7 +229,7 @@ static void lg_notify(struct virtqueue *vq) | |||
| 229 | */ | 229 | */ |
| 230 | struct lguest_vq_info *lvq = vq->priv; | 230 | struct lguest_vq_info *lvq = vq->priv; |
| 231 | 231 | ||
| 232 | kvm_hypercall1(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT); | 232 | hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | /* An extern declaration inside a C file is bad form. Don't do it. */ | 235 | /* An extern declaration inside a C file is bad form. Don't do it. */ |
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index fb2b7ef7868e..b4eb675a807e 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c | |||
| @@ -288,6 +288,18 @@ static int emulate_insn(struct lg_cpu *cpu) | |||
| 288 | insn = lgread(cpu, physaddr, u8); | 288 | insn = lgread(cpu, physaddr, u8); |
| 289 | 289 | ||
| 290 | /* | 290 | /* |
| 291 | * Around 2.6.33, the kernel started using an emulation for the | ||
| 292 | * cmpxchg8b instruction in early boot on many configurations. This | ||
| 293 | * code isn't paravirtualized, and it tries to disable interrupts. | ||
| 294 | * Ignore it, which will Mostly Work. | ||
| 295 | */ | ||
| 296 | if (insn == 0xfa) { | ||
| 297 | /* "cli", or Clear Interrupt Enable instruction. Skip it. */ | ||
| 298 | cpu->regs->eip++; | ||
| 299 | return 1; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* | ||
| 291 | * 0x66 is an "operand prefix". It means it's using the upper 16 bits | 303 | * 0x66 is an "operand prefix". It means it's using the upper 16 bits |
| 292 | * of the eax register. | 304 | * of the eax register. |
| 293 | */ | 305 | */ |
