master
c 206 lines 4.36 KB
Raw
1 /*
2 * QEMU MSHV SynIC support
3 *
4 * Copyright Microsoft, Corp. 2026
5 *
6 * Authors: Magnus Kulke <magnuskulke@microsoft.com>
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "qemu/osdep.h"
12 #include "qemu/memalign.h"
13 #include "qemu/error-report.h"
14
15 #include "system/mshv.h"
16 #include "system/mshv_int.h"
17
18 #include "linux/mshv.h"
19 #include "hw/hyperv/hvgdk_mini.h"
20 #include "cpu.h"
21
22 #include <sys/ioctl.h>
23
24 bool mshv_synic_enabled(const CPUState *cpu)
25 {
26 X86CPU *x86cpu = X86_CPU(cpu);
27
28 return x86cpu->env.msr_hv_synic_control & 1;
29 }
30
31 static int get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state)
32 {
33 int ret;
34
35 ret = ioctl(cpu_fd, MSHV_GET_VP_STATE, state);
36 if (ret < 0) {
37 error_report("failed to get vp state: %s", strerror(errno));
38 return -1;
39 }
40
41 return 0;
42 }
43
44 static int set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state)
45 {
46 int ret;
47
48 ret = ioctl(cpu_fd, MSHV_SET_VP_STATE, state);
49 if (ret < 0) {
50 error_report("failed to set vp state: %s", strerror(errno));
51 return -1;
52 }
53
54 return 0;
55 }
56
57 int mshv_get_synthetic_timers(int cpu_fd, uint8_t *state)
58 {
59 int ret;
60 void *buffer;
61 struct mshv_get_set_vp_state args = {0};
62
63 buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
64 args.buf_ptr = (uint64_t)buffer;
65 args.buf_sz = HV_HYP_PAGE_SIZE;
66 args.type = MSHV_VP_STATE_SYNTHETIC_TIMERS;
67
68 ret = get_vp_state(cpu_fd, &args);
69
70 if (ret < 0) {
71 qemu_vfree(buffer);
72 error_report("failed to get synthetic timers");
73 return -1;
74 }
75
76 memcpy(state, buffer, MSHV_STIMERS_STATE_SIZE);
77 qemu_vfree(buffer);
78
79 return 0;
80 }
81
82 int mshv_set_synthetic_timers(int cpu_fd, const uint8_t *state)
83 {
84 int ret;
85 void *buffer;
86 struct mshv_get_set_vp_state args = {0};
87
88 buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
89 memset(buffer, 0, HV_HYP_PAGE_SIZE);
90 args.buf_ptr = (uint64_t)buffer;
91 args.buf_sz = HV_HYP_PAGE_SIZE;
92 args.type = MSHV_VP_STATE_SYNTHETIC_TIMERS;
93
94 assert(state);
95 memcpy(buffer, state, MSHV_STIMERS_STATE_SIZE);
96
97 ret = set_vp_state(cpu_fd, &args);
98 qemu_vfree(buffer);
99
100 if (ret < 0) {
101 error_report("failed to set synthetic timers");
102 return -1;
103 }
104
105 return 0;
106 }
107
108 int mshv_get_simp(int cpu_fd, uint8_t *page)
109 {
110 int ret;
111 void *buffer;
112 struct mshv_get_set_vp_state args = {0};
113
114 buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
115 args.buf_ptr = (uint64_t)buffer;
116 args.buf_sz = HV_HYP_PAGE_SIZE;
117 args.type = MSHV_VP_STATE_SIMP;
118
119 ret = get_vp_state(cpu_fd, &args);
120
121 if (ret < 0) {
122 qemu_vfree(buffer);
123 error_report("failed to get simp");
124 return -1;
125 }
126
127 memcpy(page, buffer, HV_HYP_PAGE_SIZE);
128 qemu_vfree(buffer);
129
130 return 0;
131 }
132
133 int mshv_set_simp(int cpu_fd, const uint8_t *page)
134 {
135 int ret;
136 void *buffer;
137 struct mshv_get_set_vp_state args = {0};
138
139 buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
140 args.buf_ptr = (uint64_t)buffer;
141 args.buf_sz = HV_HYP_PAGE_SIZE;
142 args.type = MSHV_VP_STATE_SIMP;
143
144 assert(page);
145 memcpy(buffer, page, HV_HYP_PAGE_SIZE);
146
147 ret = set_vp_state(cpu_fd, &args);
148 qemu_vfree(buffer);
149
150 if (ret < 0) {
151 error_report("failed to set simp");
152 return -1;
153 }
154
155 return 0;
156 }
157
158 int mshv_get_siefp(int cpu_fd, uint8_t *page)
159 {
160 int ret;
161 void *buffer;
162 struct mshv_get_set_vp_state args = {0};
163
164 buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
165 args.buf_ptr = (uint64_t)buffer;
166 args.buf_sz = HV_HYP_PAGE_SIZE;
167 args.type = MSHV_VP_STATE_SIEFP,
168
169 ret = get_vp_state(cpu_fd, &args);
170
171 if (ret < 0) {
172 qemu_vfree(buffer);
173 error_report("failed to get siefp");
174 return -1;
175 }
176
177 memcpy(page, buffer, HV_HYP_PAGE_SIZE);
178 qemu_vfree(buffer);
179
180 return 0;
181 }
182
183 int mshv_set_siefp(int cpu_fd, const uint8_t *page)
184 {
185 int ret;
186 void *buffer;
187 struct mshv_get_set_vp_state args = {0};
188
189 buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
190 args.buf_ptr = (uint64_t)buffer;
191 args.buf_sz = HV_HYP_PAGE_SIZE;
192 args.type = MSHV_VP_STATE_SIEFP,
193
194 assert(page);
195 memcpy(buffer, page, HV_HYP_PAGE_SIZE);
196
197 ret = set_vp_state(cpu_fd, &args);
198 qemu_vfree(buffer);
199
200 if (ret < 0) {
201 error_report("failed to set simp");
202 return -1;
203 }
204
205 return 0;
206 }