aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/svm.c
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2008-11-25 14:17:03 -0500
committerAvi Kivity <avi@redhat.com>2009-03-24 05:02:46 -0400
commitc0725420cfdcf6dd9705b164a8c6cba86684080d (patch)
tree9ecc99526376bded58702048262e419159309fb1 /arch/x86/kvm/svm.c
parent9962d032bbff0268f22068787831405f8468c8b4 (diff)
KVM: SVM: Add helper functions for nested SVM
These are helpers for the nested SVM implementation. - nsvm_printk implements a debug printk variant - nested_svm_do calls a handler that can accesses gpa-based memory v3 makes use of the new permission checker v6 changes: - streamline nsvm_debug() - remove printk(KERN_ERR) - SVME check before CPL check - give GP error code - use new EFER constant Acked-by: Joerg Roedel <joro@8bytes.org> Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r--arch/x86/kvm/svm.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index e4eb3fd91b90..87debdcd1b90 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -50,6 +50,15 @@ MODULE_LICENSE("GPL");
50 50
51#define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) 51#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
52 52
53/* Turn on to get debugging output*/
54/* #define NESTED_DEBUG */
55
56#ifdef NESTED_DEBUG
57#define nsvm_printk(fmt, args...) printk(KERN_INFO fmt, ## args)
58#else
59#define nsvm_printk(fmt, args...) do {} while(0)
60#endif
61
53/* enable NPT for AMD64 and X86 with PAE */ 62/* enable NPT for AMD64 and X86 with PAE */
54#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) 63#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
55static bool npt_enabled = true; 64static bool npt_enabled = true;
@@ -1149,6 +1158,82 @@ static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
1149 return 1; 1158 return 1;
1150} 1159}
1151 1160
1161static int nested_svm_check_permissions(struct vcpu_svm *svm)
1162{
1163 if (!(svm->vcpu.arch.shadow_efer & EFER_SVME)
1164 || !is_paging(&svm->vcpu)) {
1165 kvm_queue_exception(&svm->vcpu, UD_VECTOR);
1166 return 1;
1167 }
1168
1169 if (svm->vmcb->save.cpl) {
1170 kvm_inject_gp(&svm->vcpu, 0);
1171 return 1;
1172 }
1173
1174 return 0;
1175}
1176
1177static struct page *nested_svm_get_page(struct vcpu_svm *svm, u64 gpa)
1178{
1179 struct page *page;
1180
1181 down_read(&current->mm->mmap_sem);
1182 page = gfn_to_page(svm->vcpu.kvm, gpa >> PAGE_SHIFT);
1183 up_read(&current->mm->mmap_sem);
1184
1185 if (is_error_page(page)) {
1186 printk(KERN_INFO "%s: could not find page at 0x%llx\n",
1187 __func__, gpa);
1188 kvm_release_page_clean(page);
1189 kvm_inject_gp(&svm->vcpu, 0);
1190 return NULL;
1191 }
1192 return page;
1193}
1194
1195static int nested_svm_do(struct vcpu_svm *svm,
1196 u64 arg1_gpa, u64 arg2_gpa, void *opaque,
1197 int (*handler)(struct vcpu_svm *svm,
1198 void *arg1,
1199 void *arg2,
1200 void *opaque))
1201{
1202 struct page *arg1_page;
1203 struct page *arg2_page = NULL;
1204 void *arg1;
1205 void *arg2 = NULL;
1206 int retval;
1207
1208 arg1_page = nested_svm_get_page(svm, arg1_gpa);
1209 if(arg1_page == NULL)
1210 return 1;
1211
1212 if (arg2_gpa) {
1213 arg2_page = nested_svm_get_page(svm, arg2_gpa);
1214 if(arg2_page == NULL) {
1215 kvm_release_page_clean(arg1_page);
1216 return 1;
1217 }
1218 }
1219
1220 arg1 = kmap_atomic(arg1_page, KM_USER0);
1221 if (arg2_gpa)
1222 arg2 = kmap_atomic(arg2_page, KM_USER1);
1223
1224 retval = handler(svm, arg1, arg2, opaque);
1225
1226 kunmap_atomic(arg1, KM_USER0);
1227 if (arg2_gpa)
1228 kunmap_atomic(arg2, KM_USER1);
1229
1230 kvm_release_page_dirty(arg1_page);
1231 if (arg2_gpa)
1232 kvm_release_page_dirty(arg2_page);
1233
1234 return retval;
1235}
1236
1152static int invalid_op_interception(struct vcpu_svm *svm, 1237static int invalid_op_interception(struct vcpu_svm *svm,
1153 struct kvm_run *kvm_run) 1238 struct kvm_run *kvm_run)
1154{ 1239{