diff options
author | Sheng Yang <sheng.yang@intel.com> | 2008-04-25 09:44:52 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-05-04 07:44:41 -0400 |
commit | b7ebfb0509692cd923e31650f81ed4d79c9a3e59 (patch) | |
tree | def19d1472976c479287bc00384706e1e9fca461 /arch/x86/kvm | |
parent | 0d15029895051904e31925ec63525cc3a637f7de (diff) |
KVM: VMX: Prepare an identity page table for EPT in real mode
[aliguory: plug leak]
Signed-off-by: Sheng Yang <sheng.yang@intel.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/vmx.c | 79 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.h | 3 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 2 |
3 files changed, 81 insertions, 3 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 98e4f2b036de..de5f6150f2f7 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -87,7 +87,7 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) | |||
87 | return container_of(vcpu, struct vcpu_vmx, vcpu); | 87 | return container_of(vcpu, struct vcpu_vmx, vcpu); |
88 | } | 88 | } |
89 | 89 | ||
90 | static int init_rmode_tss(struct kvm *kvm); | 90 | static int init_rmode(struct kvm *kvm); |
91 | 91 | ||
92 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); | 92 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); |
93 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); | 93 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); |
@@ -1304,7 +1304,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) | |||
1304 | fix_rmode_seg(VCPU_SREG_FS, &vcpu->arch.rmode.fs); | 1304 | fix_rmode_seg(VCPU_SREG_FS, &vcpu->arch.rmode.fs); |
1305 | 1305 | ||
1306 | kvm_mmu_reset_context(vcpu); | 1306 | kvm_mmu_reset_context(vcpu); |
1307 | init_rmode_tss(vcpu->kvm); | 1307 | init_rmode(vcpu->kvm); |
1308 | } | 1308 | } |
1309 | 1309 | ||
1310 | #ifdef CONFIG_X86_64 | 1310 | #ifdef CONFIG_X86_64 |
@@ -1578,6 +1578,41 @@ out: | |||
1578 | return ret; | 1578 | return ret; |
1579 | } | 1579 | } |
1580 | 1580 | ||
1581 | static int init_rmode_identity_map(struct kvm *kvm) | ||
1582 | { | ||
1583 | int i, r, ret; | ||
1584 | pfn_t identity_map_pfn; | ||
1585 | u32 tmp; | ||
1586 | |||
1587 | if (!vm_need_ept()) | ||
1588 | return 1; | ||
1589 | if (unlikely(!kvm->arch.ept_identity_pagetable)) { | ||
1590 | printk(KERN_ERR "EPT: identity-mapping pagetable " | ||
1591 | "haven't been allocated!\n"); | ||
1592 | return 0; | ||
1593 | } | ||
1594 | if (likely(kvm->arch.ept_identity_pagetable_done)) | ||
1595 | return 1; | ||
1596 | ret = 0; | ||
1597 | identity_map_pfn = VMX_EPT_IDENTITY_PAGETABLE_ADDR >> PAGE_SHIFT; | ||
1598 | r = kvm_clear_guest_page(kvm, identity_map_pfn, 0, PAGE_SIZE); | ||
1599 | if (r < 0) | ||
1600 | goto out; | ||
1601 | /* Set up identity-mapping pagetable for EPT in real mode */ | ||
1602 | for (i = 0; i < PT32_ENT_PER_PAGE; i++) { | ||
1603 | tmp = (i << 22) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | | ||
1604 | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE); | ||
1605 | r = kvm_write_guest_page(kvm, identity_map_pfn, | ||
1606 | &tmp, i * sizeof(tmp), sizeof(tmp)); | ||
1607 | if (r < 0) | ||
1608 | goto out; | ||
1609 | } | ||
1610 | kvm->arch.ept_identity_pagetable_done = true; | ||
1611 | ret = 1; | ||
1612 | out: | ||
1613 | return ret; | ||
1614 | } | ||
1615 | |||
1581 | static void seg_setup(int seg) | 1616 | static void seg_setup(int seg) |
1582 | { | 1617 | { |
1583 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; | 1618 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; |
@@ -1612,6 +1647,31 @@ out: | |||
1612 | return r; | 1647 | return r; |
1613 | } | 1648 | } |
1614 | 1649 | ||
1650 | static int alloc_identity_pagetable(struct kvm *kvm) | ||
1651 | { | ||
1652 | struct kvm_userspace_memory_region kvm_userspace_mem; | ||
1653 | int r = 0; | ||
1654 | |||
1655 | down_write(&kvm->slots_lock); | ||
1656 | if (kvm->arch.ept_identity_pagetable) | ||
1657 | goto out; | ||
1658 | kvm_userspace_mem.slot = IDENTITY_PAGETABLE_PRIVATE_MEMSLOT; | ||
1659 | kvm_userspace_mem.flags = 0; | ||
1660 | kvm_userspace_mem.guest_phys_addr = VMX_EPT_IDENTITY_PAGETABLE_ADDR; | ||
1661 | kvm_userspace_mem.memory_size = PAGE_SIZE; | ||
1662 | r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0); | ||
1663 | if (r) | ||
1664 | goto out; | ||
1665 | |||
1666 | down_read(¤t->mm->mmap_sem); | ||
1667 | kvm->arch.ept_identity_pagetable = gfn_to_page(kvm, | ||
1668 | VMX_EPT_IDENTITY_PAGETABLE_ADDR >> PAGE_SHIFT); | ||
1669 | up_read(¤t->mm->mmap_sem); | ||
1670 | out: | ||
1671 | up_write(&kvm->slots_lock); | ||
1672 | return r; | ||
1673 | } | ||
1674 | |||
1615 | static void allocate_vpid(struct vcpu_vmx *vmx) | 1675 | static void allocate_vpid(struct vcpu_vmx *vmx) |
1616 | { | 1676 | { |
1617 | int vpid; | 1677 | int vpid; |
@@ -1775,6 +1835,15 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | |||
1775 | return 0; | 1835 | return 0; |
1776 | } | 1836 | } |
1777 | 1837 | ||
1838 | static int init_rmode(struct kvm *kvm) | ||
1839 | { | ||
1840 | if (!init_rmode_tss(kvm)) | ||
1841 | return 0; | ||
1842 | if (!init_rmode_identity_map(kvm)) | ||
1843 | return 0; | ||
1844 | return 1; | ||
1845 | } | ||
1846 | |||
1778 | static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) | 1847 | static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) |
1779 | { | 1848 | { |
1780 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 1849 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
@@ -1782,7 +1851,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) | |||
1782 | int ret; | 1851 | int ret; |
1783 | 1852 | ||
1784 | down_read(&vcpu->kvm->slots_lock); | 1853 | down_read(&vcpu->kvm->slots_lock); |
1785 | if (!init_rmode_tss(vmx->vcpu.kvm)) { | 1854 | if (!init_rmode(vmx->vcpu.kvm)) { |
1786 | ret = -ENOMEM; | 1855 | ret = -ENOMEM; |
1787 | goto out; | 1856 | goto out; |
1788 | } | 1857 | } |
@@ -2759,6 +2828,10 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) | |||
2759 | if (alloc_apic_access_page(kvm) != 0) | 2828 | if (alloc_apic_access_page(kvm) != 0) |
2760 | goto free_vmcs; | 2829 | goto free_vmcs; |
2761 | 2830 | ||
2831 | if (vm_need_ept()) | ||
2832 | if (alloc_identity_pagetable(kvm) != 0) | ||
2833 | goto free_vmcs; | ||
2834 | |||
2762 | return &vmx->vcpu; | 2835 | return &vmx->vcpu; |
2763 | 2836 | ||
2764 | free_vmcs: | 2837 | free_vmcs: |
diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h index 093b085daf6a..f97eccc754e8 100644 --- a/arch/x86/kvm/vmx.h +++ b/arch/x86/kvm/vmx.h | |||
@@ -340,6 +340,7 @@ enum vmcs_field { | |||
340 | #define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4 | 340 | #define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4 |
341 | 341 | ||
342 | #define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 | 342 | #define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 |
343 | #define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT 10 | ||
343 | 344 | ||
344 | #define VMX_NR_VPIDS (1 << 16) | 345 | #define VMX_NR_VPIDS (1 << 16) |
345 | #define VMX_VPID_EXTENT_SINGLE_CONTEXT 1 | 346 | #define VMX_VPID_EXTENT_SINGLE_CONTEXT 1 |
@@ -353,4 +354,6 @@ enum vmcs_field { | |||
353 | #define VMX_EPT_EXTENT_GLOBAL_BIT (1ull << 26) | 354 | #define VMX_EPT_EXTENT_GLOBAL_BIT (1ull << 26) |
354 | #define VMX_EPT_DEFAULT_GAW 3 | 355 | #define VMX_EPT_DEFAULT_GAW 3 |
355 | 356 | ||
357 | #define VMX_EPT_IDENTITY_PAGETABLE_ADDR 0xfffbc000ul | ||
358 | |||
356 | #endif | 359 | #endif |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0735efbfa712..1842a86f7c33 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -3909,6 +3909,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) | |||
3909 | kvm_free_physmem(kvm); | 3909 | kvm_free_physmem(kvm); |
3910 | if (kvm->arch.apic_access_page) | 3910 | if (kvm->arch.apic_access_page) |
3911 | put_page(kvm->arch.apic_access_page); | 3911 | put_page(kvm->arch.apic_access_page); |
3912 | if (kvm->arch.ept_identity_pagetable) | ||
3913 | put_page(kvm->arch.ept_identity_pagetable); | ||
3912 | kfree(kvm); | 3914 | kfree(kvm); |
3913 | } | 3915 | } |
3914 | 3916 | ||