1
2
3
4
5
6
7
8
9
10
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
31
32
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