diff options
Diffstat (limited to 'drivers/kvm/x86.c')
-rw-r--r-- | drivers/kvm/x86.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c index c1f10e58f4d2..2cf7ebab50f4 100644 --- a/drivers/kvm/x86.c +++ b/drivers/kvm/x86.c | |||
@@ -1610,3 +1610,178 @@ __init void kvm_arch_init(void) | |||
1610 | { | 1610 | { |
1611 | kvm_init_msr_list(); | 1611 | kvm_init_msr_list(); |
1612 | } | 1612 | } |
1613 | |||
1614 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) | ||
1615 | { | ||
1616 | ++vcpu->stat.halt_exits; | ||
1617 | if (irqchip_in_kernel(vcpu->kvm)) { | ||
1618 | vcpu->mp_state = VCPU_MP_STATE_HALTED; | ||
1619 | kvm_vcpu_block(vcpu); | ||
1620 | if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE) | ||
1621 | return -EINTR; | ||
1622 | return 1; | ||
1623 | } else { | ||
1624 | vcpu->run->exit_reason = KVM_EXIT_HLT; | ||
1625 | return 0; | ||
1626 | } | ||
1627 | } | ||
1628 | EXPORT_SYMBOL_GPL(kvm_emulate_halt); | ||
1629 | |||
1630 | int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) | ||
1631 | { | ||
1632 | unsigned long nr, a0, a1, a2, a3, ret; | ||
1633 | |||
1634 | kvm_x86_ops->cache_regs(vcpu); | ||
1635 | |||
1636 | nr = vcpu->regs[VCPU_REGS_RAX]; | ||
1637 | a0 = vcpu->regs[VCPU_REGS_RBX]; | ||
1638 | a1 = vcpu->regs[VCPU_REGS_RCX]; | ||
1639 | a2 = vcpu->regs[VCPU_REGS_RDX]; | ||
1640 | a3 = vcpu->regs[VCPU_REGS_RSI]; | ||
1641 | |||
1642 | if (!is_long_mode(vcpu)) { | ||
1643 | nr &= 0xFFFFFFFF; | ||
1644 | a0 &= 0xFFFFFFFF; | ||
1645 | a1 &= 0xFFFFFFFF; | ||
1646 | a2 &= 0xFFFFFFFF; | ||
1647 | a3 &= 0xFFFFFFFF; | ||
1648 | } | ||
1649 | |||
1650 | switch (nr) { | ||
1651 | default: | ||
1652 | ret = -KVM_ENOSYS; | ||
1653 | break; | ||
1654 | } | ||
1655 | vcpu->regs[VCPU_REGS_RAX] = ret; | ||
1656 | kvm_x86_ops->decache_regs(vcpu); | ||
1657 | return 0; | ||
1658 | } | ||
1659 | EXPORT_SYMBOL_GPL(kvm_emulate_hypercall); | ||
1660 | |||
1661 | int kvm_fix_hypercall(struct kvm_vcpu *vcpu) | ||
1662 | { | ||
1663 | char instruction[3]; | ||
1664 | int ret = 0; | ||
1665 | |||
1666 | mutex_lock(&vcpu->kvm->lock); | ||
1667 | |||
1668 | /* | ||
1669 | * Blow out the MMU to ensure that no other VCPU has an active mapping | ||
1670 | * to ensure that the updated hypercall appears atomically across all | ||
1671 | * VCPUs. | ||
1672 | */ | ||
1673 | kvm_mmu_zap_all(vcpu->kvm); | ||
1674 | |||
1675 | kvm_x86_ops->cache_regs(vcpu); | ||
1676 | kvm_x86_ops->patch_hypercall(vcpu, instruction); | ||
1677 | if (emulator_write_emulated(vcpu->rip, instruction, 3, vcpu) | ||
1678 | != X86EMUL_CONTINUE) | ||
1679 | ret = -EFAULT; | ||
1680 | |||
1681 | mutex_unlock(&vcpu->kvm->lock); | ||
1682 | |||
1683 | return ret; | ||
1684 | } | ||
1685 | |||
1686 | static u64 mk_cr_64(u64 curr_cr, u32 new_val) | ||
1687 | { | ||
1688 | return (curr_cr & ~((1ULL << 32) - 1)) | new_val; | ||
1689 | } | ||
1690 | |||
1691 | void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) | ||
1692 | { | ||
1693 | struct descriptor_table dt = { limit, base }; | ||
1694 | |||
1695 | kvm_x86_ops->set_gdt(vcpu, &dt); | ||
1696 | } | ||
1697 | |||
1698 | void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) | ||
1699 | { | ||
1700 | struct descriptor_table dt = { limit, base }; | ||
1701 | |||
1702 | kvm_x86_ops->set_idt(vcpu, &dt); | ||
1703 | } | ||
1704 | |||
1705 | void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, | ||
1706 | unsigned long *rflags) | ||
1707 | { | ||
1708 | lmsw(vcpu, msw); | ||
1709 | *rflags = kvm_x86_ops->get_rflags(vcpu); | ||
1710 | } | ||
1711 | |||
1712 | unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) | ||
1713 | { | ||
1714 | kvm_x86_ops->decache_cr4_guest_bits(vcpu); | ||
1715 | switch (cr) { | ||
1716 | case 0: | ||
1717 | return vcpu->cr0; | ||
1718 | case 2: | ||
1719 | return vcpu->cr2; | ||
1720 | case 3: | ||
1721 | return vcpu->cr3; | ||
1722 | case 4: | ||
1723 | return vcpu->cr4; | ||
1724 | default: | ||
1725 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); | ||
1726 | return 0; | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, | ||
1731 | unsigned long *rflags) | ||
1732 | { | ||
1733 | switch (cr) { | ||
1734 | case 0: | ||
1735 | set_cr0(vcpu, mk_cr_64(vcpu->cr0, val)); | ||
1736 | *rflags = kvm_x86_ops->get_rflags(vcpu); | ||
1737 | break; | ||
1738 | case 2: | ||
1739 | vcpu->cr2 = val; | ||
1740 | break; | ||
1741 | case 3: | ||
1742 | set_cr3(vcpu, val); | ||
1743 | break; | ||
1744 | case 4: | ||
1745 | set_cr4(vcpu, mk_cr_64(vcpu->cr4, val)); | ||
1746 | break; | ||
1747 | default: | ||
1748 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); | ||
1749 | } | ||
1750 | } | ||
1751 | |||
1752 | void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) | ||
1753 | { | ||
1754 | int i; | ||
1755 | u32 function; | ||
1756 | struct kvm_cpuid_entry *e, *best; | ||
1757 | |||
1758 | kvm_x86_ops->cache_regs(vcpu); | ||
1759 | function = vcpu->regs[VCPU_REGS_RAX]; | ||
1760 | vcpu->regs[VCPU_REGS_RAX] = 0; | ||
1761 | vcpu->regs[VCPU_REGS_RBX] = 0; | ||
1762 | vcpu->regs[VCPU_REGS_RCX] = 0; | ||
1763 | vcpu->regs[VCPU_REGS_RDX] = 0; | ||
1764 | best = NULL; | ||
1765 | for (i = 0; i < vcpu->cpuid_nent; ++i) { | ||
1766 | e = &vcpu->cpuid_entries[i]; | ||
1767 | if (e->function == function) { | ||
1768 | best = e; | ||
1769 | break; | ||
1770 | } | ||
1771 | /* | ||
1772 | * Both basic or both extended? | ||
1773 | */ | ||
1774 | if (((e->function ^ function) & 0x80000000) == 0) | ||
1775 | if (!best || e->function > best->function) | ||
1776 | best = e; | ||
1777 | } | ||
1778 | if (best) { | ||
1779 | vcpu->regs[VCPU_REGS_RAX] = best->eax; | ||
1780 | vcpu->regs[VCPU_REGS_RBX] = best->ebx; | ||
1781 | vcpu->regs[VCPU_REGS_RCX] = best->ecx; | ||
1782 | vcpu->regs[VCPU_REGS_RDX] = best->edx; | ||
1783 | } | ||
1784 | kvm_x86_ops->decache_regs(vcpu); | ||
1785 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1786 | } | ||
1787 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); | ||