diff options
author | Mohammed Gamal <m.gamal005@gmail.com> | 2008-08-17 09:38:32 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-10-15 04:15:20 -0400 |
commit | 648dfaa7df2d3692db4e63dcb18dccb275d9c5a7 (patch) | |
tree | c7e52aa54420df759d3ae2dcdf0fc239f831024f /arch/x86/kvm/vmx.c | |
parent | 6762b7299aa115e11815decd1fd982d015f09615 (diff) |
KVM: VMX: Add Guest State Validity Checks
This patch adds functions to check whether guest state is VMX compliant.
Signed-off-by: Mohammed Gamal <m.gamal005@gmail.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r-- | arch/x86/kvm/vmx.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 81db7d48ab80..e889b768c751 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -1721,6 +1721,186 @@ static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) | |||
1721 | vmcs_writel(GUEST_GDTR_BASE, dt->base); | 1721 | vmcs_writel(GUEST_GDTR_BASE, dt->base); |
1722 | } | 1722 | } |
1723 | 1723 | ||
1724 | static bool rmode_segment_valid(struct kvm_vcpu *vcpu, int seg) | ||
1725 | { | ||
1726 | struct kvm_segment var; | ||
1727 | u32 ar; | ||
1728 | |||
1729 | vmx_get_segment(vcpu, &var, seg); | ||
1730 | ar = vmx_segment_access_rights(&var); | ||
1731 | |||
1732 | if (var.base != (var.selector << 4)) | ||
1733 | return false; | ||
1734 | if (var.limit != 0xffff) | ||
1735 | return false; | ||
1736 | if (ar != 0xf3) | ||
1737 | return false; | ||
1738 | |||
1739 | return true; | ||
1740 | } | ||
1741 | |||
1742 | static bool code_segment_valid(struct kvm_vcpu *vcpu) | ||
1743 | { | ||
1744 | struct kvm_segment cs; | ||
1745 | unsigned int cs_rpl; | ||
1746 | |||
1747 | vmx_get_segment(vcpu, &cs, VCPU_SREG_CS); | ||
1748 | cs_rpl = cs.selector & SELECTOR_RPL_MASK; | ||
1749 | |||
1750 | if (~cs.type & (AR_TYPE_CODE_MASK|AR_TYPE_ACCESSES_MASK)) | ||
1751 | return false; | ||
1752 | if (!cs.s) | ||
1753 | return false; | ||
1754 | if (!(~cs.type & (AR_TYPE_CODE_MASK|AR_TYPE_WRITEABLE_MASK))) { | ||
1755 | if (cs.dpl > cs_rpl) | ||
1756 | return false; | ||
1757 | } else if (cs.type & AR_TYPE_CODE_MASK) { | ||
1758 | if (cs.dpl != cs_rpl) | ||
1759 | return false; | ||
1760 | } | ||
1761 | if (!cs.present) | ||
1762 | return false; | ||
1763 | |||
1764 | /* TODO: Add Reserved field check, this'll require a new member in the kvm_segment_field structure */ | ||
1765 | return true; | ||
1766 | } | ||
1767 | |||
1768 | static bool stack_segment_valid(struct kvm_vcpu *vcpu) | ||
1769 | { | ||
1770 | struct kvm_segment ss; | ||
1771 | unsigned int ss_rpl; | ||
1772 | |||
1773 | vmx_get_segment(vcpu, &ss, VCPU_SREG_SS); | ||
1774 | ss_rpl = ss.selector & SELECTOR_RPL_MASK; | ||
1775 | |||
1776 | if ((ss.type != 3) || (ss.type != 7)) | ||
1777 | return false; | ||
1778 | if (!ss.s) | ||
1779 | return false; | ||
1780 | if (ss.dpl != ss_rpl) /* DPL != RPL */ | ||
1781 | return false; | ||
1782 | if (!ss.present) | ||
1783 | return false; | ||
1784 | |||
1785 | return true; | ||
1786 | } | ||
1787 | |||
1788 | static bool data_segment_valid(struct kvm_vcpu *vcpu, int seg) | ||
1789 | { | ||
1790 | struct kvm_segment var; | ||
1791 | unsigned int rpl; | ||
1792 | |||
1793 | vmx_get_segment(vcpu, &var, seg); | ||
1794 | rpl = var.selector & SELECTOR_RPL_MASK; | ||
1795 | |||
1796 | if (!var.s) | ||
1797 | return false; | ||
1798 | if (!var.present) | ||
1799 | return false; | ||
1800 | if (~var.type & (AR_TYPE_CODE_MASK|AR_TYPE_WRITEABLE_MASK)) { | ||
1801 | if (var.dpl < rpl) /* DPL < RPL */ | ||
1802 | return false; | ||
1803 | } | ||
1804 | |||
1805 | /* TODO: Add other members to kvm_segment_field to allow checking for other access | ||
1806 | * rights flags | ||
1807 | */ | ||
1808 | return true; | ||
1809 | } | ||
1810 | |||
1811 | static bool tr_valid(struct kvm_vcpu *vcpu) | ||
1812 | { | ||
1813 | struct kvm_segment tr; | ||
1814 | |||
1815 | vmx_get_segment(vcpu, &tr, VCPU_SREG_TR); | ||
1816 | |||
1817 | if (tr.selector & SELECTOR_TI_MASK) /* TI = 1 */ | ||
1818 | return false; | ||
1819 | if ((tr.type != 3) || (tr.type != 11)) /* TODO: Check if guest is in IA32e mode */ | ||
1820 | return false; | ||
1821 | if (!tr.present) | ||
1822 | return false; | ||
1823 | |||
1824 | return true; | ||
1825 | } | ||
1826 | |||
1827 | static bool ldtr_valid(struct kvm_vcpu *vcpu) | ||
1828 | { | ||
1829 | struct kvm_segment ldtr; | ||
1830 | |||
1831 | vmx_get_segment(vcpu, &ldtr, VCPU_SREG_LDTR); | ||
1832 | |||
1833 | if (ldtr.selector & SELECTOR_TI_MASK) /* TI = 1 */ | ||
1834 | return false; | ||
1835 | if (ldtr.type != 2) | ||
1836 | return false; | ||
1837 | if (!ldtr.present) | ||
1838 | return false; | ||
1839 | |||
1840 | return true; | ||
1841 | } | ||
1842 | |||
1843 | static bool cs_ss_rpl_check(struct kvm_vcpu *vcpu) | ||
1844 | { | ||
1845 | struct kvm_segment cs, ss; | ||
1846 | |||
1847 | vmx_get_segment(vcpu, &cs, VCPU_SREG_CS); | ||
1848 | vmx_get_segment(vcpu, &ss, VCPU_SREG_SS); | ||
1849 | |||
1850 | return ((cs.selector & SELECTOR_RPL_MASK) == | ||
1851 | (ss.selector & SELECTOR_RPL_MASK)); | ||
1852 | } | ||
1853 | |||
1854 | /* | ||
1855 | * Check if guest state is valid. Returns true if valid, false if | ||
1856 | * not. | ||
1857 | * We assume that registers are always usable | ||
1858 | */ | ||
1859 | static bool guest_state_valid(struct kvm_vcpu *vcpu) | ||
1860 | { | ||
1861 | /* real mode guest state checks */ | ||
1862 | if (!(vcpu->arch.cr0 & X86_CR0_PE)) { | ||
1863 | if (!rmode_segment_valid(vcpu, VCPU_SREG_CS)) | ||
1864 | return false; | ||
1865 | if (!rmode_segment_valid(vcpu, VCPU_SREG_SS)) | ||
1866 | return false; | ||
1867 | if (!rmode_segment_valid(vcpu, VCPU_SREG_DS)) | ||
1868 | return false; | ||
1869 | if (!rmode_segment_valid(vcpu, VCPU_SREG_ES)) | ||
1870 | return false; | ||
1871 | if (!rmode_segment_valid(vcpu, VCPU_SREG_FS)) | ||
1872 | return false; | ||
1873 | if (!rmode_segment_valid(vcpu, VCPU_SREG_GS)) | ||
1874 | return false; | ||
1875 | } else { | ||
1876 | /* protected mode guest state checks */ | ||
1877 | if (!cs_ss_rpl_check(vcpu)) | ||
1878 | return false; | ||
1879 | if (!code_segment_valid(vcpu)) | ||
1880 | return false; | ||
1881 | if (!stack_segment_valid(vcpu)) | ||
1882 | return false; | ||
1883 | if (!data_segment_valid(vcpu, VCPU_SREG_DS)) | ||
1884 | return false; | ||
1885 | if (!data_segment_valid(vcpu, VCPU_SREG_ES)) | ||
1886 | return false; | ||
1887 | if (!data_segment_valid(vcpu, VCPU_SREG_FS)) | ||
1888 | return false; | ||
1889 | if (!data_segment_valid(vcpu, VCPU_SREG_GS)) | ||
1890 | return false; | ||
1891 | if (!tr_valid(vcpu)) | ||
1892 | return false; | ||
1893 | if (!ldtr_valid(vcpu)) | ||
1894 | return false; | ||
1895 | } | ||
1896 | /* TODO: | ||
1897 | * - Add checks on RIP | ||
1898 | * - Add checks on RFLAGS | ||
1899 | */ | ||
1900 | |||
1901 | return true; | ||
1902 | } | ||
1903 | |||
1724 | static int init_rmode_tss(struct kvm *kvm) | 1904 | static int init_rmode_tss(struct kvm *kvm) |
1725 | { | 1905 | { |
1726 | gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT; | 1906 | gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT; |