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"
16*9c2ff9cdSPierrick Bouvier #include "exec/target_page.h"
1750efe82cSAndrey Smetanin #include "hyperv.h"
18701189e3SRoman Kagan #include "hw/hyperv/hyperv.h"
195e953812SRoman Kagan #include "hyperv-proto.h"
2050efe82cSAndrey Smetanin
hyperv_x86_synic_add(X86CPU * cpu)21606c34bfSRoman Kagan int hyperv_x86_synic_add(X86CPU *cpu)
22606c34bfSRoman Kagan {
23606c34bfSRoman Kagan hyperv_synic_add(CPU(cpu));
24606c34bfSRoman Kagan return 0;
25606c34bfSRoman Kagan }
26606c34bfSRoman Kagan
27ec19444aSMaciej S. Szmigiero /*
28ec19444aSMaciej S. Szmigiero * All devices possibly using SynIC have to be reset before calling this to let
29ec19444aSMaciej S. Szmigiero * them remove their SINT routes first.
30ec19444aSMaciej S. Szmigiero */
hyperv_x86_synic_reset(X86CPU * cpu)31606c34bfSRoman Kagan void hyperv_x86_synic_reset(X86CPU *cpu)
32606c34bfSRoman Kagan {
33606c34bfSRoman Kagan hyperv_synic_reset(CPU(cpu));
34606c34bfSRoman Kagan }
35606c34bfSRoman Kagan
hyperv_x86_synic_update(X86CPU * cpu)36606c34bfSRoman Kagan void hyperv_x86_synic_update(X86CPU *cpu)
37606c34bfSRoman Kagan {
38606c34bfSRoman Kagan CPUX86State *env = &cpu->env;
39606c34bfSRoman Kagan bool enable = env->msr_hv_synic_control & HV_SYNIC_ENABLE;
40606c34bfSRoman Kagan hwaddr msg_page_addr = (env->msr_hv_synic_msg_page & HV_SIMP_ENABLE) ?
41606c34bfSRoman Kagan (env->msr_hv_synic_msg_page & TARGET_PAGE_MASK) : 0;
42606c34bfSRoman Kagan hwaddr event_page_addr = (env->msr_hv_synic_evt_page & HV_SIEFP_ENABLE) ?
43606c34bfSRoman Kagan (env->msr_hv_synic_evt_page & TARGET_PAGE_MASK) : 0;
44606c34bfSRoman Kagan hyperv_synic_update(CPU(cpu), enable, msg_page_addr, event_page_addr);
45606c34bfSRoman Kagan }
46606c34bfSRoman Kagan
async_synic_update(CPUState * cs,run_on_cpu_data data)47267e071bSRoman Kagan static void async_synic_update(CPUState *cs, run_on_cpu_data data)
48267e071bSRoman Kagan {
49195801d7SStefan Hajnoczi bql_lock();
50267e071bSRoman Kagan hyperv_x86_synic_update(X86_CPU(cs));
51195801d7SStefan Hajnoczi bql_unlock();
52267e071bSRoman Kagan }
53267e071bSRoman Kagan
kvm_hv_handle_exit(X86CPU * cpu,struct kvm_hyperv_exit * exit)5450efe82cSAndrey Smetanin int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
5550efe82cSAndrey Smetanin {
5650efe82cSAndrey Smetanin CPUX86State *env = &cpu->env;
5750efe82cSAndrey Smetanin
5850efe82cSAndrey Smetanin switch (exit->type) {
5950efe82cSAndrey Smetanin case KVM_EXIT_HYPERV_SYNIC:
602d384d7cSVitaly Kuznetsov if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) {
6150efe82cSAndrey Smetanin return -1;
6250efe82cSAndrey Smetanin }
6350efe82cSAndrey Smetanin
6450efe82cSAndrey Smetanin switch (exit->u.synic.msr) {
6550efe82cSAndrey Smetanin case HV_X64_MSR_SCONTROL:
6650efe82cSAndrey Smetanin env->msr_hv_synic_control = exit->u.synic.control;
6750efe82cSAndrey Smetanin break;
6850efe82cSAndrey Smetanin case HV_X64_MSR_SIMP:
6950efe82cSAndrey Smetanin env->msr_hv_synic_msg_page = exit->u.synic.msg_page;
7050efe82cSAndrey Smetanin break;
7150efe82cSAndrey Smetanin case HV_X64_MSR_SIEFP:
7250efe82cSAndrey Smetanin env->msr_hv_synic_evt_page = exit->u.synic.evt_page;
7350efe82cSAndrey Smetanin break;
7450efe82cSAndrey Smetanin default:
7550efe82cSAndrey Smetanin return -1;
7650efe82cSAndrey Smetanin }
77606c34bfSRoman Kagan
78267e071bSRoman Kagan /*
79267e071bSRoman Kagan * this will run in this cpu thread before it returns to KVM, but in a
80267e071bSRoman Kagan * safe environment (i.e. when all cpus are quiescent) -- this is
81267e071bSRoman Kagan * necessary because memory hierarchy is being changed
82267e071bSRoman Kagan */
83267e071bSRoman Kagan async_safe_run_on_cpu(CPU(cpu), async_synic_update, RUN_ON_CPU_NULL);
84d3177e2eSVitaly Kuznetsov cpu_exit(CPU(cpu));
85606c34bfSRoman Kagan
8684d4b728Sdonsheng return EXCP_INTERRUPT;
871b0d9b05SAndrey Smetanin case KVM_EXIT_HYPERV_HCALL: {
88e6ea9f45SRoman Kagan uint16_t code = exit->u.hcall.input & 0xffff;
89e6ea9f45SRoman Kagan bool fast = exit->u.hcall.input & HV_HYPERCALL_FAST;
9073d24074SJon Doron uint64_t in_param = exit->u.hcall.params[0];
9173d24074SJon Doron uint64_t out_param = exit->u.hcall.params[1];
921b0d9b05SAndrey Smetanin
931b0d9b05SAndrey Smetanin switch (code) {
9476036a5fSRoman Kagan case HV_POST_MESSAGE:
9573d24074SJon Doron exit->u.hcall.result = hyperv_hcall_post_message(in_param, fast);
9676036a5fSRoman Kagan break;
975e953812SRoman Kagan case HV_SIGNAL_EVENT:
9873d24074SJon Doron exit->u.hcall.result = hyperv_hcall_signal_event(in_param, fast);
9973d24074SJon Doron break;
10073d24074SJon Doron case HV_POST_DEBUG_DATA:
10173d24074SJon Doron exit->u.hcall.result =
10273d24074SJon Doron hyperv_hcall_post_dbg_data(in_param, out_param, fast);
10373d24074SJon Doron break;
10473d24074SJon Doron case HV_RETRIEVE_DEBUG_DATA:
10573d24074SJon Doron exit->u.hcall.result =
10673d24074SJon Doron hyperv_hcall_retreive_dbg_data(in_param, out_param, fast);
10773d24074SJon Doron break;
10873d24074SJon Doron case HV_RESET_DEBUG_SESSION:
10973d24074SJon Doron exit->u.hcall.result =
11073d24074SJon Doron hyperv_hcall_reset_dbg_session(out_param);
111e6ea9f45SRoman Kagan break;
1121b0d9b05SAndrey Smetanin default:
1131b0d9b05SAndrey Smetanin exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
1141b0d9b05SAndrey Smetanin }
115e6ea9f45SRoman Kagan return 0;
1161b0d9b05SAndrey Smetanin }
11773d24074SJon Doron
11873d24074SJon Doron case KVM_EXIT_HYPERV_SYNDBG:
11973d24074SJon Doron if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) {
12073d24074SJon Doron return -1;
12173d24074SJon Doron }
12273d24074SJon Doron
12373d24074SJon Doron switch (exit->u.syndbg.msr) {
12473d24074SJon Doron case HV_X64_MSR_SYNDBG_CONTROL: {
12573d24074SJon Doron uint64_t control = exit->u.syndbg.control;
12673d24074SJon Doron env->msr_hv_syndbg_control = control;
12773d24074SJon Doron env->msr_hv_syndbg_send_page = exit->u.syndbg.send_page;
12873d24074SJon Doron env->msr_hv_syndbg_recv_page = exit->u.syndbg.recv_page;
12973d24074SJon Doron exit->u.syndbg.status = HV_STATUS_SUCCESS;
13073d24074SJon Doron if (control & HV_SYNDBG_CONTROL_SEND) {
13173d24074SJon Doron exit->u.syndbg.status =
13273d24074SJon Doron hyperv_syndbg_send(env->msr_hv_syndbg_send_page,
13373d24074SJon Doron HV_SYNDBG_CONTROL_SEND_SIZE(control));
13473d24074SJon Doron } else if (control & HV_SYNDBG_CONTROL_RECV) {
13573d24074SJon Doron exit->u.syndbg.status =
13673d24074SJon Doron hyperv_syndbg_recv(env->msr_hv_syndbg_recv_page,
13773d24074SJon Doron TARGET_PAGE_SIZE);
13873d24074SJon Doron }
13973d24074SJon Doron break;
14073d24074SJon Doron }
14173d24074SJon Doron case HV_X64_MSR_SYNDBG_PENDING_BUFFER:
14273d24074SJon Doron env->msr_hv_syndbg_pending_page = exit->u.syndbg.pending_page;
14373d24074SJon Doron hyperv_syndbg_set_pending_page(env->msr_hv_syndbg_pending_page);
14473d24074SJon Doron break;
14573d24074SJon Doron default:
14673d24074SJon Doron return -1;
14773d24074SJon Doron }
14873d24074SJon Doron
14973d24074SJon Doron return 0;
15050efe82cSAndrey Smetanin default:
15150efe82cSAndrey Smetanin return -1;
15250efe82cSAndrey Smetanin }
15350efe82cSAndrey Smetanin }
1546093637bSMaciej S. Szmigiero
hyperv_x86_set_vmbus_recommended_features_enabled(void)1556093637bSMaciej S. Szmigiero void hyperv_x86_set_vmbus_recommended_features_enabled(void)
1566093637bSMaciej S. Szmigiero {
1576093637bSMaciej S. Szmigiero hyperv_set_vmbus_recommended_features_enabled();
1586093637bSMaciej S. Szmigiero }
159