aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2010-01-17 08:51:22 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2010-03-01 10:35:57 -0500
commit55cd8e5a4edb8e235163ffe8264b9aaa8d7c050f (patch)
treef7d0091ead058a6c5bc427253b031374b3463b8d /arch/x86/kvm/x86.c
parent1d5103c11e32b5028262c073d56375691d51a886 (diff)
KVM: Implement bare minimum of HYPER-V MSRs
Minimum HYPER-V implementation should have GUEST_OS_ID, HYPERCALL and VP_INDEX MSRs. [avi: fix build on i386] Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Vadim Rozenfeld <vrozenfe@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r--arch/x86/kvm/x86.c193
1 files changed, 192 insertions, 1 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1ad34d185da9..480137db4770 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -622,9 +622,10 @@ static inline u32 bit(int bitno)
622 * kvm-specific. Those are put in the beginning of the list. 622 * kvm-specific. Those are put in the beginning of the list.
623 */ 623 */
624 624
625#define KVM_SAVE_MSRS_BEGIN 2 625#define KVM_SAVE_MSRS_BEGIN 4
626static u32 msrs_to_save[] = { 626static u32 msrs_to_save[] = {
627 MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, 627 MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
628 HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
628 MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, 629 MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
629 MSR_K6_STAR, 630 MSR_K6_STAR,
630#ifdef CONFIG_X86_64 631#ifdef CONFIG_X86_64
@@ -1004,6 +1005,74 @@ out:
1004 return r; 1005 return r;
1005} 1006}
1006 1007
1008static bool kvm_hv_hypercall_enabled(struct kvm *kvm)
1009{
1010 return kvm->arch.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE;
1011}
1012
1013static bool kvm_hv_msr_partition_wide(u32 msr)
1014{
1015 bool r = false;
1016 switch (msr) {
1017 case HV_X64_MSR_GUEST_OS_ID:
1018 case HV_X64_MSR_HYPERCALL:
1019 r = true;
1020 break;
1021 }
1022
1023 return r;
1024}
1025
1026static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data)
1027{
1028 struct kvm *kvm = vcpu->kvm;
1029
1030 switch (msr) {
1031 case HV_X64_MSR_GUEST_OS_ID:
1032 kvm->arch.hv_guest_os_id = data;
1033 /* setting guest os id to zero disables hypercall page */
1034 if (!kvm->arch.hv_guest_os_id)
1035 kvm->arch.hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE;
1036 break;
1037 case HV_X64_MSR_HYPERCALL: {
1038 u64 gfn;
1039 unsigned long addr;
1040 u8 instructions[4];
1041
1042 /* if guest os id is not set hypercall should remain disabled */
1043 if (!kvm->arch.hv_guest_os_id)
1044 break;
1045 if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) {
1046 kvm->arch.hv_hypercall = data;
1047 break;
1048 }
1049 gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT;
1050 addr = gfn_to_hva(kvm, gfn);
1051 if (kvm_is_error_hva(addr))
1052 return 1;
1053 kvm_x86_ops->patch_hypercall(vcpu, instructions);
1054 ((unsigned char *)instructions)[3] = 0xc3; /* ret */
1055 if (copy_to_user((void __user *)addr, instructions, 4))
1056 return 1;
1057 kvm->arch.hv_hypercall = data;
1058 break;
1059 }
1060 default:
1061 pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
1062 "data 0x%llx\n", msr, data);
1063 return 1;
1064 }
1065 return 0;
1066}
1067
1068static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
1069{
1070 pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x data 0x%llx\n",
1071 msr, data);
1072
1073 return 1;
1074}
1075
1007int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) 1076int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
1008{ 1077{
1009 switch (msr) { 1078 switch (msr) {
@@ -1118,6 +1187,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
1118 pr_unimpl(vcpu, "unimplemented perfctr wrmsr: " 1187 pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
1119 "0x%x data 0x%llx\n", msr, data); 1188 "0x%x data 0x%llx\n", msr, data);
1120 break; 1189 break;
1190 case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
1191 if (kvm_hv_msr_partition_wide(msr)) {
1192 int r;
1193 mutex_lock(&vcpu->kvm->lock);
1194 r = set_msr_hyperv_pw(vcpu, msr, data);
1195 mutex_unlock(&vcpu->kvm->lock);
1196 return r;
1197 } else
1198 return set_msr_hyperv(vcpu, msr, data);
1199 break;
1121 default: 1200 default:
1122 if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr)) 1201 if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
1123 return xen_hvm_config(vcpu, data); 1202 return xen_hvm_config(vcpu, data);
@@ -1217,6 +1296,48 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1217 return 0; 1296 return 0;
1218} 1297}
1219 1298
1299static int get_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1300{
1301 u64 data = 0;
1302 struct kvm *kvm = vcpu->kvm;
1303
1304 switch (msr) {
1305 case HV_X64_MSR_GUEST_OS_ID:
1306 data = kvm->arch.hv_guest_os_id;
1307 break;
1308 case HV_X64_MSR_HYPERCALL:
1309 data = kvm->arch.hv_hypercall;
1310 break;
1311 default:
1312 pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
1313 return 1;
1314 }
1315
1316 *pdata = data;
1317 return 0;
1318}
1319
1320static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1321{
1322 u64 data = 0;
1323
1324 switch (msr) {
1325 case HV_X64_MSR_VP_INDEX: {
1326 int r;
1327 struct kvm_vcpu *v;
1328 kvm_for_each_vcpu(r, v, vcpu->kvm)
1329 if (v == vcpu)
1330 data = r;
1331 break;
1332 }
1333 default:
1334 pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
1335 return 1;
1336 }
1337 *pdata = data;
1338 return 0;
1339}
1340
1220int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 1341int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1221{ 1342{
1222 u64 data; 1343 u64 data;
@@ -1283,6 +1404,16 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1283 case MSR_IA32_MCG_STATUS: 1404 case MSR_IA32_MCG_STATUS:
1284 case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1: 1405 case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:
1285 return get_msr_mce(vcpu, msr, pdata); 1406 return get_msr_mce(vcpu, msr, pdata);
1407 case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
1408 if (kvm_hv_msr_partition_wide(msr)) {
1409 int r;
1410 mutex_lock(&vcpu->kvm->lock);
1411 r = get_msr_hyperv_pw(vcpu, msr, pdata);
1412 mutex_unlock(&vcpu->kvm->lock);
1413 return r;
1414 } else
1415 return get_msr_hyperv(vcpu, msr, pdata);
1416 break;
1286 default: 1417 default:
1287 if (!ignore_msrs) { 1418 if (!ignore_msrs) {
1288 pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr); 1419 pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
@@ -1398,6 +1529,7 @@ int kvm_dev_ioctl_check_extension(long ext)
1398 case KVM_CAP_XEN_HVM: 1529 case KVM_CAP_XEN_HVM:
1399 case KVM_CAP_ADJUST_CLOCK: 1530 case KVM_CAP_ADJUST_CLOCK:
1400 case KVM_CAP_VCPU_EVENTS: 1531 case KVM_CAP_VCPU_EVENTS:
1532 case KVM_CAP_HYPERV:
1401 r = 1; 1533 r = 1;
1402 break; 1534 break;
1403 case KVM_CAP_COALESCED_MMIO: 1535 case KVM_CAP_COALESCED_MMIO:
@@ -3618,11 +3750,70 @@ static inline gpa_t hc_gpa(struct kvm_vcpu *vcpu, unsigned long a0,
3618 return a0 | ((gpa_t)a1 << 32); 3750 return a0 | ((gpa_t)a1 << 32);
3619} 3751}
3620 3752
3753int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
3754{
3755 u64 param, ingpa, outgpa, ret;
3756 uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0;
3757 bool fast, longmode;
3758 int cs_db, cs_l;
3759
3760 /*
3761 * hypercall generates UD from non zero cpl and real mode
3762 * per HYPER-V spec
3763 */
3764 if (kvm_x86_ops->get_cpl(vcpu) != 0 ||
3765 !kvm_read_cr0_bits(vcpu, X86_CR0_PE)) {
3766 kvm_queue_exception(vcpu, UD_VECTOR);
3767 return 0;
3768 }
3769
3770 kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
3771 longmode = is_long_mode(vcpu) && cs_l == 1;
3772
3773 if (!longmode) {
3774 param = (kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) |
3775 (kvm_register_read(vcpu, VCPU_REGS_RAX) & 0xffffff);
3776 ingpa = (kvm_register_read(vcpu, VCPU_REGS_RBX) << 32) |
3777 (kvm_register_read(vcpu, VCPU_REGS_RCX) & 0xffffff);
3778 outgpa = (kvm_register_read(vcpu, VCPU_REGS_RDI) << 32) |
3779 (kvm_register_read(vcpu, VCPU_REGS_RSI) & 0xffffff);
3780 }
3781#ifdef CONFIG_X86_64
3782 else {
3783 param = kvm_register_read(vcpu, VCPU_REGS_RCX);
3784 ingpa = kvm_register_read(vcpu, VCPU_REGS_RDX);
3785 outgpa = kvm_register_read(vcpu, VCPU_REGS_R8);
3786 }
3787#endif
3788
3789 code = param & 0xffff;
3790 fast = (param >> 16) & 0x1;
3791 rep_cnt = (param >> 32) & 0xfff;
3792 rep_idx = (param >> 48) & 0xfff;
3793
3794 trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa);
3795
3796 res = HV_STATUS_INVALID_HYPERCALL_CODE;
3797
3798 ret = res | (((u64)rep_done & 0xfff) << 32);
3799 if (longmode) {
3800 kvm_register_write(vcpu, VCPU_REGS_RAX, ret);
3801 } else {
3802 kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32);
3803 kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0xffffffff);
3804 }
3805
3806 return 1;
3807}
3808
3621int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) 3809int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
3622{ 3810{
3623 unsigned long nr, a0, a1, a2, a3, ret; 3811 unsigned long nr, a0, a1, a2, a3, ret;
3624 int r = 1; 3812 int r = 1;
3625 3813
3814 if (kvm_hv_hypercall_enabled(vcpu->kvm))
3815 return kvm_hv_hypercall(vcpu);
3816
3626 nr = kvm_register_read(vcpu, VCPU_REGS_RAX); 3817 nr = kvm_register_read(vcpu, VCPU_REGS_RAX);
3627 a0 = kvm_register_read(vcpu, VCPU_REGS_RBX); 3818 a0 = kvm_register_read(vcpu, VCPU_REGS_RBX);
3628 a1 = kvm_register_read(vcpu, VCPU_REGS_RCX); 3819 a1 = kvm_register_read(vcpu, VCPU_REGS_RCX);