Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180309' into...
[qemu/ar7.git] / target / i386 / hyperv.c
bloba050c9d2d11d63c26947945a14b32b07f3edb536
1 /*
2 * QEMU KVM Hyper-V support
4 * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
6 * Authors:
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"
16 #include "hyperv.h"
17 #include "hyperv-proto.h"
19 int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
21 CPUX86State *env = &cpu->env;
23 switch (exit->type) {
24 case KVM_EXIT_HYPERV_SYNIC:
25 if (!cpu->hyperv_synic) {
26 return -1;
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.
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;
47 return 0;
48 case KVM_EXIT_HYPERV_HCALL: {
49 uint16_t code;
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;
60 default:
61 return -1;
65 static void kvm_hv_sint_ack_handler(EventNotifier *notifier)
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);
75 HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
76 HvSintAckClb sint_ack_clb)
78 HvSintRoute *sint_route;
79 int r, gsi;
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;
87 r = event_notifier_init(&sint_route->sint_ack_notifier, false);
88 if (r) {
89 goto err_sint_set_notifier;
92 event_notifier_set_handler(&sint_route->sint_ack_notifier,
93 kvm_hv_sint_ack_handler);
95 gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vcpu_id, sint);
96 if (gsi < 0) {
97 goto err_gsi;
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;
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;
111 return sint_route;
113 err_irqfd:
114 kvm_irqchip_release_virq(kvm_state, gsi);
115 err_gsi:
116 event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
117 event_notifier_cleanup(&sint_route->sint_ack_notifier);
118 err_sint_set_notifier:
119 event_notifier_cleanup(&sint_route->sint_set_notifier);
120 err:
121 g_free(sint_route);
123 return NULL;
126 void kvm_hv_sint_route_destroy(HvSintRoute *sint_route)
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);
138 int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route)
140 return event_notifier_set(&sint_route->sint_set_notifier);