KVM: add MSR based hypercall API

This adds a special MSR based hypercall API to KVM. This is to be
used by paravirtual kernels and virtual drivers.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Avi Kivity <avi@qumranet.com>

authored by

Ingo Molnar and committed by
Avi Kivity
102d8325 5972e953

+160
+6
drivers/kvm/kvm.h
··· 14 14 15 15 #include "vmx.h" 16 16 #include <linux/kvm.h> 17 + #include <linux/kvm_para.h> 17 18 18 19 #define CR0_PE_MASK (1ULL << 0) 19 20 #define CR0_TS_MASK (1ULL << 3) ··· 238 237 unsigned long cr0; 239 238 unsigned long cr2; 240 239 unsigned long cr3; 240 + gpa_t para_state_gpa; 241 + struct page *para_state_page; 242 + gpa_t hypercall_gpa; 241 243 unsigned long cr4; 242 244 unsigned long cr8; 243 245 u64 pdptrs[4]; /* pae */ ··· 386 382 int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); 387 383 int (*vcpu_setup)(struct kvm_vcpu *vcpu); 388 384 void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); 385 + void (*patch_hypercall)(struct kvm_vcpu *vcpu, 386 + unsigned char *hypercall_addr); 389 387 }; 390 388 391 389 extern struct kvm_stat kvm_stat;
+73
drivers/kvm/kvm_main.c
··· 1204 1204 } 1205 1205 } 1206 1206 1207 + /* 1208 + * Register the para guest with the host: 1209 + */ 1210 + static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa) 1211 + { 1212 + struct kvm_vcpu_para_state *para_state; 1213 + hpa_t para_state_hpa, hypercall_hpa; 1214 + struct page *para_state_page; 1215 + unsigned char *hypercall; 1216 + gpa_t hypercall_gpa; 1217 + 1218 + printk(KERN_DEBUG "kvm: guest trying to enter paravirtual mode\n"); 1219 + printk(KERN_DEBUG ".... para_state_gpa: %08Lx\n", para_state_gpa); 1220 + 1221 + /* 1222 + * Needs to be page aligned: 1223 + */ 1224 + if (para_state_gpa != PAGE_ALIGN(para_state_gpa)) 1225 + goto err_gp; 1226 + 1227 + para_state_hpa = gpa_to_hpa(vcpu, para_state_gpa); 1228 + printk(KERN_DEBUG ".... para_state_hpa: %08Lx\n", para_state_hpa); 1229 + if (is_error_hpa(para_state_hpa)) 1230 + goto err_gp; 1231 + 1232 + para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT); 1233 + para_state = kmap_atomic(para_state_page, KM_USER0); 1234 + 1235 + printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version); 1236 + printk(KERN_DEBUG ".... size: %d\n", para_state->size); 1237 + 1238 + para_state->host_version = KVM_PARA_API_VERSION; 1239 + /* 1240 + * We cannot support guests that try to register themselves 1241 + * with a newer API version than the host supports: 1242 + */ 1243 + if (para_state->guest_version > KVM_PARA_API_VERSION) { 1244 + para_state->ret = -KVM_EINVAL; 1245 + goto err_kunmap_skip; 1246 + } 1247 + 1248 + hypercall_gpa = para_state->hypercall_gpa; 1249 + hypercall_hpa = gpa_to_hpa(vcpu, hypercall_gpa); 1250 + printk(KERN_DEBUG ".... hypercall_hpa: %08Lx\n", hypercall_hpa); 1251 + if (is_error_hpa(hypercall_hpa)) { 1252 + para_state->ret = -KVM_EINVAL; 1253 + goto err_kunmap_skip; 1254 + } 1255 + 1256 + printk(KERN_DEBUG "kvm: para guest successfully registered.\n"); 1257 + vcpu->para_state_page = para_state_page; 1258 + vcpu->para_state_gpa = para_state_gpa; 1259 + vcpu->hypercall_gpa = hypercall_gpa; 1260 + 1261 + hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT), 1262 + KM_USER1) + (hypercall_hpa & ~PAGE_MASK); 1263 + kvm_arch_ops->patch_hypercall(vcpu, hypercall); 1264 + kunmap_atomic(hypercall, KM_USER1); 1265 + 1266 + para_state->ret = 0; 1267 + err_kunmap_skip: 1268 + kunmap_atomic(para_state, KM_USER0); 1269 + return 0; 1270 + err_gp: 1271 + return 1; 1272 + } 1273 + 1207 1274 int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 1208 1275 { 1209 1276 u64 data; ··· 1379 1312 case MSR_IA32_MISC_ENABLE: 1380 1313 vcpu->ia32_misc_enable_msr = data; 1381 1314 break; 1315 + /* 1316 + * This is the 'probe whether the host is KVM' logic: 1317 + */ 1318 + case MSR_KVM_API_MAGIC: 1319 + return vcpu_register_para(vcpu, data); 1320 + 1382 1321 default: 1383 1322 printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr); 1384 1323 return 1;
+13
drivers/kvm/svm.c
··· 1669 1669 return 0; 1670 1670 } 1671 1671 1672 + static void 1673 + svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) 1674 + { 1675 + /* 1676 + * Patch in the VMMCALL instruction: 1677 + */ 1678 + hypercall[0] = 0x0f; 1679 + hypercall[1] = 0x01; 1680 + hypercall[2] = 0xd9; 1681 + hypercall[3] = 0xc3; 1682 + } 1683 + 1672 1684 static struct kvm_arch_ops svm_arch_ops = { 1673 1685 .cpu_has_kvm_support = has_svm, 1674 1686 .disabled_by_bios = is_disabled, ··· 1729 1717 .run = svm_vcpu_run, 1730 1718 .skip_emulated_instruction = skip_emulated_instruction, 1731 1719 .vcpu_setup = svm_vcpu_setup, 1720 + .patch_hypercall = svm_patch_hypercall, 1732 1721 }; 1733 1722 1734 1723 static int __init svm_init(void)
+13
drivers/kvm/vmx.c
··· 1469 1469 return 0; 1470 1470 } 1471 1471 1472 + static void 1473 + vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) 1474 + { 1475 + /* 1476 + * Patch in the VMCALL instruction: 1477 + */ 1478 + hypercall[0] = 0x0f; 1479 + hypercall[1] = 0x01; 1480 + hypercall[2] = 0xc1; 1481 + hypercall[3] = 0xc3; 1482 + } 1483 + 1472 1484 static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1473 1485 { 1474 1486 u64 exit_qualification; ··· 2076 2064 .run = vmx_vcpu_run, 2077 2065 .skip_emulated_instruction = skip_emulated_instruction, 2078 2066 .vcpu_setup = vmx_vcpu_setup, 2067 + .patch_hypercall = vmx_patch_hypercall, 2079 2068 }; 2080 2069 2081 2070 static int __init vmx_init(void)
+55
include/linux/kvm_para.h
··· 1 + #ifndef __LINUX_KVM_PARA_H 2 + #define __LINUX_KVM_PARA_H 3 + 4 + /* 5 + * Guest OS interface for KVM paravirtualization 6 + * 7 + * Note: this interface is totally experimental, and is certain to change 8 + * as we make progress. 9 + */ 10 + 11 + /* 12 + * Per-VCPU descriptor area shared between guest and host. Writable to 13 + * both guest and host. Registered with the host by the guest when 14 + * a guest acknowledges paravirtual mode. 15 + * 16 + * NOTE: all addresses are guest-physical addresses (gpa), to make it 17 + * easier for the hypervisor to map between the various addresses. 18 + */ 19 + struct kvm_vcpu_para_state { 20 + /* 21 + * API version information for compatibility. If there's any support 22 + * mismatch (too old host trying to execute too new guest) then 23 + * the host will deny entry into paravirtual mode. Any other 24 + * combination (new host + old guest and new host + new guest) 25 + * is supposed to work - new host versions will support all old 26 + * guest API versions. 27 + */ 28 + u32 guest_version; 29 + u32 host_version; 30 + u32 size; 31 + u32 ret; 32 + 33 + /* 34 + * The address of the vm exit instruction (VMCALL or VMMCALL), 35 + * which the host will patch according to the CPU model the 36 + * VM runs on: 37 + */ 38 + u64 hypercall_gpa; 39 + 40 + } __attribute__ ((aligned(PAGE_SIZE))); 41 + 42 + #define KVM_PARA_API_VERSION 1 43 + 44 + /* 45 + * This is used for an RDMSR's ECX parameter to probe for a KVM host. 46 + * Hopefully no CPU vendor will use up this number. This is placed well 47 + * out of way of the typical space occupied by CPU vendors' MSR indices, 48 + * and we think (or at least hope) it wont be occupied in the future 49 + * either. 50 + */ 51 + #define MSR_KVM_API_MAGIC 0x87655678 52 + 53 + #define KVM_EINVAL 1 54 + 55 + #endif