diff options
author | Mohammed Gamal <m.gamal005@gmail.com> | 2010-07-28 05:38:40 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:50:05 -0400 |
commit | 62bd430e6d41ac84ff2fb719f5783c3692718f47 (patch) | |
tree | d4f956bb6e12a9a76d5aa724dbe12a34c7f6c4ed /arch/x86/kvm/emulate.c | |
parent | 7a190667bb316653cbb782fff95cfdfcf51ded45 (diff) |
KVM: x86 emulator: Add IRET instruction
Ths patch adds IRET instruction (opcode 0xcf).
Currently, only IRET in real mode is emulated. Protected mode support is to be added later if needed.
Signed-off-by: Mohammed Gamal <m.gamal005@gmail.com>
Reviewed-by: Avi Kivity <avi@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 7f615c57cbad..b0f45bc63e1c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -341,6 +341,9 @@ static u32 group2_table[] = { | |||
341 | #define EFLG_PF (1<<2) | 341 | #define EFLG_PF (1<<2) |
342 | #define EFLG_CF (1<<0) | 342 | #define EFLG_CF (1<<0) |
343 | 343 | ||
344 | #define EFLG_RESERVED_ZEROS_MASK 0xffc0802a | ||
345 | #define EFLG_RESERVED_ONE_MASK 2 | ||
346 | |||
344 | /* | 347 | /* |
345 | * Instruction emulation: | 348 | * Instruction emulation: |
346 | * Most instructions are emulated directly via a fragment of inline assembly | 349 | * Most instructions are emulated directly via a fragment of inline assembly |
@@ -1729,6 +1732,78 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt, | |||
1729 | return rc; | 1732 | return rc; |
1730 | } | 1733 | } |
1731 | 1734 | ||
1735 | static int emulate_iret_real(struct x86_emulate_ctxt *ctxt, | ||
1736 | struct x86_emulate_ops *ops) | ||
1737 | { | ||
1738 | struct decode_cache *c = &ctxt->decode; | ||
1739 | int rc = X86EMUL_CONTINUE; | ||
1740 | unsigned long temp_eip = 0; | ||
1741 | unsigned long temp_eflags = 0; | ||
1742 | unsigned long cs = 0; | ||
1743 | unsigned long mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_TF | | ||
1744 | EFLG_IF | EFLG_DF | EFLG_OF | EFLG_IOPL | EFLG_NT | EFLG_RF | | ||
1745 | EFLG_AC | EFLG_ID | (1 << 1); /* Last one is the reserved bit */ | ||
1746 | unsigned long vm86_mask = EFLG_VM | EFLG_VIF | EFLG_VIP; | ||
1747 | |||
1748 | /* TODO: Add stack limit check */ | ||
1749 | |||
1750 | rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes); | ||
1751 | |||
1752 | if (rc != X86EMUL_CONTINUE) | ||
1753 | return rc; | ||
1754 | |||
1755 | if (temp_eip & ~0xffff) { | ||
1756 | emulate_gp(ctxt, 0); | ||
1757 | return X86EMUL_PROPAGATE_FAULT; | ||
1758 | } | ||
1759 | |||
1760 | rc = emulate_pop(ctxt, ops, &cs, c->op_bytes); | ||
1761 | |||
1762 | if (rc != X86EMUL_CONTINUE) | ||
1763 | return rc; | ||
1764 | |||
1765 | rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes); | ||
1766 | |||
1767 | if (rc != X86EMUL_CONTINUE) | ||
1768 | return rc; | ||
1769 | |||
1770 | rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS); | ||
1771 | |||
1772 | if (rc != X86EMUL_CONTINUE) | ||
1773 | return rc; | ||
1774 | |||
1775 | c->eip = temp_eip; | ||
1776 | |||
1777 | |||
1778 | if (c->op_bytes == 4) | ||
1779 | ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask)); | ||
1780 | else if (c->op_bytes == 2) { | ||
1781 | ctxt->eflags &= ~0xffff; | ||
1782 | ctxt->eflags |= temp_eflags; | ||
1783 | } | ||
1784 | |||
1785 | ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */ | ||
1786 | ctxt->eflags |= EFLG_RESERVED_ONE_MASK; | ||
1787 | |||
1788 | return rc; | ||
1789 | } | ||
1790 | |||
1791 | static inline int emulate_iret(struct x86_emulate_ctxt *ctxt, | ||
1792 | struct x86_emulate_ops* ops) | ||
1793 | { | ||
1794 | switch(ctxt->mode) { | ||
1795 | case X86EMUL_MODE_REAL: | ||
1796 | return emulate_iret_real(ctxt, ops); | ||
1797 | case X86EMUL_MODE_VM86: | ||
1798 | case X86EMUL_MODE_PROT16: | ||
1799 | case X86EMUL_MODE_PROT32: | ||
1800 | case X86EMUL_MODE_PROT64: | ||
1801 | default: | ||
1802 | /* iret from protected mode unimplemented yet */ | ||
1803 | return X86EMUL_UNHANDLEABLE; | ||
1804 | } | ||
1805 | } | ||
1806 | |||
1732 | static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt, | 1807 | static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt, |
1733 | struct x86_emulate_ops *ops) | 1808 | struct x86_emulate_ops *ops) |
1734 | { | 1809 | { |
@@ -2860,6 +2935,12 @@ special_insn: | |||
2860 | if (rc != X86EMUL_CONTINUE) | 2935 | if (rc != X86EMUL_CONTINUE) |
2861 | goto done; | 2936 | goto done; |
2862 | break; | 2937 | break; |
2938 | case 0xcf: /* iret */ | ||
2939 | rc = emulate_iret(ctxt, ops); | ||
2940 | |||
2941 | if (rc != X86EMUL_CONTINUE) | ||
2942 | goto done; | ||
2943 | break; | ||
2863 | case 0xd0 ... 0xd1: /* Grp2 */ | 2944 | case 0xd0 ... 0xd1: /* Grp2 */ |
2864 | c->src.val = 1; | 2945 | c->src.val = 1; |
2865 | emulate_grp2(ctxt); | 2946 | emulate_grp2(ctxt); |