xref: /qemu/target/i386/kvm/hyperv.c (revision 6093637b4d32875f98cd59696ffc5f26884aa0b4)
150efe82cSAndrey Smetanin /*
250efe82cSAndrey Smetanin  * QEMU KVM Hyper-V support
350efe82cSAndrey Smetanin  *
450efe82cSAndrey Smetanin  * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
550efe82cSAndrey Smetanin  *
650efe82cSAndrey Smetanin  * Authors:
750efe82cSAndrey Smetanin  *  Andrey Smetanin <asmetanin@virtuozzo.com>
850efe82cSAndrey Smetanin  *
950efe82cSAndrey Smetanin  * This work is licensed under the terms of the GNU GPL, version 2 or later.
1050efe82cSAndrey Smetanin  * See the COPYING file in the top-level directory.
1150efe82cSAndrey Smetanin  *
1250efe82cSAndrey Smetanin  */
1350efe82cSAndrey Smetanin 
14b6a0aa05SPeter Maydell #include "qemu/osdep.h"
15267e071bSRoman Kagan #include "qemu/main-loop.h"
1650efe82cSAndrey Smetanin #include "hyperv.h"
17701189e3SRoman Kagan #include "hw/hyperv/hyperv.h"
185e953812SRoman Kagan #include "hyperv-proto.h"
1950efe82cSAndrey Smetanin 
20606c34bfSRoman Kagan int hyperv_x86_synic_add(X86CPU *cpu)
21606c34bfSRoman Kagan {
22606c34bfSRoman Kagan     hyperv_synic_add(CPU(cpu));
23606c34bfSRoman Kagan     return 0;
24606c34bfSRoman Kagan }
25606c34bfSRoman Kagan 
26ec19444aSMaciej S. Szmigiero /*
27ec19444aSMaciej S. Szmigiero  * All devices possibly using SynIC have to be reset before calling this to let
28ec19444aSMaciej S. Szmigiero  * them remove their SINT routes first.
29ec19444aSMaciej S. Szmigiero  */
30606c34bfSRoman Kagan void hyperv_x86_synic_reset(X86CPU *cpu)
31606c34bfSRoman Kagan {
32606c34bfSRoman Kagan     hyperv_synic_reset(CPU(cpu));
33606c34bfSRoman Kagan }
34606c34bfSRoman Kagan 
35606c34bfSRoman Kagan void hyperv_x86_synic_update(X86CPU *cpu)
36606c34bfSRoman Kagan {
37606c34bfSRoman Kagan     CPUX86State *env = &cpu->env;
38606c34bfSRoman Kagan     bool enable = env->msr_hv_synic_control & HV_SYNIC_ENABLE;
39606c34bfSRoman Kagan     hwaddr msg_page_addr = (env->msr_hv_synic_msg_page & HV_SIMP_ENABLE) ?
40606c34bfSRoman Kagan         (env->msr_hv_synic_msg_page & TARGET_PAGE_MASK) : 0;
41606c34bfSRoman Kagan     hwaddr event_page_addr = (env->msr_hv_synic_evt_page & HV_SIEFP_ENABLE) ?
42606c34bfSRoman Kagan         (env->msr_hv_synic_evt_page & TARGET_PAGE_MASK) : 0;
43606c34bfSRoman Kagan     hyperv_synic_update(CPU(cpu), enable, msg_page_addr, event_page_addr);
44606c34bfSRoman Kagan }
45606c34bfSRoman Kagan 
46267e071bSRoman Kagan static void async_synic_update(CPUState *cs, run_on_cpu_data data)
47267e071bSRoman Kagan {
48195801d7SStefan Hajnoczi     bql_lock();
49267e071bSRoman Kagan     hyperv_x86_synic_update(X86_CPU(cs));
50195801d7SStefan Hajnoczi     bql_unlock();
51267e071bSRoman Kagan }
52267e071bSRoman Kagan 
5350efe82cSAndrey Smetanin int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
5450efe82cSAndrey Smetanin {
5550efe82cSAndrey Smetanin     CPUX86State *env = &cpu->env;
5650efe82cSAndrey Smetanin 
5750efe82cSAndrey Smetanin     switch (exit->type) {
5850efe82cSAndrey Smetanin     case KVM_EXIT_HYPERV_SYNIC:
592d384d7cSVitaly Kuznetsov         if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) {
6050efe82cSAndrey Smetanin             return -1;
6150efe82cSAndrey Smetanin         }
6250efe82cSAndrey Smetanin 
6350efe82cSAndrey Smetanin         switch (exit->u.synic.msr) {
6450efe82cSAndrey Smetanin         case HV_X64_MSR_SCONTROL:
6550efe82cSAndrey Smetanin             env->msr_hv_synic_control = exit->u.synic.control;
6650efe82cSAndrey Smetanin             break;
6750efe82cSAndrey Smetanin         case HV_X64_MSR_SIMP:
6850efe82cSAndrey Smetanin             env->msr_hv_synic_msg_page = exit->u.synic.msg_page;
6950efe82cSAndrey Smetanin             break;
7050efe82cSAndrey Smetanin         case HV_X64_MSR_SIEFP:
7150efe82cSAndrey Smetanin             env->msr_hv_synic_evt_page = exit->u.synic.evt_page;
7250efe82cSAndrey Smetanin             break;
7350efe82cSAndrey Smetanin         default:
7450efe82cSAndrey Smetanin             return -1;
7550efe82cSAndrey Smetanin         }
76606c34bfSRoman Kagan 
77267e071bSRoman Kagan         /*
78267e071bSRoman Kagan          * this will run in this cpu thread before it returns to KVM, but in a
79267e071bSRoman Kagan          * safe environment (i.e. when all cpus are quiescent) -- this is
80267e071bSRoman Kagan          * necessary because memory hierarchy is being changed
81267e071bSRoman Kagan          */
82267e071bSRoman Kagan         async_safe_run_on_cpu(CPU(cpu), async_synic_update, RUN_ON_CPU_NULL);
83606c34bfSRoman Kagan 
8450efe82cSAndrey Smetanin         return 0;
851b0d9b05SAndrey Smetanin     case KVM_EXIT_HYPERV_HCALL: {
86e6ea9f45SRoman Kagan         uint16_t code = exit->u.hcall.input & 0xffff;
87e6ea9f45SRoman Kagan         bool fast = exit->u.hcall.input & HV_HYPERCALL_FAST;
8873d24074SJon Doron         uint64_t in_param = exit->u.hcall.params[0];
8973d24074SJon Doron         uint64_t out_param = exit->u.hcall.params[1];
901b0d9b05SAndrey Smetanin 
911b0d9b05SAndrey Smetanin         switch (code) {
9276036a5fSRoman Kagan         case HV_POST_MESSAGE:
9373d24074SJon Doron             exit->u.hcall.result = hyperv_hcall_post_message(in_param, fast);
9476036a5fSRoman Kagan             break;
955e953812SRoman Kagan         case HV_SIGNAL_EVENT:
9673d24074SJon Doron             exit->u.hcall.result = hyperv_hcall_signal_event(in_param, fast);
9773d24074SJon Doron             break;
9873d24074SJon Doron         case HV_POST_DEBUG_DATA:
9973d24074SJon Doron             exit->u.hcall.result =
10073d24074SJon Doron                 hyperv_hcall_post_dbg_data(in_param, out_param, fast);
10173d24074SJon Doron             break;
10273d24074SJon Doron         case HV_RETRIEVE_DEBUG_DATA:
10373d24074SJon Doron             exit->u.hcall.result =
10473d24074SJon Doron                 hyperv_hcall_retreive_dbg_data(in_param, out_param, fast);
10573d24074SJon Doron             break;
10673d24074SJon Doron         case HV_RESET_DEBUG_SESSION:
10773d24074SJon Doron             exit->u.hcall.result =
10873d24074SJon Doron                 hyperv_hcall_reset_dbg_session(out_param);
109e6ea9f45SRoman Kagan             break;
1101b0d9b05SAndrey Smetanin         default:
1111b0d9b05SAndrey Smetanin             exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
1121b0d9b05SAndrey Smetanin         }
113e6ea9f45SRoman Kagan         return 0;
1141b0d9b05SAndrey Smetanin     }
11573d24074SJon Doron 
11673d24074SJon Doron     case KVM_EXIT_HYPERV_SYNDBG:
11773d24074SJon Doron         if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) {
11873d24074SJon Doron             return -1;
11973d24074SJon Doron         }
12073d24074SJon Doron 
12173d24074SJon Doron         switch (exit->u.syndbg.msr) {
12273d24074SJon Doron         case HV_X64_MSR_SYNDBG_CONTROL: {
12373d24074SJon Doron             uint64_t control = exit->u.syndbg.control;
12473d24074SJon Doron             env->msr_hv_syndbg_control = control;
12573d24074SJon Doron             env->msr_hv_syndbg_send_page = exit->u.syndbg.send_page;
12673d24074SJon Doron             env->msr_hv_syndbg_recv_page = exit->u.syndbg.recv_page;
12773d24074SJon Doron             exit->u.syndbg.status = HV_STATUS_SUCCESS;
12873d24074SJon Doron             if (control & HV_SYNDBG_CONTROL_SEND) {
12973d24074SJon Doron                 exit->u.syndbg.status =
13073d24074SJon Doron                     hyperv_syndbg_send(env->msr_hv_syndbg_send_page,
13173d24074SJon Doron                             HV_SYNDBG_CONTROL_SEND_SIZE(control));
13273d24074SJon Doron             } else if (control & HV_SYNDBG_CONTROL_RECV) {
13373d24074SJon Doron                 exit->u.syndbg.status =
13473d24074SJon Doron                     hyperv_syndbg_recv(env->msr_hv_syndbg_recv_page,
13573d24074SJon Doron                             TARGET_PAGE_SIZE);
13673d24074SJon Doron             }
13773d24074SJon Doron             break;
13873d24074SJon Doron         }
13973d24074SJon Doron         case HV_X64_MSR_SYNDBG_PENDING_BUFFER:
14073d24074SJon Doron             env->msr_hv_syndbg_pending_page = exit->u.syndbg.pending_page;
14173d24074SJon Doron             hyperv_syndbg_set_pending_page(env->msr_hv_syndbg_pending_page);
14273d24074SJon Doron             break;
14373d24074SJon Doron         default:
14473d24074SJon Doron             return -1;
14573d24074SJon Doron         }
14673d24074SJon Doron 
14773d24074SJon Doron         return 0;
14850efe82cSAndrey Smetanin     default:
14950efe82cSAndrey Smetanin         return -1;
15050efe82cSAndrey Smetanin     }
15150efe82cSAndrey Smetanin }
152*6093637bSMaciej S. Szmigiero 
153*6093637bSMaciej S. Szmigiero void hyperv_x86_set_vmbus_recommended_features_enabled(void)
154*6093637bSMaciej S. Szmigiero {
155*6093637bSMaciej S. Szmigiero     hyperv_set_vmbus_recommended_features_enabled();
156*6093637bSMaciej S. Szmigiero }
157