xref: /openbmc/qemu/target/i386/kvm/hyperv.c (revision 73d24074078a2cefb5305047e3bf50b73daa3f98)
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 
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 
26a9dc68d9SClaudio Fontana void hyperv_x86_synic_reset(X86CPU *cpu)
27a9dc68d9SClaudio Fontana {
28a9dc68d9SClaudio Fontana     hyperv_synic_reset(CPU(cpu));
29a9dc68d9SClaudio Fontana }
30a9dc68d9SClaudio Fontana 
31a9dc68d9SClaudio Fontana void hyperv_x86_synic_update(X86CPU *cpu)
32a9dc68d9SClaudio Fontana {
33a9dc68d9SClaudio Fontana     CPUX86State *env = &cpu->env;
34a9dc68d9SClaudio Fontana     bool enable = env->msr_hv_synic_control & HV_SYNIC_ENABLE;
35a9dc68d9SClaudio Fontana     hwaddr msg_page_addr = (env->msr_hv_synic_msg_page & HV_SIMP_ENABLE) ?
36a9dc68d9SClaudio Fontana         (env->msr_hv_synic_msg_page & TARGET_PAGE_MASK) : 0;
37a9dc68d9SClaudio Fontana     hwaddr event_page_addr = (env->msr_hv_synic_evt_page & HV_SIEFP_ENABLE) ?
38a9dc68d9SClaudio Fontana         (env->msr_hv_synic_evt_page & TARGET_PAGE_MASK) : 0;
39a9dc68d9SClaudio Fontana     hyperv_synic_update(CPU(cpu), enable, msg_page_addr, event_page_addr);
40a9dc68d9SClaudio Fontana }
41a9dc68d9SClaudio Fontana 
42a9dc68d9SClaudio Fontana static void async_synic_update(CPUState *cs, run_on_cpu_data data)
43a9dc68d9SClaudio Fontana {
44a9dc68d9SClaudio Fontana     qemu_mutex_lock_iothread();
45a9dc68d9SClaudio Fontana     hyperv_x86_synic_update(X86_CPU(cs));
46a9dc68d9SClaudio Fontana     qemu_mutex_unlock_iothread();
47a9dc68d9SClaudio Fontana }
48a9dc68d9SClaudio Fontana 
49a9dc68d9SClaudio Fontana int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
50a9dc68d9SClaudio Fontana {
51a9dc68d9SClaudio Fontana     CPUX86State *env = &cpu->env;
52a9dc68d9SClaudio Fontana 
53a9dc68d9SClaudio Fontana     switch (exit->type) {
54a9dc68d9SClaudio Fontana     case KVM_EXIT_HYPERV_SYNIC:
55a9dc68d9SClaudio Fontana         if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) {
56a9dc68d9SClaudio Fontana             return -1;
57a9dc68d9SClaudio Fontana         }
58a9dc68d9SClaudio Fontana 
59a9dc68d9SClaudio Fontana         switch (exit->u.synic.msr) {
60a9dc68d9SClaudio Fontana         case HV_X64_MSR_SCONTROL:
61a9dc68d9SClaudio Fontana             env->msr_hv_synic_control = exit->u.synic.control;
62a9dc68d9SClaudio Fontana             break;
63a9dc68d9SClaudio Fontana         case HV_X64_MSR_SIMP:
64a9dc68d9SClaudio Fontana             env->msr_hv_synic_msg_page = exit->u.synic.msg_page;
65a9dc68d9SClaudio Fontana             break;
66a9dc68d9SClaudio Fontana         case HV_X64_MSR_SIEFP:
67a9dc68d9SClaudio Fontana             env->msr_hv_synic_evt_page = exit->u.synic.evt_page;
68a9dc68d9SClaudio Fontana             break;
69a9dc68d9SClaudio Fontana         default:
70a9dc68d9SClaudio Fontana             return -1;
71a9dc68d9SClaudio Fontana         }
72a9dc68d9SClaudio Fontana 
73a9dc68d9SClaudio Fontana         /*
74a9dc68d9SClaudio Fontana          * this will run in this cpu thread before it returns to KVM, but in a
75a9dc68d9SClaudio Fontana          * safe environment (i.e. when all cpus are quiescent) -- this is
76a9dc68d9SClaudio Fontana          * necessary because memory hierarchy is being changed
77a9dc68d9SClaudio Fontana          */
78a9dc68d9SClaudio Fontana         async_safe_run_on_cpu(CPU(cpu), async_synic_update, RUN_ON_CPU_NULL);
79a9dc68d9SClaudio Fontana 
80a9dc68d9SClaudio Fontana         return 0;
81a9dc68d9SClaudio Fontana     case KVM_EXIT_HYPERV_HCALL: {
82a9dc68d9SClaudio Fontana         uint16_t code = exit->u.hcall.input & 0xffff;
83a9dc68d9SClaudio Fontana         bool fast = exit->u.hcall.input & HV_HYPERCALL_FAST;
84*73d24074SJon Doron         uint64_t in_param = exit->u.hcall.params[0];
85*73d24074SJon Doron         uint64_t out_param = exit->u.hcall.params[1];
86a9dc68d9SClaudio Fontana 
87a9dc68d9SClaudio Fontana         switch (code) {
88a9dc68d9SClaudio Fontana         case HV_POST_MESSAGE:
89*73d24074SJon Doron             exit->u.hcall.result = hyperv_hcall_post_message(in_param, fast);
90a9dc68d9SClaudio Fontana             break;
91a9dc68d9SClaudio Fontana         case HV_SIGNAL_EVENT:
92*73d24074SJon Doron             exit->u.hcall.result = hyperv_hcall_signal_event(in_param, fast);
93*73d24074SJon Doron             break;
94*73d24074SJon Doron         case HV_POST_DEBUG_DATA:
95*73d24074SJon Doron             exit->u.hcall.result =
96*73d24074SJon Doron                 hyperv_hcall_post_dbg_data(in_param, out_param, fast);
97*73d24074SJon Doron             break;
98*73d24074SJon Doron         case HV_RETRIEVE_DEBUG_DATA:
99*73d24074SJon Doron             exit->u.hcall.result =
100*73d24074SJon Doron                 hyperv_hcall_retreive_dbg_data(in_param, out_param, fast);
101*73d24074SJon Doron             break;
102*73d24074SJon Doron         case HV_RESET_DEBUG_SESSION:
103*73d24074SJon Doron             exit->u.hcall.result =
104*73d24074SJon Doron                 hyperv_hcall_reset_dbg_session(out_param);
105a9dc68d9SClaudio Fontana             break;
106a9dc68d9SClaudio Fontana         default:
107a9dc68d9SClaudio Fontana             exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
108a9dc68d9SClaudio Fontana         }
109a9dc68d9SClaudio Fontana         return 0;
110a9dc68d9SClaudio Fontana     }
111*73d24074SJon Doron 
112*73d24074SJon Doron     case KVM_EXIT_HYPERV_SYNDBG:
113*73d24074SJon Doron         if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) {
114*73d24074SJon Doron             return -1;
115*73d24074SJon Doron         }
116*73d24074SJon Doron 
117*73d24074SJon Doron         switch (exit->u.syndbg.msr) {
118*73d24074SJon Doron         case HV_X64_MSR_SYNDBG_CONTROL: {
119*73d24074SJon Doron             uint64_t control = exit->u.syndbg.control;
120*73d24074SJon Doron             env->msr_hv_syndbg_control = control;
121*73d24074SJon Doron             env->msr_hv_syndbg_send_page = exit->u.syndbg.send_page;
122*73d24074SJon Doron             env->msr_hv_syndbg_recv_page = exit->u.syndbg.recv_page;
123*73d24074SJon Doron             exit->u.syndbg.status = HV_STATUS_SUCCESS;
124*73d24074SJon Doron             if (control & HV_SYNDBG_CONTROL_SEND) {
125*73d24074SJon Doron                 exit->u.syndbg.status =
126*73d24074SJon Doron                     hyperv_syndbg_send(env->msr_hv_syndbg_send_page,
127*73d24074SJon Doron                             HV_SYNDBG_CONTROL_SEND_SIZE(control));
128*73d24074SJon Doron             } else if (control & HV_SYNDBG_CONTROL_RECV) {
129*73d24074SJon Doron                 exit->u.syndbg.status =
130*73d24074SJon Doron                     hyperv_syndbg_recv(env->msr_hv_syndbg_recv_page,
131*73d24074SJon Doron                             TARGET_PAGE_SIZE);
132*73d24074SJon Doron             }
133*73d24074SJon Doron             break;
134*73d24074SJon Doron         }
135*73d24074SJon Doron         case HV_X64_MSR_SYNDBG_PENDING_BUFFER:
136*73d24074SJon Doron             env->msr_hv_syndbg_pending_page = exit->u.syndbg.pending_page;
137*73d24074SJon Doron             hyperv_syndbg_set_pending_page(env->msr_hv_syndbg_pending_page);
138*73d24074SJon Doron             break;
139*73d24074SJon Doron         default:
140*73d24074SJon Doron             return -1;
141*73d24074SJon Doron         }
142*73d24074SJon Doron 
143*73d24074SJon Doron         return 0;
144a9dc68d9SClaudio Fontana     default:
145a9dc68d9SClaudio Fontana         return -1;
146a9dc68d9SClaudio Fontana     }
147a9dc68d9SClaudio Fontana }
148