diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2014-03-27 06:58:02 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-07-11 03:13:58 -0400 |
commit | d40a6898e50c2589ca3d345ef5ca6671e2b35b1a (patch) | |
tree | 774afe302d8a79ce59bdc17f8d213e5d4564b9ed /arch/x86/kvm | |
parent | e24186e097b80c5995ff75e1bbcd541d09c9e42b (diff) |
KVM: emulate: protect checks on ctxt->d by a common "if (unlikely())"
There are several checks for "peculiar" aspects of instructions in both
x86_decode_insn and x86_emulate_insn. Group them together, and guard
them with a single "if" that lets the processor quickly skip them all.
Make this more effective by adding two more flag bits that say whether the
.intercept and .check_perm fields are valid. We will reuse these
flags later to avoid initializing fields of the emulate_ctxt struct.
This skims about 30 cycles for each emulated instructions, which is
approximately a 3% improvement.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/emulate.c | 175 |
1 files changed, 94 insertions, 81 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index d79677c6056d..ea56dae3e67c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -162,6 +162,8 @@ | |||
162 | #define NoWrite ((u64)1 << 45) /* No writeback */ | 162 | #define NoWrite ((u64)1 << 45) /* No writeback */ |
163 | #define SrcWrite ((u64)1 << 46) /* Write back src operand */ | 163 | #define SrcWrite ((u64)1 << 46) /* Write back src operand */ |
164 | #define NoMod ((u64)1 << 47) /* Mod field is ignored */ | 164 | #define NoMod ((u64)1 << 47) /* Mod field is ignored */ |
165 | #define Intercept ((u64)1 << 48) /* Has valid intercept field */ | ||
166 | #define CheckPerm ((u64)1 << 49) /* Has valid check_perm field */ | ||
165 | 167 | ||
166 | #define DstXacc (DstAccLo | SrcAccHi | SrcWrite) | 168 | #define DstXacc (DstAccLo | SrcAccHi | SrcWrite) |
167 | 169 | ||
@@ -3546,9 +3548,9 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) | |||
3546 | } | 3548 | } |
3547 | 3549 | ||
3548 | #define D(_y) { .flags = (_y) } | 3550 | #define D(_y) { .flags = (_y) } |
3549 | #define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } | 3551 | #define DI(_y, _i) { .flags = (_y)|Intercept, .intercept = x86_intercept_##_i } |
3550 | #define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ | 3552 | #define DIP(_y, _i, _p) { .flags = (_y)|Intercept|CheckPerm, \ |
3551 | .check_perm = (_p) } | 3553 | .intercept = x86_intercept_##_i, .check_perm = (_p) } |
3552 | #define N D(NotImpl) | 3554 | #define N D(NotImpl) |
3553 | #define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) } | 3555 | #define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) } |
3554 | #define G(_f, _g) { .flags = ((_f) | Group | ModRM), .u.group = (_g) } | 3556 | #define G(_f, _g) { .flags = ((_f) | Group | ModRM), .u.group = (_g) } |
@@ -3557,10 +3559,10 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) | |||
3557 | #define I(_f, _e) { .flags = (_f), .u.execute = (_e) } | 3559 | #define I(_f, _e) { .flags = (_f), .u.execute = (_e) } |
3558 | #define F(_f, _e) { .flags = (_f) | Fastop, .u.fastop = (_e) } | 3560 | #define F(_f, _e) { .flags = (_f) | Fastop, .u.fastop = (_e) } |
3559 | #define II(_f, _e, _i) \ | 3561 | #define II(_f, _e, _i) \ |
3560 | { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i } | 3562 | { .flags = (_f)|Intercept, .u.execute = (_e), .intercept = x86_intercept_##_i } |
3561 | #define IIP(_f, _e, _i, _p) \ | 3563 | #define IIP(_f, _e, _i, _p) \ |
3562 | { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i, \ | 3564 | { .flags = (_f)|Intercept|CheckPerm, .u.execute = (_e), \ |
3563 | .check_perm = (_p) } | 3565 | .intercept = x86_intercept_##_i, .check_perm = (_p) } |
3564 | #define GP(_f, _g) { .flags = ((_f) | Prefix), .u.gprefix = (_g) } | 3566 | #define GP(_f, _g) { .flags = ((_f) | Prefix), .u.gprefix = (_g) } |
3565 | 3567 | ||
3566 | #define D2bv(_f) D((_f) | ByteOp), D(_f) | 3568 | #define D2bv(_f) D((_f) | ByteOp), D(_f) |
@@ -4393,29 +4395,37 @@ done_prefixes: | |||
4393 | return EMULATION_FAILED; | 4395 | return EMULATION_FAILED; |
4394 | 4396 | ||
4395 | ctxt->execute = opcode.u.execute; | 4397 | ctxt->execute = opcode.u.execute; |
4396 | ctxt->check_perm = opcode.check_perm; | ||
4397 | ctxt->intercept = opcode.intercept; | ||
4398 | 4398 | ||
4399 | if (ctxt->d & NotImpl) | 4399 | if (unlikely(ctxt->d & |
4400 | return EMULATION_FAILED; | 4400 | (NotImpl|EmulateOnUD|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) { |
4401 | /* | ||
4402 | * These are copied unconditionally here, and checked unconditionally | ||
4403 | * in x86_emulate_insn. | ||
4404 | */ | ||
4405 | ctxt->check_perm = opcode.check_perm; | ||
4406 | ctxt->intercept = opcode.intercept; | ||
4401 | 4407 | ||
4402 | if (!(ctxt->d & EmulateOnUD) && ctxt->ud) | 4408 | if (ctxt->d & NotImpl) |
4403 | return EMULATION_FAILED; | 4409 | return EMULATION_FAILED; |
4404 | 4410 | ||
4405 | if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack)) | 4411 | if (!(ctxt->d & EmulateOnUD) && ctxt->ud) |
4406 | ctxt->op_bytes = 8; | 4412 | return EMULATION_FAILED; |
4407 | 4413 | ||
4408 | if (ctxt->d & Op3264) { | 4414 | if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack)) |
4409 | if (mode == X86EMUL_MODE_PROT64) | ||
4410 | ctxt->op_bytes = 8; | 4415 | ctxt->op_bytes = 8; |
4411 | else | ||
4412 | ctxt->op_bytes = 4; | ||
4413 | } | ||
4414 | 4416 | ||
4415 | if (ctxt->d & Sse) | 4417 | if (ctxt->d & Op3264) { |
4416 | ctxt->op_bytes = 16; | 4418 | if (mode == X86EMUL_MODE_PROT64) |
4417 | else if (ctxt->d & Mmx) | 4419 | ctxt->op_bytes = 8; |
4418 | ctxt->op_bytes = 8; | 4420 | else |
4421 | ctxt->op_bytes = 4; | ||
4422 | } | ||
4423 | |||
4424 | if (ctxt->d & Sse) | ||
4425 | ctxt->op_bytes = 16; | ||
4426 | else if (ctxt->d & Mmx) | ||
4427 | ctxt->op_bytes = 8; | ||
4428 | } | ||
4419 | 4429 | ||
4420 | /* ModRM and SIB bytes. */ | 4430 | /* ModRM and SIB bytes. */ |
4421 | if (ctxt->d & ModRM) { | 4431 | if (ctxt->d & ModRM) { |
@@ -4549,75 +4559,78 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) | |||
4549 | goto done; | 4559 | goto done; |
4550 | } | 4560 | } |
4551 | 4561 | ||
4552 | if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) || | 4562 | if (unlikely(ctxt->d & |
4553 | (ctxt->d & Undefined)) { | 4563 | (No64|Undefined|Sse|Mmx|Intercept|CheckPerm|Priv|Prot|String))) { |
4554 | rc = emulate_ud(ctxt); | 4564 | if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) || |
4555 | goto done; | 4565 | (ctxt->d & Undefined)) { |
4556 | } | 4566 | rc = emulate_ud(ctxt); |
4557 | 4567 | goto done; | |
4558 | if (((ctxt->d & (Sse|Mmx)) && ((ops->get_cr(ctxt, 0) & X86_CR0_EM))) | 4568 | } |
4559 | || ((ctxt->d & Sse) && !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) { | ||
4560 | rc = emulate_ud(ctxt); | ||
4561 | goto done; | ||
4562 | } | ||
4563 | |||
4564 | if ((ctxt->d & (Sse|Mmx)) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) { | ||
4565 | rc = emulate_nm(ctxt); | ||
4566 | goto done; | ||
4567 | } | ||
4568 | 4569 | ||
4569 | if (ctxt->d & Mmx) { | 4570 | if (((ctxt->d & (Sse|Mmx)) && ((ops->get_cr(ctxt, 0) & X86_CR0_EM))) |
4570 | rc = flush_pending_x87_faults(ctxt); | 4571 | || ((ctxt->d & Sse) && !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) { |
4571 | if (rc != X86EMUL_CONTINUE) | 4572 | rc = emulate_ud(ctxt); |
4572 | goto done; | 4573 | goto done; |
4573 | /* | 4574 | } |
4574 | * Now that we know the fpu is exception safe, we can fetch | ||
4575 | * operands from it. | ||
4576 | */ | ||
4577 | fetch_possible_mmx_operand(ctxt, &ctxt->src); | ||
4578 | fetch_possible_mmx_operand(ctxt, &ctxt->src2); | ||
4579 | if (!(ctxt->d & Mov)) | ||
4580 | fetch_possible_mmx_operand(ctxt, &ctxt->dst); | ||
4581 | } | ||
4582 | 4575 | ||
4583 | if (unlikely(ctxt->guest_mode) && ctxt->intercept) { | 4576 | if ((ctxt->d & (Sse|Mmx)) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) { |
4584 | rc = emulator_check_intercept(ctxt, ctxt->intercept, | 4577 | rc = emulate_nm(ctxt); |
4585 | X86_ICPT_PRE_EXCEPT); | ||
4586 | if (rc != X86EMUL_CONTINUE) | ||
4587 | goto done; | 4578 | goto done; |
4588 | } | 4579 | } |
4589 | 4580 | ||
4590 | /* Privileged instruction can be executed only in CPL=0 */ | 4581 | if (ctxt->d & Mmx) { |
4591 | if ((ctxt->d & Priv) && ops->cpl(ctxt)) { | 4582 | rc = flush_pending_x87_faults(ctxt); |
4592 | rc = emulate_gp(ctxt, 0); | 4583 | if (rc != X86EMUL_CONTINUE) |
4593 | goto done; | 4584 | goto done; |
4594 | } | 4585 | /* |
4586 | * Now that we know the fpu is exception safe, we can fetch | ||
4587 | * operands from it. | ||
4588 | */ | ||
4589 | fetch_possible_mmx_operand(ctxt, &ctxt->src); | ||
4590 | fetch_possible_mmx_operand(ctxt, &ctxt->src2); | ||
4591 | if (!(ctxt->d & Mov)) | ||
4592 | fetch_possible_mmx_operand(ctxt, &ctxt->dst); | ||
4593 | } | ||
4595 | 4594 | ||
4596 | /* Instruction can only be executed in protected mode */ | 4595 | if (unlikely(ctxt->guest_mode) && ctxt->intercept) { |
4597 | if ((ctxt->d & Prot) && ctxt->mode < X86EMUL_MODE_PROT16) { | 4596 | rc = emulator_check_intercept(ctxt, ctxt->intercept, |
4598 | rc = emulate_ud(ctxt); | 4597 | X86_ICPT_PRE_EXCEPT); |
4599 | goto done; | 4598 | if (rc != X86EMUL_CONTINUE) |
4600 | } | 4599 | goto done; |
4600 | } | ||
4601 | 4601 | ||
4602 | /* Do instruction specific permission checks */ | 4602 | /* Privileged instruction can be executed only in CPL=0 */ |
4603 | if (ctxt->check_perm) { | 4603 | if ((ctxt->d & Priv) && ops->cpl(ctxt)) { |
4604 | rc = ctxt->check_perm(ctxt); | 4604 | rc = emulate_gp(ctxt, 0); |
4605 | if (rc != X86EMUL_CONTINUE) | ||
4606 | goto done; | 4605 | goto done; |
4607 | } | 4606 | } |
4608 | 4607 | ||
4609 | if (unlikely(ctxt->guest_mode) && ctxt->intercept) { | 4608 | /* Instruction can only be executed in protected mode */ |
4610 | rc = emulator_check_intercept(ctxt, ctxt->intercept, | 4609 | if ((ctxt->d & Prot) && ctxt->mode < X86EMUL_MODE_PROT16) { |
4611 | X86_ICPT_POST_EXCEPT); | 4610 | rc = emulate_ud(ctxt); |
4612 | if (rc != X86EMUL_CONTINUE) | ||
4613 | goto done; | 4611 | goto done; |
4614 | } | 4612 | } |
4615 | 4613 | ||
4616 | if (ctxt->rep_prefix && (ctxt->d & String)) { | 4614 | /* Do instruction specific permission checks */ |
4617 | /* All REP prefixes have the same first termination condition */ | 4615 | if (ctxt->check_perm) { |
4618 | if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) { | 4616 | rc = ctxt->check_perm(ctxt); |
4619 | ctxt->eip = ctxt->_eip; | 4617 | if (rc != X86EMUL_CONTINUE) |
4620 | goto done; | 4618 | goto done; |
4619 | } | ||
4620 | |||
4621 | if (unlikely(ctxt->guest_mode) && ctxt->intercept) { | ||
4622 | rc = emulator_check_intercept(ctxt, ctxt->intercept, | ||
4623 | X86_ICPT_POST_EXCEPT); | ||
4624 | if (rc != X86EMUL_CONTINUE) | ||
4625 | goto done; | ||
4626 | } | ||
4627 | |||
4628 | if (ctxt->rep_prefix && (ctxt->d & String)) { | ||
4629 | /* All REP prefixes have the same first termination condition */ | ||
4630 | if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) { | ||
4631 | ctxt->eip = ctxt->_eip; | ||
4632 | goto done; | ||
4633 | } | ||
4621 | } | 4634 | } |
4622 | } | 4635 | } |
4623 | 4636 | ||