aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohammed Gamal <m.gamal005@gmail.com>2010-08-04 07:38:06 -0400
committerAvi Kivity <avi@redhat.com>2010-10-24 04:51:00 -0400
commit6e154e56b4d7a6a28c54f0984e13d3f8defc4755 (patch)
tree1e075b700d3a150d7ac0dacc459b4f131fa72b3f
parent160ce1f1a8fe64b3e2686ae73fbf051ccfe7c7ef (diff)
KVM: x86 emulator: Add into, int, and int3 instructions (opcodes 0xcc-0xce)
This adds support for int instructions to the emulator. Signed-off-by: Mohammed Gamal <m.gamal005@gmail.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/kvm/emulate.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index a9a4a0b78a7d..5205d6890828 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1180,6 +1180,67 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt,
1180 return rc; 1180 return rc;
1181} 1181}
1182 1182
1183int emulate_int_real(struct x86_emulate_ctxt *ctxt,
1184 struct x86_emulate_ops *ops, int irq)
1185{
1186 struct decode_cache *c = &ctxt->decode;
1187 int rc = X86EMUL_CONTINUE;
1188 struct desc_ptr dt;
1189 gva_t cs_addr;
1190 gva_t eip_addr;
1191 u16 cs, eip;
1192 u32 err;
1193
1194 /* TODO: Add limit checks */
1195 c->src.val = ctxt->eflags;
1196 emulate_push(ctxt, ops);
1197
1198 ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC);
1199
1200 c->src.val = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
1201 emulate_push(ctxt, ops);
1202
1203 c->src.val = c->eip;
1204 emulate_push(ctxt, ops);
1205
1206 ops->get_idt(&dt, ctxt->vcpu);
1207
1208 eip_addr = dt.address + (irq << 2);
1209 cs_addr = dt.address + (irq << 2) + 2;
1210
1211 rc = ops->read_std(cs_addr, &cs, 2, ctxt->vcpu, &err);
1212 if (rc != X86EMUL_CONTINUE)
1213 return rc;
1214
1215 rc = ops->read_std(eip_addr, &eip, 2, ctxt->vcpu, &err);
1216 if (rc != X86EMUL_CONTINUE)
1217 return rc;
1218
1219 rc = load_segment_descriptor(ctxt, ops, cs, VCPU_SREG_CS);
1220 if (rc != X86EMUL_CONTINUE)
1221 return rc;
1222
1223 c->eip = eip;
1224
1225 return rc;
1226}
1227
1228static int emulate_int(struct x86_emulate_ctxt *ctxt,
1229 struct x86_emulate_ops *ops, int irq)
1230{
1231 switch(ctxt->mode) {
1232 case X86EMUL_MODE_REAL:
1233 return emulate_int_real(ctxt, ops, irq);
1234 case X86EMUL_MODE_VM86:
1235 case X86EMUL_MODE_PROT16:
1236 case X86EMUL_MODE_PROT32:
1237 case X86EMUL_MODE_PROT64:
1238 default:
1239 /* Protected mode interrupts unimplemented yet */
1240 return X86EMUL_UNHANDLEABLE;
1241 }
1242}
1243
1183static int emulate_iret_real(struct x86_emulate_ctxt *ctxt, 1244static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
1184 struct x86_emulate_ops *ops) 1245 struct x86_emulate_ops *ops)
1185{ 1246{
@@ -2616,6 +2677,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
2616 struct decode_cache *c = &ctxt->decode; 2677 struct decode_cache *c = &ctxt->decode;
2617 int rc = X86EMUL_CONTINUE; 2678 int rc = X86EMUL_CONTINUE;
2618 int saved_dst_type = c->dst.type; 2679 int saved_dst_type = c->dst.type;
2680 int irq; /* Used for int 3, int, and into */
2619 2681
2620 ctxt->decode.mem_read.pos = 0; 2682 ctxt->decode.mem_read.pos = 0;
2621 2683
@@ -2960,6 +3022,22 @@ special_insn:
2960 if (rc != X86EMUL_CONTINUE) 3022 if (rc != X86EMUL_CONTINUE)
2961 goto done; 3023 goto done;
2962 break; 3024 break;
3025 case 0xcc: /* int3 */
3026 irq = 3;
3027 goto do_interrupt;
3028 case 0xcd: /* int n */
3029 irq = c->src.val;
3030 do_interrupt:
3031 rc = emulate_int(ctxt, ops, irq);
3032 if (rc != X86EMUL_CONTINUE)
3033 goto done;
3034 break;
3035 case 0xce: /* into */
3036 if (ctxt->eflags & EFLG_OF) {
3037 irq = 4;
3038 goto do_interrupt;
3039 }
3040 break;
2963 case 0xcf: /* iret */ 3041 case 0xcf: /* iret */
2964 rc = emulate_iret(ctxt, ops); 3042 rc = emulate_iret(ctxt, ops);
2965 3043