qemu/target/i386/hyperv.c
<<
>>
Prefs
   1/*
   2 * QEMU KVM Hyper-V support
   3 *
   4 * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
   5 *
   6 * Authors:
   7 *  Andrey Smetanin <asmetanin@virtuozzo.com>
   8 *
   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.
  11 *
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "qemu/main-loop.h"
  16#include "hyperv.h"
  17#include "hyperv-proto.h"
  18
  19int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
  20{
  21    CPUX86State *env = &cpu->env;
  22
  23    switch (exit->type) {
  24    case KVM_EXIT_HYPERV_SYNIC:
  25        if (!cpu->hyperv_synic) {
  26            return -1;
  27        }
  28
  29        /*
  30         * For now just track changes in SynIC control and msg/evt pages msr's.
  31         * When SynIC messaging/events processing will be added in future
  32         * here we will do messages queues flushing and pages remapping.
  33         */
  34        switch (exit->u.synic.msr) {
  35        case HV_X64_MSR_SCONTROL:
  36            env->msr_hv_synic_control = exit->u.synic.control;
  37            break;
  38        case HV_X64_MSR_SIMP:
  39            env->msr_hv_synic_msg_page = exit->u.synic.msg_page;
  40            break;
  41        case HV_X64_MSR_SIEFP:
  42            env->msr_hv_synic_evt_page = exit->u.synic.evt_page;
  43            break;
  44        default:
  45            return -1;
  46        }
  47        return 0;
  48    case KVM_EXIT_HYPERV_HCALL: {
  49        uint16_t code;
  50
  51        code  = exit->u.hcall.input & 0xffff;
  52        switch (code) {
  53        case HV_POST_MESSAGE:
  54        case HV_SIGNAL_EVENT:
  55        default:
  56            exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
  57            return 0;
  58        }
  59    }
  60    default:
  61        return -1;
  62    }
  63}
  64
  65static void kvm_hv_sint_ack_handler(EventNotifier *notifier)
  66{
  67    HvSintRoute *sint_route = container_of(notifier, HvSintRoute,
  68                                           sint_ack_notifier);
  69    event_notifier_test_and_clear(notifier);
  70    if (sint_route->sint_ack_clb) {
  71        sint_route->sint_ack_clb(sint_route);
  72    }
  73}
  74
  75HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
  76                                      HvSintAckClb sint_ack_clb)
  77{
  78    HvSintRoute *sint_route;
  79    int r, gsi;
  80
  81    sint_route = g_malloc0(sizeof(*sint_route));
  82    r = event_notifier_init(&sint_route->sint_set_notifier, false);
  83    if (r) {
  84        goto err;
  85    }
  86
  87    r = event_notifier_init(&sint_route->sint_ack_notifier, false);
  88    if (r) {
  89        goto err_sint_set_notifier;
  90    }
  91
  92    event_notifier_set_handler(&sint_route->sint_ack_notifier,
  93                               kvm_hv_sint_ack_handler);
  94
  95    gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vcpu_id, sint);
  96    if (gsi < 0) {
  97        goto err_gsi;
  98    }
  99
 100    r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state,
 101                                           &sint_route->sint_set_notifier,
 102                                           &sint_route->sint_ack_notifier, gsi);
 103    if (r) {
 104        goto err_irqfd;
 105    }
 106    sint_route->gsi = gsi;
 107    sint_route->sint_ack_clb = sint_ack_clb;
 108    sint_route->vcpu_id = vcpu_id;
 109    sint_route->sint = sint;
 110
 111    return sint_route;
 112
 113err_irqfd:
 114    kvm_irqchip_release_virq(kvm_state, gsi);
 115err_gsi:
 116    event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
 117    event_notifier_cleanup(&sint_route->sint_ack_notifier);
 118err_sint_set_notifier:
 119    event_notifier_cleanup(&sint_route->sint_set_notifier);
 120err:
 121    g_free(sint_route);
 122
 123    return NULL;
 124}
 125
 126void kvm_hv_sint_route_destroy(HvSintRoute *sint_route)
 127{
 128    kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state,
 129                                          &sint_route->sint_set_notifier,
 130                                          sint_route->gsi);
 131    kvm_irqchip_release_virq(kvm_state, sint_route->gsi);
 132    event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
 133    event_notifier_cleanup(&sint_route->sint_ack_notifier);
 134    event_notifier_cleanup(&sint_route->sint_set_notifier);
 135    g_free(sint_route);
 136}
 137
 138int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route)
 139{
 140    return event_notifier_set(&sint_route->sint_set_notifier);
 141}
 142