aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/mmu.c
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2008-02-22 12:21:37 -0500
committerAvi Kivity <avi@qumranet.com>2008-04-27 05:00:27 -0400
commit2f333bcb4edd8daef99dabe4e7df8277af73cff1 (patch)
treec984466e7756e0910bf470a094558b52bd10df33 /arch/x86/kvm/mmu.c
parent9f81128591ca1e9907f2e7a7b195e33232167d60 (diff)
KVM: MMU: hypercall based pte updates and TLB flushes
Hypercall based pte updates are faster than faults, and also allow use of the lazy MMU mode to batch operations. Don't report the feature if two dimensional paging is enabled. [avi: - one mmu_op hypercall instead of one per op - allow 64-bit gpa on hypercall - don't pass host errors (-ENOMEM) to guest] [akpm: warning fix on i386] Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r--arch/x86/kvm/mmu.c136
1 files changed, 135 insertions, 1 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 414405b6ec13..072e9422c914 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -28,6 +28,7 @@
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/swap.h> 29#include <linux/swap.h>
30#include <linux/hugetlb.h> 30#include <linux/hugetlb.h>
31#include <linux/compiler.h>
31 32
32#include <asm/page.h> 33#include <asm/page.h>
33#include <asm/cmpxchg.h> 34#include <asm/cmpxchg.h>
@@ -40,7 +41,7 @@
40 * 2. while doing 1. it walks guest-physical to host-physical 41 * 2. while doing 1. it walks guest-physical to host-physical
41 * If the hardware supports that we don't need to do shadow paging. 42 * If the hardware supports that we don't need to do shadow paging.
42 */ 43 */
43static bool tdp_enabled = false; 44bool tdp_enabled = false;
44 45
45#undef MMU_DEBUG 46#undef MMU_DEBUG
46 47
@@ -167,6 +168,13 @@ static int dbg = 1;
167#define ACC_USER_MASK PT_USER_MASK 168#define ACC_USER_MASK PT_USER_MASK
168#define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK) 169#define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK)
169 170
171struct kvm_pv_mmu_op_buffer {
172 void *ptr;
173 unsigned len;
174 unsigned processed;
175 char buf[512] __aligned(sizeof(long));
176};
177
170struct kvm_rmap_desc { 178struct kvm_rmap_desc {
171 u64 *shadow_ptes[RMAP_EXT]; 179 u64 *shadow_ptes[RMAP_EXT];
172 struct kvm_rmap_desc *more; 180 struct kvm_rmap_desc *more;
@@ -2003,6 +2011,132 @@ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm)
2003 return nr_mmu_pages; 2011 return nr_mmu_pages;
2004} 2012}
2005 2013
2014static void *pv_mmu_peek_buffer(struct kvm_pv_mmu_op_buffer *buffer,
2015 unsigned len)
2016{
2017 if (len > buffer->len)
2018 return NULL;
2019 return buffer->ptr;
2020}
2021
2022static void *pv_mmu_read_buffer(struct kvm_pv_mmu_op_buffer *buffer,
2023 unsigned len)
2024{
2025 void *ret;
2026
2027 ret = pv_mmu_peek_buffer(buffer, len);
2028 if (!ret)
2029 return ret;
2030 buffer->ptr += len;
2031 buffer->len -= len;
2032 buffer->processed += len;
2033 return ret;
2034}
2035
2036static int kvm_pv_mmu_write(struct kvm_vcpu *vcpu,
2037 gpa_t addr, gpa_t value)
2038{
2039 int bytes = 8;
2040 int r;
2041
2042 if (!is_long_mode(vcpu) && !is_pae(vcpu))
2043 bytes = 4;
2044
2045 r = mmu_topup_memory_caches(vcpu);
2046 if (r)
2047 return r;
2048
2049 if (!__emulator_write_phys(vcpu, addr, &value, bytes))
2050 return -EFAULT;
2051
2052 return 1;
2053}
2054
2055static int kvm_pv_mmu_flush_tlb(struct kvm_vcpu *vcpu)
2056{
2057 kvm_x86_ops->tlb_flush(vcpu);
2058 return 1;
2059}
2060
2061static int kvm_pv_mmu_release_pt(struct kvm_vcpu *vcpu, gpa_t addr)
2062{
2063 spin_lock(&vcpu->kvm->mmu_lock);
2064 mmu_unshadow(vcpu->kvm, addr >> PAGE_SHIFT);
2065 spin_unlock(&vcpu->kvm->mmu_lock);
2066 return 1;
2067}
2068
2069static int kvm_pv_mmu_op_one(struct kvm_vcpu *vcpu,
2070 struct kvm_pv_mmu_op_buffer *buffer)
2071{
2072 struct kvm_mmu_op_header *header;
2073
2074 header = pv_mmu_peek_buffer(buffer, sizeof *header);
2075 if (!header)
2076 return 0;
2077 switch (header->op) {
2078 case KVM_MMU_OP_WRITE_PTE: {
2079 struct kvm_mmu_op_write_pte *wpte;
2080
2081 wpte = pv_mmu_read_buffer(buffer, sizeof *wpte);
2082 if (!wpte)
2083 return 0;
2084 return kvm_pv_mmu_write(vcpu, wpte->pte_phys,
2085 wpte->pte_val);
2086 }
2087 case KVM_MMU_OP_FLUSH_TLB: {
2088 struct kvm_mmu_op_flush_tlb *ftlb;
2089
2090 ftlb = pv_mmu_read_buffer(buffer, sizeof *ftlb);
2091 if (!ftlb)
2092 return 0;
2093 return kvm_pv_mmu_flush_tlb(vcpu);
2094 }
2095 case KVM_MMU_OP_RELEASE_PT: {
2096 struct kvm_mmu_op_release_pt *rpt;
2097
2098 rpt = pv_mmu_read_buffer(buffer, sizeof *rpt);
2099 if (!rpt)
2100 return 0;
2101 return kvm_pv_mmu_release_pt(vcpu, rpt->pt_phys);
2102 }
2103 default: return 0;
2104 }
2105}
2106
2107int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
2108 gpa_t addr, unsigned long *ret)
2109{
2110 int r;
2111 struct kvm_pv_mmu_op_buffer buffer;
2112
2113 down_read(&vcpu->kvm->slots_lock);
2114 down_read(&current->mm->mmap_sem);
2115
2116 buffer.ptr = buffer.buf;
2117 buffer.len = min_t(unsigned long, bytes, sizeof buffer.buf);
2118 buffer.processed = 0;
2119
2120 r = kvm_read_guest(vcpu->kvm, addr, buffer.buf, buffer.len);
2121 if (r)
2122 goto out;
2123
2124 while (buffer.len) {
2125 r = kvm_pv_mmu_op_one(vcpu, &buffer);
2126 if (r < 0)
2127 goto out;
2128 if (r == 0)
2129 break;
2130 }
2131
2132 r = 1;
2133out:
2134 *ret = buffer.processed;
2135 up_read(&current->mm->mmap_sem);
2136 up_read(&vcpu->kvm->slots_lock);
2137 return r;
2138}
2139
2006#ifdef AUDIT 2140#ifdef AUDIT
2007 2141
2008static const char *audit_msg; 2142static const char *audit_msg;