diff options
author | Mohammed Gamal <m.gamal005@gmail.com> | 2010-08-04 07:38:06 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:51:00 -0400 |
commit | 6e154e56b4d7a6a28c54f0984e13d3f8defc4755 (patch) | |
tree | 1e075b700d3a150d7ac0dacc459b4f131fa72b3f | |
parent | 160ce1f1a8fe64b3e2686ae73fbf051ccfe7c7ef (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.c | 78 |
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 | ||
1183 | int 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 | |||
1228 | static 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 | |||
1183 | static int emulate_iret_real(struct x86_emulate_ctxt *ctxt, | 1244 | static 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 | ||