diff options
author | Avi Kivity <avi@redhat.com> | 2010-11-22 10:53:21 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-01-12 04:29:53 -0500 |
commit | da9cb575b1127f84984b8ad6d973dcc05ac036dd (patch) | |
tree | e0269a888731c630c9b64693b21d24b2821da362 /arch | |
parent | a4ee1ca4a36e7857d90ae8c2b85f1bde9a042c10 (diff) |
KVM: x86 emulator: introduce struct x86_exception to communicate faults
Introduce a structure that can contain an exception to be passed back
to main kvm code.
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/kvm_emulate.h | 11 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 26 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 13 |
3 files changed, 38 insertions, 12 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index b48c133c95ab..b7c11270ae8f 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
@@ -15,6 +15,12 @@ | |||
15 | 15 | ||
16 | struct x86_emulate_ctxt; | 16 | struct x86_emulate_ctxt; |
17 | 17 | ||
18 | struct x86_exception { | ||
19 | u8 vector; | ||
20 | bool error_code_valid; | ||
21 | u16 error_code; | ||
22 | }; | ||
23 | |||
18 | /* | 24 | /* |
19 | * x86_emulate_ops: | 25 | * x86_emulate_ops: |
20 | * | 26 | * |
@@ -229,9 +235,8 @@ struct x86_emulate_ctxt { | |||
229 | 235 | ||
230 | bool perm_ok; /* do not check permissions if true */ | 236 | bool perm_ok; /* do not check permissions if true */ |
231 | 237 | ||
232 | int exception; /* exception that happens during emulation or -1 */ | 238 | bool have_exception; |
233 | u32 error_code; /* error code for exception */ | 239 | struct x86_exception exception; |
234 | bool error_code_valid; | ||
235 | 240 | ||
236 | /* decode cache */ | 241 | /* decode cache */ |
237 | struct decode_cache decode; | 242 | struct decode_cache decode; |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index bdbbb1839e89..18596e6649aa 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -469,9 +469,9 @@ static ulong linear(struct x86_emulate_ctxt *ctxt, | |||
469 | static void emulate_exception(struct x86_emulate_ctxt *ctxt, int vec, | 469 | static void emulate_exception(struct x86_emulate_ctxt *ctxt, int vec, |
470 | u32 error, bool valid) | 470 | u32 error, bool valid) |
471 | { | 471 | { |
472 | ctxt->exception = vec; | 472 | ctxt->exception.vector = vec; |
473 | ctxt->error_code = error; | 473 | ctxt->exception.error_code = error; |
474 | ctxt->error_code_valid = valid; | 474 | ctxt->exception.error_code_valid = valid; |
475 | } | 475 | } |
476 | 476 | ||
477 | static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err) | 477 | static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err) |
@@ -3015,23 +3015,27 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) | |||
3015 | 3015 | ||
3016 | if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) { | 3016 | if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) { |
3017 | emulate_ud(ctxt); | 3017 | emulate_ud(ctxt); |
3018 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3018 | goto done; | 3019 | goto done; |
3019 | } | 3020 | } |
3020 | 3021 | ||
3021 | /* LOCK prefix is allowed only with some instructions */ | 3022 | /* LOCK prefix is allowed only with some instructions */ |
3022 | if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) { | 3023 | if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) { |
3023 | emulate_ud(ctxt); | 3024 | emulate_ud(ctxt); |
3025 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3024 | goto done; | 3026 | goto done; |
3025 | } | 3027 | } |
3026 | 3028 | ||
3027 | if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) { | 3029 | if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) { |
3028 | emulate_ud(ctxt); | 3030 | emulate_ud(ctxt); |
3031 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3029 | goto done; | 3032 | goto done; |
3030 | } | 3033 | } |
3031 | 3034 | ||
3032 | /* Privileged instruction can be executed only in CPL=0 */ | 3035 | /* Privileged instruction can be executed only in CPL=0 */ |
3033 | if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) { | 3036 | if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) { |
3034 | emulate_gp(ctxt, 0); | 3037 | emulate_gp(ctxt, 0); |
3038 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3035 | goto done; | 3039 | goto done; |
3036 | } | 3040 | } |
3037 | 3041 | ||
@@ -3210,6 +3214,7 @@ special_insn: | |||
3210 | case 0x8c: /* mov r/m, sreg */ | 3214 | case 0x8c: /* mov r/m, sreg */ |
3211 | if (c->modrm_reg > VCPU_SREG_GS) { | 3215 | if (c->modrm_reg > VCPU_SREG_GS) { |
3212 | emulate_ud(ctxt); | 3216 | emulate_ud(ctxt); |
3217 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3213 | goto done; | 3218 | goto done; |
3214 | } | 3219 | } |
3215 | c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu); | 3220 | c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu); |
@@ -3225,6 +3230,7 @@ special_insn: | |||
3225 | if (c->modrm_reg == VCPU_SREG_CS || | 3230 | if (c->modrm_reg == VCPU_SREG_CS || |
3226 | c->modrm_reg > VCPU_SREG_GS) { | 3231 | c->modrm_reg > VCPU_SREG_GS) { |
3227 | emulate_ud(ctxt); | 3232 | emulate_ud(ctxt); |
3233 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3228 | goto done; | 3234 | goto done; |
3229 | } | 3235 | } |
3230 | 3236 | ||
@@ -3357,6 +3363,7 @@ special_insn: | |||
3357 | c->dst.bytes = min(c->dst.bytes, 4u); | 3363 | c->dst.bytes = min(c->dst.bytes, 4u); |
3358 | if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) { | 3364 | if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) { |
3359 | emulate_gp(ctxt, 0); | 3365 | emulate_gp(ctxt, 0); |
3366 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3360 | goto done; | 3367 | goto done; |
3361 | } | 3368 | } |
3362 | if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val, | 3369 | if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val, |
@@ -3371,6 +3378,7 @@ special_insn: | |||
3371 | if (!emulator_io_permited(ctxt, ops, c->dst.val, | 3378 | if (!emulator_io_permited(ctxt, ops, c->dst.val, |
3372 | c->src.bytes)) { | 3379 | c->src.bytes)) { |
3373 | emulate_gp(ctxt, 0); | 3380 | emulate_gp(ctxt, 0); |
3381 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3374 | goto done; | 3382 | goto done; |
3375 | } | 3383 | } |
3376 | ops->pio_out_emulated(c->src.bytes, c->dst.val, | 3384 | ops->pio_out_emulated(c->src.bytes, c->dst.val, |
@@ -3396,6 +3404,7 @@ special_insn: | |||
3396 | case 0xfa: /* cli */ | 3404 | case 0xfa: /* cli */ |
3397 | if (emulator_bad_iopl(ctxt, ops)) { | 3405 | if (emulator_bad_iopl(ctxt, ops)) { |
3398 | emulate_gp(ctxt, 0); | 3406 | emulate_gp(ctxt, 0); |
3407 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3399 | goto done; | 3408 | goto done; |
3400 | } else | 3409 | } else |
3401 | ctxt->eflags &= ~X86_EFLAGS_IF; | 3410 | ctxt->eflags &= ~X86_EFLAGS_IF; |
@@ -3403,6 +3412,7 @@ special_insn: | |||
3403 | case 0xfb: /* sti */ | 3412 | case 0xfb: /* sti */ |
3404 | if (emulator_bad_iopl(ctxt, ops)) { | 3413 | if (emulator_bad_iopl(ctxt, ops)) { |
3405 | emulate_gp(ctxt, 0); | 3414 | emulate_gp(ctxt, 0); |
3415 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3406 | goto done; | 3416 | goto done; |
3407 | } else { | 3417 | } else { |
3408 | ctxt->interruptibility = KVM_X86_SHADOW_INT_STI; | 3418 | ctxt->interruptibility = KVM_X86_SHADOW_INT_STI; |
@@ -3475,6 +3485,8 @@ writeback: | |||
3475 | ctxt->eip = c->eip; | 3485 | ctxt->eip = c->eip; |
3476 | 3486 | ||
3477 | done: | 3487 | done: |
3488 | if (rc == X86EMUL_PROPAGATE_FAULT) | ||
3489 | ctxt->have_exception = true; | ||
3478 | return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; | 3490 | return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; |
3479 | 3491 | ||
3480 | twobyte_insn: | 3492 | twobyte_insn: |
@@ -3537,6 +3549,7 @@ twobyte_insn: | |||
3537 | break; | 3549 | break; |
3538 | case 5: /* not defined */ | 3550 | case 5: /* not defined */ |
3539 | emulate_ud(ctxt); | 3551 | emulate_ud(ctxt); |
3552 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3540 | goto done; | 3553 | goto done; |
3541 | case 7: /* invlpg*/ | 3554 | case 7: /* invlpg*/ |
3542 | emulate_invlpg(ctxt->vcpu, | 3555 | emulate_invlpg(ctxt->vcpu, |
@@ -3567,6 +3580,7 @@ twobyte_insn: | |||
3567 | case 5 ... 7: | 3580 | case 5 ... 7: |
3568 | case 9 ... 15: | 3581 | case 9 ... 15: |
3569 | emulate_ud(ctxt); | 3582 | emulate_ud(ctxt); |
3583 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3570 | goto done; | 3584 | goto done; |
3571 | } | 3585 | } |
3572 | c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu); | 3586 | c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu); |
@@ -3575,6 +3589,7 @@ twobyte_insn: | |||
3575 | if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) && | 3589 | if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) && |
3576 | (c->modrm_reg == 4 || c->modrm_reg == 5)) { | 3590 | (c->modrm_reg == 4 || c->modrm_reg == 5)) { |
3577 | emulate_ud(ctxt); | 3591 | emulate_ud(ctxt); |
3592 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3578 | goto done; | 3593 | goto done; |
3579 | } | 3594 | } |
3580 | ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu); | 3595 | ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu); |
@@ -3582,6 +3597,7 @@ twobyte_insn: | |||
3582 | case 0x22: /* mov reg, cr */ | 3597 | case 0x22: /* mov reg, cr */ |
3583 | if (ops->set_cr(c->modrm_reg, c->src.val, ctxt->vcpu)) { | 3598 | if (ops->set_cr(c->modrm_reg, c->src.val, ctxt->vcpu)) { |
3584 | emulate_gp(ctxt, 0); | 3599 | emulate_gp(ctxt, 0); |
3600 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3585 | goto done; | 3601 | goto done; |
3586 | } | 3602 | } |
3587 | c->dst.type = OP_NONE; | 3603 | c->dst.type = OP_NONE; |
@@ -3590,6 +3606,7 @@ twobyte_insn: | |||
3590 | if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) && | 3606 | if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) && |
3591 | (c->modrm_reg == 4 || c->modrm_reg == 5)) { | 3607 | (c->modrm_reg == 4 || c->modrm_reg == 5)) { |
3592 | emulate_ud(ctxt); | 3608 | emulate_ud(ctxt); |
3609 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3593 | goto done; | 3610 | goto done; |
3594 | } | 3611 | } |
3595 | 3612 | ||
@@ -3598,6 +3615,7 @@ twobyte_insn: | |||
3598 | ~0ULL : ~0U), ctxt->vcpu) < 0) { | 3615 | ~0ULL : ~0U), ctxt->vcpu) < 0) { |
3599 | /* #UD condition is already handled by the code above */ | 3616 | /* #UD condition is already handled by the code above */ |
3600 | emulate_gp(ctxt, 0); | 3617 | emulate_gp(ctxt, 0); |
3618 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3601 | goto done; | 3619 | goto done; |
3602 | } | 3620 | } |
3603 | 3621 | ||
@@ -3609,6 +3627,7 @@ twobyte_insn: | |||
3609 | | ((u64)c->regs[VCPU_REGS_RDX] << 32); | 3627 | | ((u64)c->regs[VCPU_REGS_RDX] << 32); |
3610 | if (ops->set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) { | 3628 | if (ops->set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) { |
3611 | emulate_gp(ctxt, 0); | 3629 | emulate_gp(ctxt, 0); |
3630 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3612 | goto done; | 3631 | goto done; |
3613 | } | 3632 | } |
3614 | rc = X86EMUL_CONTINUE; | 3633 | rc = X86EMUL_CONTINUE; |
@@ -3617,6 +3636,7 @@ twobyte_insn: | |||
3617 | /* rdmsr */ | 3636 | /* rdmsr */ |
3618 | if (ops->get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) { | 3637 | if (ops->get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) { |
3619 | emulate_gp(ctxt, 0); | 3638 | emulate_gp(ctxt, 0); |
3639 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3620 | goto done; | 3640 | goto done; |
3621 | } else { | 3641 | } else { |
3622 | c->regs[VCPU_REGS_RAX] = (u32)msr_data; | 3642 | c->regs[VCPU_REGS_RAX] = (u32)msr_data; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 651cf9004fbe..0c908321e900 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4254,12 +4254,13 @@ static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) | |||
4254 | static void inject_emulated_exception(struct kvm_vcpu *vcpu) | 4254 | static void inject_emulated_exception(struct kvm_vcpu *vcpu) |
4255 | { | 4255 | { |
4256 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; | 4256 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; |
4257 | if (ctxt->exception == PF_VECTOR) | 4257 | if (ctxt->exception.vector == PF_VECTOR) |
4258 | kvm_propagate_fault(vcpu); | 4258 | kvm_propagate_fault(vcpu); |
4259 | else if (ctxt->error_code_valid) | 4259 | else if (ctxt->exception.error_code_valid) |
4260 | kvm_queue_exception_e(vcpu, ctxt->exception, ctxt->error_code); | 4260 | kvm_queue_exception_e(vcpu, ctxt->exception.vector, |
4261 | ctxt->exception.error_code); | ||
4261 | else | 4262 | else |
4262 | kvm_queue_exception(vcpu, ctxt->exception); | 4263 | kvm_queue_exception(vcpu, ctxt->exception.vector); |
4263 | } | 4264 | } |
4264 | 4265 | ||
4265 | static void init_emulate_ctxt(struct kvm_vcpu *vcpu) | 4266 | static void init_emulate_ctxt(struct kvm_vcpu *vcpu) |
@@ -4371,7 +4372,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | |||
4371 | if (!(emulation_type & EMULTYPE_NO_DECODE)) { | 4372 | if (!(emulation_type & EMULTYPE_NO_DECODE)) { |
4372 | init_emulate_ctxt(vcpu); | 4373 | init_emulate_ctxt(vcpu); |
4373 | vcpu->arch.emulate_ctxt.interruptibility = 0; | 4374 | vcpu->arch.emulate_ctxt.interruptibility = 0; |
4374 | vcpu->arch.emulate_ctxt.exception = -1; | 4375 | vcpu->arch.emulate_ctxt.have_exception = false; |
4375 | vcpu->arch.emulate_ctxt.perm_ok = false; | 4376 | vcpu->arch.emulate_ctxt.perm_ok = false; |
4376 | 4377 | ||
4377 | r = x86_decode_insn(&vcpu->arch.emulate_ctxt); | 4378 | r = x86_decode_insn(&vcpu->arch.emulate_ctxt); |
@@ -4437,7 +4438,7 @@ restart: | |||
4437 | } | 4438 | } |
4438 | 4439 | ||
4439 | done: | 4440 | done: |
4440 | if (vcpu->arch.emulate_ctxt.exception >= 0) { | 4441 | if (vcpu->arch.emulate_ctxt.have_exception) { |
4441 | inject_emulated_exception(vcpu); | 4442 | inject_emulated_exception(vcpu); |
4442 | r = EMULATE_DONE; | 4443 | r = EMULATE_DONE; |
4443 | } else if (vcpu->arch.pio.count) { | 4444 | } else if (vcpu->arch.pio.count) { |