2 * QEMU KVM Hyper-V support
4 * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
7 * Andrey Smetanin <asmetanin@virtuozzo.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "qemu/main-loop.h"
17 #include "hw/hyperv/hyperv.h"
18 #include "hyperv-proto.h"
20 int hyperv_x86_synic_add(X86CPU
*cpu
)
22 hyperv_synic_add(CPU(cpu
));
27 * All devices possibly using SynIC have to be reset before calling this to let
28 * them remove their SINT routes first.
30 void hyperv_x86_synic_reset(X86CPU
*cpu
)
32 hyperv_synic_reset(CPU(cpu
));
35 void hyperv_x86_synic_update(X86CPU
*cpu
)
37 CPUX86State
*env
= &cpu
->env
;
38 bool enable
= env
->msr_hv_synic_control
& HV_SYNIC_ENABLE
;
39 hwaddr msg_page_addr
= (env
->msr_hv_synic_msg_page
& HV_SIMP_ENABLE
) ?
40 (env
->msr_hv_synic_msg_page
& TARGET_PAGE_MASK
) : 0;
41 hwaddr event_page_addr
= (env
->msr_hv_synic_evt_page
& HV_SIEFP_ENABLE
) ?
42 (env
->msr_hv_synic_evt_page
& TARGET_PAGE_MASK
) : 0;
43 hyperv_synic_update(CPU(cpu
), enable
, msg_page_addr
, event_page_addr
);
46 static void async_synic_update(CPUState
*cs
, run_on_cpu_data data
)
48 qemu_mutex_lock_iothread();
49 hyperv_x86_synic_update(X86_CPU(cs
));
50 qemu_mutex_unlock_iothread();
53 int kvm_hv_handle_exit(X86CPU
*cpu
, struct kvm_hyperv_exit
*exit
)
55 CPUX86State
*env
= &cpu
->env
;
58 case KVM_EXIT_HYPERV_SYNIC
:
59 if (!hyperv_feat_enabled(cpu
, HYPERV_FEAT_SYNIC
)) {
63 switch (exit
->u
.synic
.msr
) {
64 case HV_X64_MSR_SCONTROL
:
65 env
->msr_hv_synic_control
= exit
->u
.synic
.control
;
68 env
->msr_hv_synic_msg_page
= exit
->u
.synic
.msg_page
;
70 case HV_X64_MSR_SIEFP
:
71 env
->msr_hv_synic_evt_page
= exit
->u
.synic
.evt_page
;
78 * this will run in this cpu thread before it returns to KVM, but in a
79 * safe environment (i.e. when all cpus are quiescent) -- this is
80 * necessary because memory hierarchy is being changed
82 async_safe_run_on_cpu(CPU(cpu
), async_synic_update
, RUN_ON_CPU_NULL
);
85 case KVM_EXIT_HYPERV_HCALL
: {
86 uint16_t code
= exit
->u
.hcall
.input
& 0xffff;
87 bool fast
= exit
->u
.hcall
.input
& HV_HYPERCALL_FAST
;
88 uint64_t in_param
= exit
->u
.hcall
.params
[0];
89 uint64_t out_param
= exit
->u
.hcall
.params
[1];
93 exit
->u
.hcall
.result
= hyperv_hcall_post_message(in_param
, fast
);
96 exit
->u
.hcall
.result
= hyperv_hcall_signal_event(in_param
, fast
);
98 case HV_POST_DEBUG_DATA
:
99 exit
->u
.hcall
.result
=
100 hyperv_hcall_post_dbg_data(in_param
, out_param
, fast
);
102 case HV_RETRIEVE_DEBUG_DATA
:
103 exit
->u
.hcall
.result
=
104 hyperv_hcall_retreive_dbg_data(in_param
, out_param
, fast
);
106 case HV_RESET_DEBUG_SESSION
:
107 exit
->u
.hcall
.result
=
108 hyperv_hcall_reset_dbg_session(out_param
);
111 exit
->u
.hcall
.result
= HV_STATUS_INVALID_HYPERCALL_CODE
;
116 case KVM_EXIT_HYPERV_SYNDBG
:
117 if (!hyperv_feat_enabled(cpu
, HYPERV_FEAT_SYNDBG
)) {
121 switch (exit
->u
.syndbg
.msr
) {
122 case HV_X64_MSR_SYNDBG_CONTROL
: {
123 uint64_t control
= exit
->u
.syndbg
.control
;
124 env
->msr_hv_syndbg_control
= control
;
125 env
->msr_hv_syndbg_send_page
= exit
->u
.syndbg
.send_page
;
126 env
->msr_hv_syndbg_recv_page
= exit
->u
.syndbg
.recv_page
;
127 exit
->u
.syndbg
.status
= HV_STATUS_SUCCESS
;
128 if (control
& HV_SYNDBG_CONTROL_SEND
) {
129 exit
->u
.syndbg
.status
=
130 hyperv_syndbg_send(env
->msr_hv_syndbg_send_page
,
131 HV_SYNDBG_CONTROL_SEND_SIZE(control
));
132 } else if (control
& HV_SYNDBG_CONTROL_RECV
) {
133 exit
->u
.syndbg
.status
=
134 hyperv_syndbg_recv(env
->msr_hv_syndbg_recv_page
,
139 case HV_X64_MSR_SYNDBG_PENDING_BUFFER
:
140 env
->msr_hv_syndbg_pending_page
= exit
->u
.syndbg
.pending_page
;
141 hyperv_syndbg_set_pending_page(env
->msr_hv_syndbg_pending_page
);