xref: /qemu/target/i386/kvm/hyperv.c (revision 6093637b)
1a9dc68d9SClaudio Fontana /*
2a9dc68d9SClaudio Fontana  * QEMU KVM Hyper-V support
3a9dc68d9SClaudio Fontana  *
4a9dc68d9SClaudio Fontana  * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
5a9dc68d9SClaudio Fontana  *
6a9dc68d9SClaudio Fontana  * Authors:
7a9dc68d9SClaudio Fontana  *  Andrey Smetanin <asmetanin@virtuozzo.com>
8a9dc68d9SClaudio Fontana  *
9a9dc68d9SClaudio Fontana  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10a9dc68d9SClaudio Fontana  * See the COPYING file in the top-level directory.
11a9dc68d9SClaudio Fontana  *
12a9dc68d9SClaudio Fontana  */
13a9dc68d9SClaudio Fontana 
14a9dc68d9SClaudio Fontana #include "qemu/osdep.h"
15a9dc68d9SClaudio Fontana #include "qemu/main-loop.h"
16a9dc68d9SClaudio Fontana #include "hyperv.h"
17a9dc68d9SClaudio Fontana #include "hw/hyperv/hyperv.h"
18a9dc68d9SClaudio Fontana #include "hyperv-proto.h"
19a9dc68d9SClaudio Fontana 
hyperv_x86_synic_add(X86CPU * cpu)20a9dc68d9SClaudio Fontana int hyperv_x86_synic_add(X86CPU *cpu)
21a9dc68d9SClaudio Fontana {
22a9dc68d9SClaudio Fontana     hyperv_synic_add(CPU(cpu));
23a9dc68d9SClaudio Fontana     return 0;
24a9dc68d9SClaudio Fontana }
25a9dc68d9SClaudio Fontana 
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  */
hyperv_x86_synic_reset(X86CPU * cpu)30a9dc68d9SClaudio Fontana void hyperv_x86_synic_reset(X86CPU *cpu)
31a9dc68d9SClaudio Fontana {
32a9dc68d9SClaudio Fontana     hyperv_synic_reset(CPU(cpu));
33a9dc68d9SClaudio Fontana }
34a9dc68d9SClaudio Fontana 
hyperv_x86_synic_update(X86CPU * cpu)35a9dc68d9SClaudio Fontana void hyperv_x86_synic_update(X86CPU *cpu)
36a9dc68d9SClaudio Fontana {
37a9dc68d9SClaudio Fontana     CPUX86State *env = &cpu->env;
38a9dc68d9SClaudio Fontana     bool enable = env->msr_hv_synic_control & HV_SYNIC_ENABLE;
39a9dc68d9SClaudio Fontana     hwaddr msg_page_addr = (env->msr_hv_synic_msg_page & HV_SIMP_ENABLE) ?
40a9dc68d9SClaudio Fontana         (env->msr_hv_synic_msg_page & TARGET_PAGE_MASK) : 0;
41a9dc68d9SClaudio Fontana     hwaddr event_page_addr = (env->msr_hv_synic_evt_page & HV_SIEFP_ENABLE) ?
42a9dc68d9SClaudio Fontana         (env->msr_hv_synic_evt_page & TARGET_PAGE_MASK) : 0;
43a9dc68d9SClaudio Fontana     hyperv_synic_update(CPU(cpu), enable, msg_page_addr, event_page_addr);
44a9dc68d9SClaudio Fontana }
45a9dc68d9SClaudio Fontana 
async_synic_update(CPUState * cs,run_on_cpu_data data)46a9dc68d9SClaudio Fontana static void async_synic_update(CPUState *cs, run_on_cpu_data data)
47a9dc68d9SClaudio Fontana {
48195801d7SStefan Hajnoczi     bql_lock();
49a9dc68d9SClaudio Fontana     hyperv_x86_synic_update(X86_CPU(cs));
50195801d7SStefan Hajnoczi     bql_unlock();
51a9dc68d9SClaudio Fontana }
52a9dc68d9SClaudio Fontana 
kvm_hv_handle_exit(X86CPU * cpu,struct kvm_hyperv_exit * exit)53a9dc68d9SClaudio Fontana int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
54a9dc68d9SClaudio Fontana {
55a9dc68d9SClaudio Fontana     CPUX86State *env = &cpu->env;
56a9dc68d9SClaudio Fontana 
57a9dc68d9SClaudio Fontana     switch (exit->type) {
58a9dc68d9SClaudio Fontana     case KVM_EXIT_HYPERV_SYNIC:
59a9dc68d9SClaudio Fontana         if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) {
60a9dc68d9SClaudio Fontana             return -1;
61a9dc68d9SClaudio Fontana         }
62a9dc68d9SClaudio Fontana 
63a9dc68d9SClaudio Fontana         switch (exit->u.synic.msr) {
64a9dc68d9SClaudio Fontana         case HV_X64_MSR_SCONTROL:
65a9dc68d9SClaudio Fontana             env->msr_hv_synic_control = exit->u.synic.control;
66a9dc68d9SClaudio Fontana             break;
67a9dc68d9SClaudio Fontana         case HV_X64_MSR_SIMP:
68a9dc68d9SClaudio Fontana             env->msr_hv_synic_msg_page = exit->u.synic.msg_page;
69a9dc68d9SClaudio Fontana             break;
70a9dc68d9SClaudio Fontana         case HV_X64_MSR_SIEFP:
71a9dc68d9SClaudio Fontana             env->msr_hv_synic_evt_page = exit->u.synic.evt_page;
72a9dc68d9SClaudio Fontana             break;
73a9dc68d9SClaudio Fontana         default:
74a9dc68d9SClaudio Fontana             return -1;
75a9dc68d9SClaudio Fontana         }
76a9dc68d9SClaudio Fontana 
77a9dc68d9SClaudio Fontana         /*
78a9dc68d9SClaudio Fontana          * this will run in this cpu thread before it returns to KVM, but in a
79a9dc68d9SClaudio Fontana          * safe environment (i.e. when all cpus are quiescent) -- this is
80a9dc68d9SClaudio Fontana          * necessary because memory hierarchy is being changed
81a9dc68d9SClaudio Fontana          */
82a9dc68d9SClaudio Fontana         async_safe_run_on_cpu(CPU(cpu), async_synic_update, RUN_ON_CPU_NULL);
83a9dc68d9SClaudio Fontana 
84a9dc68d9SClaudio Fontana         return 0;
85a9dc68d9SClaudio Fontana     case KVM_EXIT_HYPERV_HCALL: {
86a9dc68d9SClaudio Fontana         uint16_t code = exit->u.hcall.input & 0xffff;
87a9dc68d9SClaudio Fontana         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];
90a9dc68d9SClaudio Fontana 
91a9dc68d9SClaudio Fontana         switch (code) {
92a9dc68d9SClaudio Fontana         case HV_POST_MESSAGE:
9373d24074SJon Doron             exit->u.hcall.result = hyperv_hcall_post_message(in_param, fast);
94a9dc68d9SClaudio Fontana             break;
95a9dc68d9SClaudio Fontana         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);
109a9dc68d9SClaudio Fontana             break;
110a9dc68d9SClaudio Fontana         default:
111a9dc68d9SClaudio Fontana             exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
112a9dc68d9SClaudio Fontana         }
113a9dc68d9SClaudio Fontana         return 0;
114a9dc68d9SClaudio Fontana     }
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;
148a9dc68d9SClaudio Fontana     default:
149a9dc68d9SClaudio Fontana         return -1;
150a9dc68d9SClaudio Fontana     }
151a9dc68d9SClaudio Fontana }
152*6093637bSMaciej S. Szmigiero 
hyperv_x86_set_vmbus_recommended_features_enabled(void)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