aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao Guangrong <guangrong.xiao@linux.intel.com>2016-02-24 04:51:09 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2016-03-03 08:36:20 -0500
commit21ebbedaddf25a35a70fedc001ba7e5f5b9129bc (patch)
tree9bdc4d1421ba5915ac05a1923715a9da9f47bec5
parentaeecee2ea6e2b020de8bb562f4e79ab34eda3e22 (diff)
KVM: page track: add the framework of guest page tracking
The array, gfn_track[mode][gfn], is introduced in memory slot for every guest page, this is the tracking count for the gust page on different modes. If the page is tracked then the count is increased, the page is not tracked after the count reaches zero We use 'unsigned short' as the tracking count which should be enough as shadow page table only can use 2^14 (2^3 for level, 2^1 for cr4_pae, 2^2 for quadrant, 2^3 for access, 2^1 for nxe, 2^1 for cr0_wp, 2^1 for smep_andnot_wp, 2^1 for smap_andnot_wp, and 2^1 for smm) at most, there is enough room for other trackers Two callbacks, kvm_page_track_create_memslot() and kvm_page_track_free_memslot() are implemented in this patch, they are internally used to initialize and reclaim the memory of the array Currently, only write track mode is supported Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_host.h10
-rw-r--r--arch/x86/include/asm/kvm_page_track.h13
-rw-r--r--arch/x86/kvm/Makefile3
-rw-r--r--arch/x86/kvm/page_track.c52
-rw-r--r--arch/x86/kvm/x86.c5
5 files changed, 82 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 1f7fed5f35fc..71e43fe04bbc 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -32,6 +32,7 @@
32#include <asm/mtrr.h> 32#include <asm/mtrr.h>
33#include <asm/msr-index.h> 33#include <asm/msr-index.h>
34#include <asm/asm.h> 34#include <asm/asm.h>
35#include <asm/kvm_page_track.h>
35 36
36#define KVM_MAX_VCPUS 255 37#define KVM_MAX_VCPUS 255
37#define KVM_SOFT_MAX_VCPUS 160 38#define KVM_SOFT_MAX_VCPUS 160
@@ -214,6 +215,14 @@ struct kvm_mmu_memory_cache {
214 void *objects[KVM_NR_MEM_OBJS]; 215 void *objects[KVM_NR_MEM_OBJS];
215}; 216};
216 217
218/*
219 * the pages used as guest page table on soft mmu are tracked by
220 * kvm_memory_slot.arch.gfn_track which is 16 bits, so the role bits used
221 * by indirect shadow page can not be more than 15 bits.
222 *
223 * Currently, we used 14 bits that are @level, @cr4_pae, @quadrant, @access,
224 * @nxe, @cr0_wp, @smep_andnot_wp and @smap_andnot_wp.
225 */
217union kvm_mmu_page_role { 226union kvm_mmu_page_role {
218 unsigned word; 227 unsigned word;
219 struct { 228 struct {
@@ -650,6 +659,7 @@ struct kvm_lpage_info {
650struct kvm_arch_memory_slot { 659struct kvm_arch_memory_slot {
651 struct kvm_rmap_head *rmap[KVM_NR_PAGE_SIZES]; 660 struct kvm_rmap_head *rmap[KVM_NR_PAGE_SIZES];
652 struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1]; 661 struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
662 unsigned short *gfn_track[KVM_PAGE_TRACK_MAX];
653}; 663};
654 664
655/* 665/*
diff --git a/arch/x86/include/asm/kvm_page_track.h b/arch/x86/include/asm/kvm_page_track.h
new file mode 100644
index 000000000000..5520040682d1
--- /dev/null
+++ b/arch/x86/include/asm/kvm_page_track.h
@@ -0,0 +1,13 @@
1#ifndef _ASM_X86_KVM_PAGE_TRACK_H
2#define _ASM_X86_KVM_PAGE_TRACK_H
3
4enum kvm_page_track_mode {
5 KVM_PAGE_TRACK_WRITE,
6 KVM_PAGE_TRACK_MAX,
7};
8
9void kvm_page_track_free_memslot(struct kvm_memory_slot *free,
10 struct kvm_memory_slot *dont);
11int kvm_page_track_create_memslot(struct kvm_memory_slot *slot,
12 unsigned long npages);
13#endif
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index a1ff508bb423..464fa477afbf 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -13,9 +13,10 @@ kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o
13 13
14kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \ 14kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
15 i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \ 15 i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
16 hyperv.o 16 hyperv.o page_track.o
17 17
18kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += assigned-dev.o iommu.o 18kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += assigned-dev.o iommu.o
19
19kvm-intel-y += vmx.o pmu_intel.o 20kvm-intel-y += vmx.o pmu_intel.o
20kvm-amd-y += svm.o pmu_amd.o 21kvm-amd-y += svm.o pmu_amd.o
21 22
diff --git a/arch/x86/kvm/page_track.c b/arch/x86/kvm/page_track.c
new file mode 100644
index 000000000000..8c396d08c0a4
--- /dev/null
+++ b/arch/x86/kvm/page_track.c
@@ -0,0 +1,52 @@
1/*
2 * Support KVM gust page tracking
3 *
4 * This feature allows us to track page access in guest. Currently, only
5 * write access is tracked.
6 *
7 * Copyright(C) 2015 Intel Corporation.
8 *
9 * Author:
10 * Xiao Guangrong <guangrong.xiao@linux.intel.com>
11 *
12 * This work is licensed under the terms of the GNU GPL, version 2. See
13 * the COPYING file in the top-level directory.
14 */
15
16#include <linux/kvm_host.h>
17#include <asm/kvm_host.h>
18#include <asm/kvm_page_track.h>
19
20#include "mmu.h"
21
22void kvm_page_track_free_memslot(struct kvm_memory_slot *free,
23 struct kvm_memory_slot *dont)
24{
25 int i;
26
27 for (i = 0; i < KVM_PAGE_TRACK_MAX; i++)
28 if (!dont || free->arch.gfn_track[i] !=
29 dont->arch.gfn_track[i]) {
30 kvfree(free->arch.gfn_track[i]);
31 free->arch.gfn_track[i] = NULL;
32 }
33}
34
35int kvm_page_track_create_memslot(struct kvm_memory_slot *slot,
36 unsigned long npages)
37{
38 int i;
39
40 for (i = 0; i < KVM_PAGE_TRACK_MAX; i++) {
41 slot->arch.gfn_track[i] = kvm_kvzalloc(npages *
42 sizeof(*slot->arch.gfn_track[i]));
43 if (!slot->arch.gfn_track[i])
44 goto track_free;
45 }
46
47 return 0;
48
49track_free:
50 kvm_page_track_free_memslot(slot, NULL);
51 return -ENOMEM;
52}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 668625e47102..7b4cfea09deb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7871,6 +7871,8 @@ void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
7871 free->arch.lpage_info[i - 1] = NULL; 7871 free->arch.lpage_info[i - 1] = NULL;
7872 } 7872 }
7873 } 7873 }
7874
7875 kvm_page_track_free_memslot(free, dont);
7874} 7876}
7875 7877
7876int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot, 7878int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
@@ -7919,6 +7921,9 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
7919 } 7921 }
7920 } 7922 }
7921 7923
7924 if (kvm_page_track_create_memslot(slot, npages))
7925 goto out_free;
7926
7922 return 0; 7927 return 0;
7923 7928
7924out_free: 7929out_free: