mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 10:19:47 +00:00
KVM: x86 emulator: unify four switch statements into two
Unify the special instruction switch with the regular instruction switch, and the two byte special instruction switch with the regular two byte instruction switch. That makes it much easier to find an instruction or the place an instruction needs to be added in. Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
111de5d60c
commit
018a98db74
1 changed files with 168 additions and 174 deletions
|
@ -1294,6 +1294,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
}
|
||||
c->dst.orig_val = c->dst.val;
|
||||
|
||||
special_insn:
|
||||
|
||||
if (c->twobyte)
|
||||
goto twobyte_insn;
|
||||
|
||||
|
@ -1378,6 +1380,52 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
goto cannot_emulate;
|
||||
c->dst.val = (s32) c->src.val;
|
||||
break;
|
||||
case 0x6a: /* push imm8 */
|
||||
c->src.val = 0L;
|
||||
c->src.val = insn_fetch(s8, 1, c->eip);
|
||||
emulate_push(ctxt);
|
||||
break;
|
||||
case 0x6c: /* insb */
|
||||
case 0x6d: /* insw/insd */
|
||||
if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
|
||||
1,
|
||||
(c->d & ByteOp) ? 1 : c->op_bytes,
|
||||
c->rep_prefix ?
|
||||
address_mask(c->regs[VCPU_REGS_RCX]) : 1,
|
||||
(ctxt->eflags & EFLG_DF),
|
||||
register_address(ctxt->es_base,
|
||||
c->regs[VCPU_REGS_RDI]),
|
||||
c->rep_prefix,
|
||||
c->regs[VCPU_REGS_RDX]) == 0) {
|
||||
c->eip = saved_eip;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
case 0x6e: /* outsb */
|
||||
case 0x6f: /* outsw/outsd */
|
||||
if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
|
||||
0,
|
||||
(c->d & ByteOp) ? 1 : c->op_bytes,
|
||||
c->rep_prefix ?
|
||||
address_mask(c->regs[VCPU_REGS_RCX]) : 1,
|
||||
(ctxt->eflags & EFLG_DF),
|
||||
register_address(c->override_base ?
|
||||
*c->override_base :
|
||||
ctxt->ds_base,
|
||||
c->regs[VCPU_REGS_RSI]),
|
||||
c->rep_prefix,
|
||||
c->regs[VCPU_REGS_RDX]) == 0) {
|
||||
c->eip = saved_eip;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
case 0x70 ... 0x7f: /* jcc (short) */ {
|
||||
int rel = insn_fetch(s8, 1, c->eip);
|
||||
|
||||
if (test_cc(c->b, ctxt->eflags))
|
||||
JMP_REL(rel);
|
||||
break;
|
||||
}
|
||||
case 0x80 ... 0x83: /* Grp1 */
|
||||
switch (c->modrm_reg) {
|
||||
case 0:
|
||||
|
@ -1434,106 +1482,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
if (rc != 0)
|
||||
goto done;
|
||||
break;
|
||||
case 0xa0 ... 0xa1: /* mov */
|
||||
c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
|
||||
c->dst.val = c->src.val;
|
||||
break;
|
||||
case 0xa2 ... 0xa3: /* mov */
|
||||
c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
|
||||
break;
|
||||
case 0xc0 ... 0xc1:
|
||||
emulate_grp2(ctxt);
|
||||
break;
|
||||
case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
|
||||
mov:
|
||||
c->dst.val = c->src.val;
|
||||
break;
|
||||
case 0xd0 ... 0xd1: /* Grp2 */
|
||||
c->src.val = 1;
|
||||
emulate_grp2(ctxt);
|
||||
break;
|
||||
case 0xd2 ... 0xd3: /* Grp2 */
|
||||
c->src.val = c->regs[VCPU_REGS_RCX];
|
||||
emulate_grp2(ctxt);
|
||||
break;
|
||||
case 0xf6 ... 0xf7: /* Grp3 */
|
||||
rc = emulate_grp3(ctxt, ops);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
break;
|
||||
case 0xfe ... 0xff: /* Grp4/Grp5 */
|
||||
rc = emulate_grp45(ctxt, ops);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
writeback:
|
||||
rc = writeback(ctxt, ops);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
|
||||
/* Commit shadow register state. */
|
||||
memcpy(ctxt->vcpu->regs, c->regs, sizeof c->regs);
|
||||
ctxt->vcpu->rip = c->eip;
|
||||
|
||||
done:
|
||||
if (rc == X86EMUL_UNHANDLEABLE) {
|
||||
c->eip = saved_eip;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
special_insn:
|
||||
if (c->twobyte)
|
||||
goto twobyte_special_insn;
|
||||
switch (c->b) {
|
||||
case 0x6a: /* push imm8 */
|
||||
c->src.val = 0L;
|
||||
c->src.val = insn_fetch(s8, 1, c->eip);
|
||||
emulate_push(ctxt);
|
||||
break;
|
||||
case 0x6c: /* insb */
|
||||
case 0x6d: /* insw/insd */
|
||||
if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
|
||||
1,
|
||||
(c->d & ByteOp) ? 1 : c->op_bytes,
|
||||
c->rep_prefix ?
|
||||
address_mask(c->regs[VCPU_REGS_RCX]) : 1,
|
||||
(ctxt->eflags & EFLG_DF),
|
||||
register_address(ctxt->es_base,
|
||||
c->regs[VCPU_REGS_RDI]),
|
||||
c->rep_prefix,
|
||||
c->regs[VCPU_REGS_RDX]) == 0) {
|
||||
c->eip = saved_eip;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
case 0x6e: /* outsb */
|
||||
case 0x6f: /* outsw/outsd */
|
||||
if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
|
||||
0,
|
||||
(c->d & ByteOp) ? 1 : c->op_bytes,
|
||||
c->rep_prefix ?
|
||||
address_mask(c->regs[VCPU_REGS_RCX]) : 1,
|
||||
(ctxt->eflags & EFLG_DF),
|
||||
register_address(c->override_base ?
|
||||
*c->override_base :
|
||||
ctxt->ds_base,
|
||||
c->regs[VCPU_REGS_RSI]),
|
||||
c->rep_prefix,
|
||||
c->regs[VCPU_REGS_RDX]) == 0) {
|
||||
c->eip = saved_eip;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
case 0x70 ... 0x7f: /* jcc (short) */ {
|
||||
int rel = insn_fetch(s8, 1, c->eip);
|
||||
|
||||
if (test_cc(c->b, ctxt->eflags))
|
||||
JMP_REL(rel);
|
||||
break;
|
||||
}
|
||||
case 0x9c: /* pushf */
|
||||
c->src.val = (unsigned long) ctxt->eflags;
|
||||
emulate_push(ctxt);
|
||||
|
@ -1541,6 +1489,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
case 0x9d: /* popf */
|
||||
c->dst.ptr = (unsigned long *) &ctxt->eflags;
|
||||
goto pop_instruction;
|
||||
case 0xa0 ... 0xa1: /* mov */
|
||||
c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
|
||||
c->dst.val = c->src.val;
|
||||
break;
|
||||
case 0xa2 ... 0xa3: /* mov */
|
||||
c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
|
||||
break;
|
||||
case 0xa4 ... 0xa5: /* movs */
|
||||
c->dst.type = OP_MEM;
|
||||
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||
|
@ -1627,9 +1582,24 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
case 0xae ... 0xaf: /* scas */
|
||||
DPRINTF("Urk! I don't handle SCAS.\n");
|
||||
goto cannot_emulate;
|
||||
case 0xc0 ... 0xc1:
|
||||
emulate_grp2(ctxt);
|
||||
break;
|
||||
case 0xc3: /* ret */
|
||||
c->dst.ptr = &c->eip;
|
||||
goto pop_instruction;
|
||||
case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
|
||||
mov:
|
||||
c->dst.val = c->src.val;
|
||||
break;
|
||||
case 0xd0 ... 0xd1: /* Grp2 */
|
||||
c->src.val = 1;
|
||||
emulate_grp2(ctxt);
|
||||
break;
|
||||
case 0xd2 ... 0xd3: /* Grp2 */
|
||||
c->src.val = c->regs[VCPU_REGS_RCX];
|
||||
emulate_grp2(ctxt);
|
||||
break;
|
||||
case 0xe8: /* call (near) */ {
|
||||
long int rel;
|
||||
switch (c->op_bytes) {
|
||||
|
@ -1662,6 +1632,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
ctxt->eflags ^= EFLG_CF;
|
||||
c->dst.type = OP_NONE; /* Disable writeback. */
|
||||
break;
|
||||
case 0xf6 ... 0xf7: /* Grp3 */
|
||||
rc = emulate_grp3(ctxt, ops);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
break;
|
||||
case 0xf8: /* clc */
|
||||
ctxt->eflags &= ~EFLG_CF;
|
||||
c->dst.type = OP_NONE; /* Disable writeback. */
|
||||
|
@ -1674,8 +1649,28 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
ctxt->eflags |= X86_EFLAGS_IF;
|
||||
c->dst.type = OP_NONE; /* Disable writeback. */
|
||||
break;
|
||||
case 0xfe ... 0xff: /* Grp4/Grp5 */
|
||||
rc = emulate_grp45(ctxt, ops);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
goto writeback;
|
||||
|
||||
writeback:
|
||||
rc = writeback(ctxt, ops);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
|
||||
/* Commit shadow register state. */
|
||||
memcpy(ctxt->vcpu->regs, c->regs, sizeof c->regs);
|
||||
ctxt->vcpu->rip = c->eip;
|
||||
|
||||
done:
|
||||
if (rc == X86EMUL_UNHANDLEABLE) {
|
||||
c->eip = saved_eip;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
twobyte_insn:
|
||||
switch (c->b) {
|
||||
|
@ -1737,6 +1732,23 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
/* Disable writeback. */
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
case 0x06:
|
||||
emulate_clts(ctxt->vcpu);
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
case 0x08: /* invd */
|
||||
case 0x09: /* wbinvd */
|
||||
case 0x0d: /* GrpP (prefetch) */
|
||||
case 0x18: /* Grp16 (prefetch/nop) */
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
case 0x20: /* mov cr, reg */
|
||||
if (c->modrm_mod != 3)
|
||||
goto cannot_emulate;
|
||||
c->regs[c->modrm_rm] =
|
||||
realmode_get_cr(ctxt->vcpu, c->modrm_reg);
|
||||
c->dst.type = OP_NONE; /* no writeback */
|
||||
break;
|
||||
case 0x21: /* mov from dr to reg */
|
||||
if (c->modrm_mod != 3)
|
||||
goto cannot_emulate;
|
||||
|
@ -1745,6 +1757,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
goto cannot_emulate;
|
||||
c->dst.type = OP_NONE; /* no writeback */
|
||||
break;
|
||||
case 0x22: /* mov reg, cr */
|
||||
if (c->modrm_mod != 3)
|
||||
goto cannot_emulate;
|
||||
realmode_set_cr(ctxt->vcpu,
|
||||
c->modrm_reg, c->modrm_val, &ctxt->eflags);
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
case 0x23: /* mov from reg to dr */
|
||||
if (c->modrm_mod != 3)
|
||||
goto cannot_emulate;
|
||||
|
@ -1754,11 +1773,58 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
goto cannot_emulate;
|
||||
c->dst.type = OP_NONE; /* no writeback */
|
||||
break;
|
||||
case 0x30:
|
||||
/* wrmsr */
|
||||
msr_data = (u32)c->regs[VCPU_REGS_RAX]
|
||||
| ((u64)c->regs[VCPU_REGS_RDX] << 32);
|
||||
rc = kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data);
|
||||
if (rc) {
|
||||
kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
|
||||
c->eip = ctxt->vcpu->rip;
|
||||
}
|
||||
rc = X86EMUL_CONTINUE;
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
case 0x32:
|
||||
/* rdmsr */
|
||||
rc = kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data);
|
||||
if (rc) {
|
||||
kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
|
||||
c->eip = ctxt->vcpu->rip;
|
||||
} else {
|
||||
c->regs[VCPU_REGS_RAX] = (u32)msr_data;
|
||||
c->regs[VCPU_REGS_RDX] = msr_data >> 32;
|
||||
}
|
||||
rc = X86EMUL_CONTINUE;
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
case 0x40 ... 0x4f: /* cmov */
|
||||
c->dst.val = c->dst.orig_val = c->src.val;
|
||||
if (!test_cc(c->b, ctxt->eflags))
|
||||
c->dst.type = OP_NONE; /* no writeback */
|
||||
break;
|
||||
case 0x80 ... 0x8f: /* jnz rel, etc*/ {
|
||||
long int rel;
|
||||
|
||||
switch (c->op_bytes) {
|
||||
case 2:
|
||||
rel = insn_fetch(s16, 2, c->eip);
|
||||
break;
|
||||
case 4:
|
||||
rel = insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
case 8:
|
||||
rel = insn_fetch(s64, 8, c->eip);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("jnz: Invalid op_bytes\n");
|
||||
goto cannot_emulate;
|
||||
}
|
||||
if (test_cc(c->b, ctxt->eflags))
|
||||
JMP_REL(rel);
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
}
|
||||
case 0xa3:
|
||||
bt: /* bt */
|
||||
c->dst.type = OP_NONE;
|
||||
|
@ -1828,85 +1894,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
c->dst.val = (c->op_bytes == 4) ? (u32) c->src.val :
|
||||
(u64) c->src.val;
|
||||
break;
|
||||
}
|
||||
goto writeback;
|
||||
|
||||
twobyte_special_insn:
|
||||
switch (c->b) {
|
||||
case 0x06:
|
||||
emulate_clts(ctxt->vcpu);
|
||||
break;
|
||||
case 0x08: /* invd */
|
||||
break;
|
||||
case 0x09: /* wbinvd */
|
||||
break;
|
||||
case 0x0d: /* GrpP (prefetch) */
|
||||
case 0x18: /* Grp16 (prefetch/nop) */
|
||||
break;
|
||||
case 0x20: /* mov cr, reg */
|
||||
if (c->modrm_mod != 3)
|
||||
goto cannot_emulate;
|
||||
c->regs[c->modrm_rm] =
|
||||
realmode_get_cr(ctxt->vcpu, c->modrm_reg);
|
||||
break;
|
||||
case 0x22: /* mov reg, cr */
|
||||
if (c->modrm_mod != 3)
|
||||
goto cannot_emulate;
|
||||
realmode_set_cr(ctxt->vcpu,
|
||||
c->modrm_reg, c->modrm_val, &ctxt->eflags);
|
||||
break;
|
||||
case 0x30:
|
||||
/* wrmsr */
|
||||
msr_data = (u32)c->regs[VCPU_REGS_RAX]
|
||||
| ((u64)c->regs[VCPU_REGS_RDX] << 32);
|
||||
rc = kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data);
|
||||
if (rc) {
|
||||
kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
|
||||
c->eip = ctxt->vcpu->rip;
|
||||
}
|
||||
rc = X86EMUL_CONTINUE;
|
||||
break;
|
||||
case 0x32:
|
||||
/* rdmsr */
|
||||
rc = kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data);
|
||||
if (rc) {
|
||||
kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
|
||||
c->eip = ctxt->vcpu->rip;
|
||||
} else {
|
||||
c->regs[VCPU_REGS_RAX] = (u32)msr_data;
|
||||
c->regs[VCPU_REGS_RDX] = msr_data >> 32;
|
||||
}
|
||||
rc = X86EMUL_CONTINUE;
|
||||
break;
|
||||
case 0x80 ... 0x8f: /* jnz rel, etc*/ {
|
||||
long int rel;
|
||||
|
||||
switch (c->op_bytes) {
|
||||
case 2:
|
||||
rel = insn_fetch(s16, 2, c->eip);
|
||||
break;
|
||||
case 4:
|
||||
rel = insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
case 8:
|
||||
rel = insn_fetch(s64, 8, c->eip);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("jnz: Invalid op_bytes\n");
|
||||
goto cannot_emulate;
|
||||
}
|
||||
if (test_cc(c->b, ctxt->eflags))
|
||||
JMP_REL(rel);
|
||||
break;
|
||||
}
|
||||
case 0xc7: /* Grp9 (cmpxchg8b) */
|
||||
rc = emulate_grp9(ctxt, ops, memop);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
c->dst.type = OP_NONE;
|
||||
break;
|
||||
}
|
||||
/* Disable writeback. */
|
||||
c->dst.type = OP_NONE;
|
||||
goto writeback;
|
||||
|
||||
cannot_emulate:
|
||||
|
|
Loading…
Reference in a new issue