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" 15d6da1e9eSPaolo Bonzini #include "qemu/main-loop.h" 1650efe82cSAndrey Smetanin #include "hyperv.h" 175e953812SRoman Kagan #include "hyperv-proto.h" 1850efe82cSAndrey Smetanin 1950efe82cSAndrey Smetanin int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) 2050efe82cSAndrey Smetanin { 2150efe82cSAndrey Smetanin CPUX86State *env = &cpu->env; 2250efe82cSAndrey Smetanin 2350efe82cSAndrey Smetanin switch (exit->type) { 2450efe82cSAndrey Smetanin case KVM_EXIT_HYPERV_SYNIC: 2550efe82cSAndrey Smetanin if (!cpu->hyperv_synic) { 2650efe82cSAndrey Smetanin return -1; 2750efe82cSAndrey Smetanin } 2850efe82cSAndrey Smetanin 2950efe82cSAndrey Smetanin /* 3050efe82cSAndrey Smetanin * For now just track changes in SynIC control and msg/evt pages msr's. 3150efe82cSAndrey Smetanin * When SynIC messaging/events processing will be added in future 3250efe82cSAndrey Smetanin * here we will do messages queues flushing and pages remapping. 3350efe82cSAndrey Smetanin */ 3450efe82cSAndrey Smetanin switch (exit->u.synic.msr) { 3550efe82cSAndrey Smetanin case HV_X64_MSR_SCONTROL: 3650efe82cSAndrey Smetanin env->msr_hv_synic_control = exit->u.synic.control; 3750efe82cSAndrey Smetanin break; 3850efe82cSAndrey Smetanin case HV_X64_MSR_SIMP: 3950efe82cSAndrey Smetanin env->msr_hv_synic_msg_page = exit->u.synic.msg_page; 4050efe82cSAndrey Smetanin break; 4150efe82cSAndrey Smetanin case HV_X64_MSR_SIEFP: 4250efe82cSAndrey Smetanin env->msr_hv_synic_evt_page = exit->u.synic.evt_page; 4350efe82cSAndrey Smetanin break; 4450efe82cSAndrey Smetanin default: 4550efe82cSAndrey Smetanin return -1; 4650efe82cSAndrey Smetanin } 4750efe82cSAndrey Smetanin return 0; 481b0d9b05SAndrey Smetanin case KVM_EXIT_HYPERV_HCALL: { 491b0d9b05SAndrey Smetanin uint16_t code; 501b0d9b05SAndrey Smetanin 511b0d9b05SAndrey Smetanin code = exit->u.hcall.input & 0xffff; 521b0d9b05SAndrey Smetanin switch (code) { 535e953812SRoman Kagan case HV_POST_MESSAGE: 545e953812SRoman Kagan case HV_SIGNAL_EVENT: 551b0d9b05SAndrey Smetanin default: 561b0d9b05SAndrey Smetanin exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE; 571b0d9b05SAndrey Smetanin return 0; 581b0d9b05SAndrey Smetanin } 591b0d9b05SAndrey Smetanin } 6050efe82cSAndrey Smetanin default: 6150efe82cSAndrey Smetanin return -1; 6250efe82cSAndrey Smetanin } 6350efe82cSAndrey Smetanin } 6450efe82cSAndrey Smetanin 6550efe82cSAndrey Smetanin static void kvm_hv_sint_ack_handler(EventNotifier *notifier) 6650efe82cSAndrey Smetanin { 6750efe82cSAndrey Smetanin HvSintRoute *sint_route = container_of(notifier, HvSintRoute, 6850efe82cSAndrey Smetanin sint_ack_notifier); 6950efe82cSAndrey Smetanin event_notifier_test_and_clear(notifier); 7050efe82cSAndrey Smetanin if (sint_route->sint_ack_clb) { 7150efe82cSAndrey Smetanin sint_route->sint_ack_clb(sint_route); 7250efe82cSAndrey Smetanin } 7350efe82cSAndrey Smetanin } 7450efe82cSAndrey Smetanin 7550efe82cSAndrey Smetanin HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint, 7650efe82cSAndrey Smetanin HvSintAckClb sint_ack_clb) 7750efe82cSAndrey Smetanin { 7850efe82cSAndrey Smetanin HvSintRoute *sint_route; 7950efe82cSAndrey Smetanin int r, gsi; 8050efe82cSAndrey Smetanin 8150efe82cSAndrey Smetanin sint_route = g_malloc0(sizeof(*sint_route)); 8250efe82cSAndrey Smetanin r = event_notifier_init(&sint_route->sint_set_notifier, false); 8350efe82cSAndrey Smetanin if (r) { 8450efe82cSAndrey Smetanin goto err; 8550efe82cSAndrey Smetanin } 8650efe82cSAndrey Smetanin 8750efe82cSAndrey Smetanin r = event_notifier_init(&sint_route->sint_ack_notifier, false); 8850efe82cSAndrey Smetanin if (r) { 8950efe82cSAndrey Smetanin goto err_sint_set_notifier; 9050efe82cSAndrey Smetanin } 9150efe82cSAndrey Smetanin 92d6da1e9eSPaolo Bonzini event_notifier_set_handler(&sint_route->sint_ack_notifier, 9350efe82cSAndrey Smetanin kvm_hv_sint_ack_handler); 9450efe82cSAndrey Smetanin 9550efe82cSAndrey Smetanin gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vcpu_id, sint); 9650efe82cSAndrey Smetanin if (gsi < 0) { 9750efe82cSAndrey Smetanin goto err_gsi; 9850efe82cSAndrey Smetanin } 9950efe82cSAndrey Smetanin 10050efe82cSAndrey Smetanin r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, 10150efe82cSAndrey Smetanin &sint_route->sint_set_notifier, 10250efe82cSAndrey Smetanin &sint_route->sint_ack_notifier, gsi); 10350efe82cSAndrey Smetanin if (r) { 10450efe82cSAndrey Smetanin goto err_irqfd; 10550efe82cSAndrey Smetanin } 10650efe82cSAndrey Smetanin sint_route->gsi = gsi; 10750efe82cSAndrey Smetanin sint_route->sint_ack_clb = sint_ack_clb; 10850efe82cSAndrey Smetanin sint_route->vcpu_id = vcpu_id; 10950efe82cSAndrey Smetanin sint_route->sint = sint; 11050efe82cSAndrey Smetanin 11150efe82cSAndrey Smetanin return sint_route; 11250efe82cSAndrey Smetanin 11350efe82cSAndrey Smetanin err_irqfd: 11450efe82cSAndrey Smetanin kvm_irqchip_release_virq(kvm_state, gsi); 11550efe82cSAndrey Smetanin err_gsi: 116d6da1e9eSPaolo Bonzini event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); 11750efe82cSAndrey Smetanin event_notifier_cleanup(&sint_route->sint_ack_notifier); 11850efe82cSAndrey Smetanin err_sint_set_notifier: 11950efe82cSAndrey Smetanin event_notifier_cleanup(&sint_route->sint_set_notifier); 12050efe82cSAndrey Smetanin err: 12150efe82cSAndrey Smetanin g_free(sint_route); 12250efe82cSAndrey Smetanin 12350efe82cSAndrey Smetanin return NULL; 12450efe82cSAndrey Smetanin } 12550efe82cSAndrey Smetanin 12650efe82cSAndrey Smetanin void kvm_hv_sint_route_destroy(HvSintRoute *sint_route) 12750efe82cSAndrey Smetanin { 12850efe82cSAndrey Smetanin kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, 12950efe82cSAndrey Smetanin &sint_route->sint_set_notifier, 13050efe82cSAndrey Smetanin sint_route->gsi); 13150efe82cSAndrey Smetanin kvm_irqchip_release_virq(kvm_state, sint_route->gsi); 132d6da1e9eSPaolo Bonzini event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); 13350efe82cSAndrey Smetanin event_notifier_cleanup(&sint_route->sint_ack_notifier); 13450efe82cSAndrey Smetanin event_notifier_cleanup(&sint_route->sint_set_notifier); 13550efe82cSAndrey Smetanin g_free(sint_route); 13650efe82cSAndrey Smetanin } 13750efe82cSAndrey Smetanin 13850efe82cSAndrey Smetanin int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route) 13950efe82cSAndrey Smetanin { 14050efe82cSAndrey Smetanin return event_notifier_set(&sint_route->sint_set_notifier); 14150efe82cSAndrey Smetanin } 142