diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2010-04-14 09:51:09 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:17:46 -0400 |
commit | e269fb2189fb86d79d64c0ca74c6c1a549ad4aa3 (patch) | |
tree | 627c658efaec155d1f295d1fc7b8abded9d4f861 /arch/x86/kvm/emulate.c | |
parent | 0760d44868f351ba30fc9a08cf1830e46aa72466 (diff) |
KVM: x86: Push potential exception error code on task switches
When a fault triggers a task switch, the error code, if existent, has to
be pushed on the new task's stack. Implement the missing bits.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index aace5659bbe0..585d0ef4a5f6 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -2344,8 +2344,9 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, | |||
2344 | } | 2344 | } |
2345 | 2345 | ||
2346 | static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | 2346 | static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, |
2347 | struct x86_emulate_ops *ops, | 2347 | struct x86_emulate_ops *ops, |
2348 | u16 tss_selector, int reason) | 2348 | u16 tss_selector, int reason, |
2349 | bool has_error_code, u32 error_code) | ||
2349 | { | 2350 | { |
2350 | struct desc_struct curr_tss_desc, next_tss_desc; | 2351 | struct desc_struct curr_tss_desc, next_tss_desc; |
2351 | int ret; | 2352 | int ret; |
@@ -2418,12 +2419,22 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2418 | ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu); | 2419 | ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu); |
2419 | ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu); | 2420 | ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu); |
2420 | 2421 | ||
2422 | if (has_error_code) { | ||
2423 | struct decode_cache *c = &ctxt->decode; | ||
2424 | |||
2425 | c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; | ||
2426 | c->lock_prefix = 0; | ||
2427 | c->src.val = (unsigned long) error_code; | ||
2428 | emulate_push(ctxt); | ||
2429 | } | ||
2430 | |||
2421 | return ret; | 2431 | return ret; |
2422 | } | 2432 | } |
2423 | 2433 | ||
2424 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | 2434 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, |
2425 | struct x86_emulate_ops *ops, | 2435 | struct x86_emulate_ops *ops, |
2426 | u16 tss_selector, int reason) | 2436 | u16 tss_selector, int reason, |
2437 | bool has_error_code, u32 error_code) | ||
2427 | { | 2438 | { |
2428 | struct decode_cache *c = &ctxt->decode; | 2439 | struct decode_cache *c = &ctxt->decode; |
2429 | int rc; | 2440 | int rc; |
@@ -2431,12 +2442,15 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2431 | memset(c, 0, sizeof(struct decode_cache)); | 2442 | memset(c, 0, sizeof(struct decode_cache)); |
2432 | c->eip = ctxt->eip; | 2443 | c->eip = ctxt->eip; |
2433 | memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); | 2444 | memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); |
2445 | c->dst.type = OP_NONE; | ||
2434 | 2446 | ||
2435 | rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason); | 2447 | rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason, |
2448 | has_error_code, error_code); | ||
2436 | 2449 | ||
2437 | if (rc == X86EMUL_CONTINUE) { | 2450 | if (rc == X86EMUL_CONTINUE) { |
2438 | memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); | 2451 | memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); |
2439 | kvm_rip_write(ctxt->vcpu, c->eip); | 2452 | kvm_rip_write(ctxt->vcpu, c->eip); |
2453 | rc = writeback(ctxt, ops); | ||
2440 | } | 2454 | } |
2441 | 2455 | ||
2442 | return rc; | 2456 | return rc; |