diff options
author | Alexander Graf <agraf@suse.de> | 2008-11-25 14:17:03 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-03-24 05:02:46 -0400 |
commit | c0725420cfdcf6dd9705b164a8c6cba86684080d (patch) | |
tree | 9ecc99526376bded58702048262e419159309fb1 /arch/x86/kvm/svm.c | |
parent | 9962d032bbff0268f22068787831405f8468c8b4 (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.c | 85 |
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) |
55 | static bool npt_enabled = true; | 64 | static 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 | ||
1161 | static 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 | |||
1177 | static struct page *nested_svm_get_page(struct vcpu_svm *svm, u64 gpa) | ||
1178 | { | ||
1179 | struct page *page; | ||
1180 | |||
1181 | down_read(¤t->mm->mmap_sem); | ||
1182 | page = gfn_to_page(svm->vcpu.kvm, gpa >> PAGE_SHIFT); | ||
1183 | up_read(¤t->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 | |||
1195 | static 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 | |||
1152 | static int invalid_op_interception(struct vcpu_svm *svm, | 1237 | static int invalid_op_interception(struct vcpu_svm *svm, |
1153 | struct kvm_run *kvm_run) | 1238 | struct kvm_run *kvm_run) |
1154 | { | 1239 | { |