aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorTakuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>2010-02-18 05:15:02 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2010-03-01 10:36:14 -0500
commite54cfa97a9ca9a544a7257b89b530b505ae1b892 (patch)
tree7ff46cd0cb6da4bab3dcdd7a0099f300a8b0b52f /arch/x86/kvm
parentc697518a861e6c43b92b848895f9926580ee63c3 (diff)
KVM: Fix emulate_sys[call, enter, exit]()'s fault handling
This patch fixes emulate_syscall(), emulate_sysenter() and emulate_sysexit() to handle injected faults properly. Even though original code injects faults in these functions, we cannot handle these unless we use the different return value from the UNHANDLEABLE case. So this patch use X86EMUL_* codes instead of -1 and 0 and makes x86_emulate_insn() to handle these propagated faults. Be sure that, in x86_emulate_insn(), goto cannot_emulate and goto done with rc equals X86EMUL_UNHANDLEABLE have same effect. Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/emulate.c37
1 files changed, 20 insertions, 17 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index a1a7b27adf41..4dade6ac0827 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1599,7 +1599,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
1599 1599
1600 /* syscall is not available in real mode */ 1600 /* syscall is not available in real mode */
1601 if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86) 1601 if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86)
1602 return -1; 1602 return X86EMUL_UNHANDLEABLE;
1603 1603
1604 setup_syscalls_segments(ctxt, &cs, &ss); 1604 setup_syscalls_segments(ctxt, &cs, &ss);
1605 1605
@@ -1636,7 +1636,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
1636 ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF); 1636 ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
1637 } 1637 }
1638 1638
1639 return 0; 1639 return X86EMUL_CONTINUE;
1640} 1640}
1641 1641
1642static int 1642static int
@@ -1649,14 +1649,14 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
1649 /* inject #GP if in real mode */ 1649 /* inject #GP if in real mode */
1650 if (ctxt->mode == X86EMUL_MODE_REAL) { 1650 if (ctxt->mode == X86EMUL_MODE_REAL) {
1651 kvm_inject_gp(ctxt->vcpu, 0); 1651 kvm_inject_gp(ctxt->vcpu, 0);
1652 return -1; 1652 return X86EMUL_UNHANDLEABLE;
1653 } 1653 }
1654 1654
1655 /* XXX sysenter/sysexit have not been tested in 64bit mode. 1655 /* XXX sysenter/sysexit have not been tested in 64bit mode.
1656 * Therefore, we inject an #UD. 1656 * Therefore, we inject an #UD.
1657 */ 1657 */
1658 if (ctxt->mode == X86EMUL_MODE_PROT64) 1658 if (ctxt->mode == X86EMUL_MODE_PROT64)
1659 return -1; 1659 return X86EMUL_UNHANDLEABLE;
1660 1660
1661 setup_syscalls_segments(ctxt, &cs, &ss); 1661 setup_syscalls_segments(ctxt, &cs, &ss);
1662 1662
@@ -1665,13 +1665,13 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
1665 case X86EMUL_MODE_PROT32: 1665 case X86EMUL_MODE_PROT32:
1666 if ((msr_data & 0xfffc) == 0x0) { 1666 if ((msr_data & 0xfffc) == 0x0) {
1667 kvm_inject_gp(ctxt->vcpu, 0); 1667 kvm_inject_gp(ctxt->vcpu, 0);
1668 return -1; 1668 return X86EMUL_PROPAGATE_FAULT;
1669 } 1669 }
1670 break; 1670 break;
1671 case X86EMUL_MODE_PROT64: 1671 case X86EMUL_MODE_PROT64:
1672 if (msr_data == 0x0) { 1672 if (msr_data == 0x0) {
1673 kvm_inject_gp(ctxt->vcpu, 0); 1673 kvm_inject_gp(ctxt->vcpu, 0);
1674 return -1; 1674 return X86EMUL_PROPAGATE_FAULT;
1675 } 1675 }
1676 break; 1676 break;
1677 } 1677 }
@@ -1696,7 +1696,7 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
1696 kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data); 1696 kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
1697 c->regs[VCPU_REGS_RSP] = msr_data; 1697 c->regs[VCPU_REGS_RSP] = msr_data;
1698 1698
1699 return 0; 1699 return X86EMUL_CONTINUE;
1700} 1700}
1701 1701
1702static int 1702static int
@@ -1711,7 +1711,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
1711 if (ctxt->mode == X86EMUL_MODE_REAL || 1711 if (ctxt->mode == X86EMUL_MODE_REAL ||
1712 ctxt->mode == X86EMUL_MODE_VM86) { 1712 ctxt->mode == X86EMUL_MODE_VM86) {
1713 kvm_inject_gp(ctxt->vcpu, 0); 1713 kvm_inject_gp(ctxt->vcpu, 0);
1714 return -1; 1714 return X86EMUL_UNHANDLEABLE;
1715 } 1715 }
1716 1716
1717 setup_syscalls_segments(ctxt, &cs, &ss); 1717 setup_syscalls_segments(ctxt, &cs, &ss);
@@ -1729,7 +1729,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
1729 cs.selector = (u16)(msr_data + 16); 1729 cs.selector = (u16)(msr_data + 16);
1730 if ((msr_data & 0xfffc) == 0x0) { 1730 if ((msr_data & 0xfffc) == 0x0) {
1731 kvm_inject_gp(ctxt->vcpu, 0); 1731 kvm_inject_gp(ctxt->vcpu, 0);
1732 return -1; 1732 return X86EMUL_PROPAGATE_FAULT;
1733 } 1733 }
1734 ss.selector = (u16)(msr_data + 24); 1734 ss.selector = (u16)(msr_data + 24);
1735 break; 1735 break;
@@ -1737,7 +1737,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
1737 cs.selector = (u16)(msr_data + 32); 1737 cs.selector = (u16)(msr_data + 32);
1738 if (msr_data == 0x0) { 1738 if (msr_data == 0x0) {
1739 kvm_inject_gp(ctxt->vcpu, 0); 1739 kvm_inject_gp(ctxt->vcpu, 0);
1740 return -1; 1740 return X86EMUL_PROPAGATE_FAULT;
1741 } 1741 }
1742 ss.selector = cs.selector + 8; 1742 ss.selector = cs.selector + 8;
1743 cs.db = 0; 1743 cs.db = 0;
@@ -1753,7 +1753,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
1753 c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX]; 1753 c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX];
1754 c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX]; 1754 c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX];
1755 1755
1756 return 0; 1756 return X86EMUL_CONTINUE;
1757} 1757}
1758 1758
1759static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) 1759static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
@@ -2476,8 +2476,9 @@ twobyte_insn:
2476 } 2476 }
2477 break; 2477 break;
2478 case 0x05: /* syscall */ 2478 case 0x05: /* syscall */
2479 if (emulate_syscall(ctxt) == -1) 2479 rc = emulate_syscall(ctxt);
2480 goto cannot_emulate; 2480 if (rc != X86EMUL_CONTINUE)
2481 goto done;
2481 else 2482 else
2482 goto writeback; 2483 goto writeback;
2483 break; 2484 break;
@@ -2548,14 +2549,16 @@ twobyte_insn:
2548 c->dst.type = OP_NONE; 2549 c->dst.type = OP_NONE;
2549 break; 2550 break;
2550 case 0x34: /* sysenter */ 2551 case 0x34: /* sysenter */
2551 if (emulate_sysenter(ctxt) == -1) 2552 rc = emulate_sysenter(ctxt);
2552 goto cannot_emulate; 2553 if (rc != X86EMUL_CONTINUE)
2554 goto done;
2553 else 2555 else
2554 goto writeback; 2556 goto writeback;
2555 break; 2557 break;
2556 case 0x35: /* sysexit */ 2558 case 0x35: /* sysexit */
2557 if (emulate_sysexit(ctxt) == -1) 2559 rc = emulate_sysexit(ctxt);
2558 goto cannot_emulate; 2560 if (rc != X86EMUL_CONTINUE)
2561 goto done;
2559 else 2562 else
2560 goto writeback; 2563 goto writeback;
2561 break; 2564 break;