1*a9dc68d9SClaudio Fontana /* 2*a9dc68d9SClaudio Fontana * QEMU KVM Hyper-V support 3*a9dc68d9SClaudio Fontana * 4*a9dc68d9SClaudio Fontana * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com> 5*a9dc68d9SClaudio Fontana * 6*a9dc68d9SClaudio Fontana * Authors: 7*a9dc68d9SClaudio Fontana * Andrey Smetanin <asmetanin@virtuozzo.com> 8*a9dc68d9SClaudio Fontana * 9*a9dc68d9SClaudio Fontana * This work is licensed under the terms of the GNU GPL, version 2 or later. 10*a9dc68d9SClaudio Fontana * See the COPYING file in the top-level directory. 11*a9dc68d9SClaudio Fontana * 12*a9dc68d9SClaudio Fontana */ 13*a9dc68d9SClaudio Fontana 14*a9dc68d9SClaudio Fontana #include "qemu/osdep.h" 15*a9dc68d9SClaudio Fontana #include "qemu/main-loop.h" 16*a9dc68d9SClaudio Fontana #include "hyperv.h" 17*a9dc68d9SClaudio Fontana #include "hw/hyperv/hyperv.h" 18*a9dc68d9SClaudio Fontana #include "hyperv-proto.h" 19*a9dc68d9SClaudio Fontana 20*a9dc68d9SClaudio Fontana int hyperv_x86_synic_add(X86CPU *cpu) 21*a9dc68d9SClaudio Fontana { 22*a9dc68d9SClaudio Fontana hyperv_synic_add(CPU(cpu)); 23*a9dc68d9SClaudio Fontana return 0; 24*a9dc68d9SClaudio Fontana } 25*a9dc68d9SClaudio Fontana 26*a9dc68d9SClaudio Fontana void hyperv_x86_synic_reset(X86CPU *cpu) 27*a9dc68d9SClaudio Fontana { 28*a9dc68d9SClaudio Fontana hyperv_synic_reset(CPU(cpu)); 29*a9dc68d9SClaudio Fontana } 30*a9dc68d9SClaudio Fontana 31*a9dc68d9SClaudio Fontana void hyperv_x86_synic_update(X86CPU *cpu) 32*a9dc68d9SClaudio Fontana { 33*a9dc68d9SClaudio Fontana CPUX86State *env = &cpu->env; 34*a9dc68d9SClaudio Fontana bool enable = env->msr_hv_synic_control & HV_SYNIC_ENABLE; 35*a9dc68d9SClaudio Fontana hwaddr msg_page_addr = (env->msr_hv_synic_msg_page & HV_SIMP_ENABLE) ? 36*a9dc68d9SClaudio Fontana (env->msr_hv_synic_msg_page & TARGET_PAGE_MASK) : 0; 37*a9dc68d9SClaudio Fontana hwaddr event_page_addr = (env->msr_hv_synic_evt_page & HV_SIEFP_ENABLE) ? 38*a9dc68d9SClaudio Fontana (env->msr_hv_synic_evt_page & TARGET_PAGE_MASK) : 0; 39*a9dc68d9SClaudio Fontana hyperv_synic_update(CPU(cpu), enable, msg_page_addr, event_page_addr); 40*a9dc68d9SClaudio Fontana } 41*a9dc68d9SClaudio Fontana 42*a9dc68d9SClaudio Fontana static void async_synic_update(CPUState *cs, run_on_cpu_data data) 43*a9dc68d9SClaudio Fontana { 44*a9dc68d9SClaudio Fontana qemu_mutex_lock_iothread(); 45*a9dc68d9SClaudio Fontana hyperv_x86_synic_update(X86_CPU(cs)); 46*a9dc68d9SClaudio Fontana qemu_mutex_unlock_iothread(); 47*a9dc68d9SClaudio Fontana } 48*a9dc68d9SClaudio Fontana 49*a9dc68d9SClaudio Fontana int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) 50*a9dc68d9SClaudio Fontana { 51*a9dc68d9SClaudio Fontana CPUX86State *env = &cpu->env; 52*a9dc68d9SClaudio Fontana 53*a9dc68d9SClaudio Fontana switch (exit->type) { 54*a9dc68d9SClaudio Fontana case KVM_EXIT_HYPERV_SYNIC: 55*a9dc68d9SClaudio Fontana if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) { 56*a9dc68d9SClaudio Fontana return -1; 57*a9dc68d9SClaudio Fontana } 58*a9dc68d9SClaudio Fontana 59*a9dc68d9SClaudio Fontana switch (exit->u.synic.msr) { 60*a9dc68d9SClaudio Fontana case HV_X64_MSR_SCONTROL: 61*a9dc68d9SClaudio Fontana env->msr_hv_synic_control = exit->u.synic.control; 62*a9dc68d9SClaudio Fontana break; 63*a9dc68d9SClaudio Fontana case HV_X64_MSR_SIMP: 64*a9dc68d9SClaudio Fontana env->msr_hv_synic_msg_page = exit->u.synic.msg_page; 65*a9dc68d9SClaudio Fontana break; 66*a9dc68d9SClaudio Fontana case HV_X64_MSR_SIEFP: 67*a9dc68d9SClaudio Fontana env->msr_hv_synic_evt_page = exit->u.synic.evt_page; 68*a9dc68d9SClaudio Fontana break; 69*a9dc68d9SClaudio Fontana default: 70*a9dc68d9SClaudio Fontana return -1; 71*a9dc68d9SClaudio Fontana } 72*a9dc68d9SClaudio Fontana 73*a9dc68d9SClaudio Fontana /* 74*a9dc68d9SClaudio Fontana * this will run in this cpu thread before it returns to KVM, but in a 75*a9dc68d9SClaudio Fontana * safe environment (i.e. when all cpus are quiescent) -- this is 76*a9dc68d9SClaudio Fontana * necessary because memory hierarchy is being changed 77*a9dc68d9SClaudio Fontana */ 78*a9dc68d9SClaudio Fontana async_safe_run_on_cpu(CPU(cpu), async_synic_update, RUN_ON_CPU_NULL); 79*a9dc68d9SClaudio Fontana 80*a9dc68d9SClaudio Fontana return 0; 81*a9dc68d9SClaudio Fontana case KVM_EXIT_HYPERV_HCALL: { 82*a9dc68d9SClaudio Fontana uint16_t code = exit->u.hcall.input & 0xffff; 83*a9dc68d9SClaudio Fontana bool fast = exit->u.hcall.input & HV_HYPERCALL_FAST; 84*a9dc68d9SClaudio Fontana uint64_t param = exit->u.hcall.params[0]; 85*a9dc68d9SClaudio Fontana 86*a9dc68d9SClaudio Fontana switch (code) { 87*a9dc68d9SClaudio Fontana case HV_POST_MESSAGE: 88*a9dc68d9SClaudio Fontana exit->u.hcall.result = hyperv_hcall_post_message(param, fast); 89*a9dc68d9SClaudio Fontana break; 90*a9dc68d9SClaudio Fontana case HV_SIGNAL_EVENT: 91*a9dc68d9SClaudio Fontana exit->u.hcall.result = hyperv_hcall_signal_event(param, fast); 92*a9dc68d9SClaudio Fontana break; 93*a9dc68d9SClaudio Fontana default: 94*a9dc68d9SClaudio Fontana exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE; 95*a9dc68d9SClaudio Fontana } 96*a9dc68d9SClaudio Fontana return 0; 97*a9dc68d9SClaudio Fontana } 98*a9dc68d9SClaudio Fontana default: 99*a9dc68d9SClaudio Fontana return -1; 100*a9dc68d9SClaudio Fontana } 101*a9dc68d9SClaudio Fontana } 102