2 * QEMU Hyper-V Synthetic Debugging device
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
8 #include "qemu/ctype.h"
9 #include "qemu/osdep.h"
10 #include "qemu/error-report.h"
11 #include "qemu/main-loop.h"
12 #include "qemu/sockets.h"
13 #include "qapi/error.h"
14 #include "migration/vmstate.h"
15 #include "hw/qdev-properties.h"
16 #include "hw/loader.h"
18 #include "hw/hyperv/hyperv.h"
19 #include "hw/hyperv/vmbus-bridge.h"
20 #include "hw/hyperv/hyperv-proto.h"
23 #include "net/checksum.h"
26 #define TYPE_HV_SYNDBG "hv-syndbg"
28 typedef struct HvSynDbg
{
29 DeviceState parent_obj
;
36 struct sockaddr_in servaddr
;
38 bool has_data_pending
;
39 uint64_t pending_page_gpa
;
42 #define HVSYNDBG(obj) OBJECT_CHECK(HvSynDbg, (obj), TYPE_HV_SYNDBG)
44 /* returns NULL unless there is exactly one HV Synth debug device */
45 static HvSynDbg
*hv_syndbg_find(void)
47 /* Returns NULL unless there is exactly one hvsd device */
48 return HVSYNDBG(object_resolve_path_type("", TYPE_HV_SYNDBG
, NULL
));
51 static void set_pending_state(HvSynDbg
*syndbg
, bool has_pending
)
56 syndbg
->has_data_pending
= has_pending
;
58 if (!syndbg
->pending_page_gpa
) {
63 out_data
= cpu_physical_memory_map(syndbg
->pending_page_gpa
, &out_len
, 1);
65 *(uint8_t *)out_data
= !!has_pending
;
66 cpu_physical_memory_unmap(out_data
, out_len
, 1, out_len
);
70 static bool get_udb_pkt_data(void *p
, uint32_t len
, uint32_t *data_ofs
,
73 uint32_t offset
, curr_len
= len
;
75 if (curr_len
< sizeof(struct eth_header
) ||
76 (be16_to_cpu(PKT_GET_ETH_HDR(p
)->h_proto
) != ETH_P_IP
)) {
79 offset
= sizeof(struct eth_header
);
80 curr_len
-= sizeof(struct eth_header
);
82 if (curr_len
< sizeof(struct ip_header
) ||
83 PKT_GET_IP_HDR(p
)->ip_p
!= IP_PROTO_UDP
) {
86 offset
+= PKT_GET_IP_HDR_LEN(p
);
87 curr_len
-= PKT_GET_IP_HDR_LEN(p
);
89 if (curr_len
< sizeof(struct udp_header
)) {
93 offset
+= sizeof(struct udp_header
);
95 *src_ip
= PKT_GET_IP_HDR(p
)->ip_src
;
99 static uint16_t handle_send_msg(HvSynDbg
*syndbg
, uint64_t ingpa
,
100 uint32_t count
, bool is_raw
,
101 uint32_t *pending_count
)
105 void *debug_data
= NULL
;
106 uint32_t udp_data_ofs
= 0;
107 const void *pkt_data
;
111 debug_data
= cpu_physical_memory_map(ingpa
, &data_len
, 0);
112 if (!debug_data
|| data_len
< count
) {
113 ret
= HV_STATUS_INSUFFICIENT_MEMORY
;
118 !get_udb_pkt_data(debug_data
, count
, &udp_data_ofs
,
119 &syndbg
->target_ip
)) {
120 ret
= HV_STATUS_SUCCESS
;
124 pkt_data
= (const void *)((uintptr_t)debug_data
+ udp_data_ofs
);
125 sent_count
= sendto(syndbg
->socket
, pkt_data
, count
- udp_data_ofs
,
126 MSG_NOSIGNAL
, NULL
, 0);
127 if (sent_count
== -1) {
128 ret
= HV_STATUS_INSUFFICIENT_MEMORY
;
132 *pending_count
= count
- (sent_count
+ udp_data_ofs
);
133 ret
= HV_STATUS_SUCCESS
;
136 cpu_physical_memory_unmap(debug_data
, count
, 0, data_len
);
142 #define UDP_PKT_HEADER_SIZE \
143 (sizeof(struct eth_header) + sizeof(struct ip_header) +\
144 sizeof(struct udp_header))
146 static bool create_udp_pkt(HvSynDbg
*syndbg
, void *pkt
, uint32_t pkt_len
,
147 void *udp_data
, uint32_t udp_data_len
)
149 struct udp_header
*udp_part
;
151 if (pkt_len
< (UDP_PKT_HEADER_SIZE
+ udp_data_len
)) {
156 memset(&PKT_GET_ETH_HDR(pkt
)->h_source
, 0, ETH_ALEN
);
157 memset(&PKT_GET_ETH_HDR(pkt
)->h_dest
, 0, ETH_ALEN
);
158 PKT_GET_ETH_HDR(pkt
)->h_proto
= cpu_to_be16(ETH_P_IP
);
161 PKT_GET_IP_HDR(pkt
)->ip_ver_len
=
162 (4 << 4) | (sizeof(struct ip_header
) >> 2);
163 PKT_GET_IP_HDR(pkt
)->ip_tos
= 0;
164 PKT_GET_IP_HDR(pkt
)->ip_id
= 0;
165 PKT_GET_IP_HDR(pkt
)->ip_off
= 0;
166 PKT_GET_IP_HDR(pkt
)->ip_ttl
= 64; /* IPDEFTTL */
167 PKT_GET_IP_HDR(pkt
)->ip_p
= IP_PROTO_UDP
;
168 PKT_GET_IP_HDR(pkt
)->ip_src
= syndbg
->servaddr
.sin_addr
.s_addr
;
169 PKT_GET_IP_HDR(pkt
)->ip_dst
= syndbg
->target_ip
;
170 PKT_GET_IP_HDR(pkt
)->ip_len
=
171 cpu_to_be16(sizeof(struct ip_header
) + sizeof(struct udp_header
) +
173 eth_fix_ip4_checksum(PKT_GET_IP_HDR(pkt
), PKT_GET_IP_HDR_LEN(pkt
));
175 udp_part
= (struct udp_header
*)((uintptr_t)pkt
+
176 sizeof(struct eth_header
) +
177 PKT_GET_IP_HDR_LEN(pkt
));
178 udp_part
->uh_sport
= syndbg
->servaddr
.sin_port
;
179 udp_part
->uh_dport
= syndbg
->servaddr
.sin_port
;
180 udp_part
->uh_ulen
= cpu_to_be16(sizeof(struct udp_header
) + udp_data_len
);
181 memcpy(udp_part
+ 1, udp_data
, udp_data_len
);
182 net_checksum_calculate(pkt
, UDP_PKT_HEADER_SIZE
+ udp_data_len
, CSUM_ALL
);
186 static uint16_t handle_recv_msg(HvSynDbg
*syndbg
, uint64_t outgpa
,
187 uint32_t count
, bool is_raw
, uint32_t options
,
188 uint64_t timeout
, uint32_t *retrieved_count
)
191 uint8_t data_buf
[TARGET_PAGE_SIZE
- UDP_PKT_HEADER_SIZE
];
194 ssize_t recv_byte_count
;
196 /* TODO: Handle options and timeout */
200 if (!syndbg
->has_data_pending
) {
203 recv_byte_count
= recv(syndbg
->socket
, data_buf
,
204 MIN(sizeof(data_buf
), count
), MSG_WAITALL
);
205 if (recv_byte_count
== -1) {
206 return HV_STATUS_INVALID_PARAMETER
;
210 if (!recv_byte_count
) {
211 *retrieved_count
= 0;
212 return HV_STATUS_NO_DATA
;
215 set_pending_state(syndbg
, false);
217 out_len
= recv_byte_count
;
219 out_len
+= UDP_PKT_HEADER_SIZE
;
221 out_data
= cpu_physical_memory_map(outgpa
, &out_len
, 1);
223 return HV_STATUS_INSUFFICIENT_MEMORY
;
227 !create_udp_pkt(syndbg
, out_data
,
228 recv_byte_count
+ UDP_PKT_HEADER_SIZE
,
229 data_buf
, recv_byte_count
)) {
230 ret
= HV_STATUS_INSUFFICIENT_MEMORY
;
231 goto cleanup_out_data
;
232 } else if (!is_raw
) {
233 memcpy(out_data
, data_buf
, recv_byte_count
);
236 *retrieved_count
= recv_byte_count
;
238 *retrieved_count
+= UDP_PKT_HEADER_SIZE
;
240 ret
= HV_STATUS_SUCCESS
;
243 cpu_physical_memory_unmap(out_data
, out_len
, 1, out_len
);
247 static uint16_t hv_syndbg_handler(void *context
, HvSynDbgMsg
*msg
)
249 HvSynDbg
*syndbg
= context
;
250 uint16_t ret
= HV_STATUS_INVALID_HYPERCALL_CODE
;
253 case HV_SYNDBG_MSG_CONNECTION_INFO
:
254 msg
->u
.connection_info
.host_ip
=
255 ntohl(syndbg
->servaddr
.sin_addr
.s_addr
);
256 msg
->u
.connection_info
.host_port
=
257 ntohs(syndbg
->servaddr
.sin_port
);
258 ret
= HV_STATUS_SUCCESS
;
260 case HV_SYNDBG_MSG_SEND
:
261 ret
= handle_send_msg(syndbg
, msg
->u
.send
.buf_gpa
, msg
->u
.send
.count
,
262 msg
->u
.send
.is_raw
, &msg
->u
.send
.pending_count
);
264 case HV_SYNDBG_MSG_RECV
:
265 ret
= handle_recv_msg(syndbg
, msg
->u
.recv
.buf_gpa
, msg
->u
.recv
.count
,
266 msg
->u
.recv
.is_raw
, msg
->u
.recv
.options
,
268 &msg
->u
.recv
.retrieved_count
);
270 case HV_SYNDBG_MSG_SET_PENDING_PAGE
:
271 syndbg
->pending_page_gpa
= msg
->u
.pending_page
.buf_gpa
;
272 ret
= HV_STATUS_SUCCESS
;
274 case HV_SYNDBG_MSG_QUERY_OPTIONS
:
275 msg
->u
.query_options
.options
= 0;
276 if (syndbg
->use_hcalls
) {
277 msg
->u
.query_options
.options
= HV_X64_SYNDBG_OPTION_USE_HCALLS
;
279 ret
= HV_STATUS_SUCCESS
;
288 static void hv_syndbg_recv_event(void *opaque
)
290 HvSynDbg
*syndbg
= opaque
;
297 FD_SET(syndbg
->socket
, &rfds
);
298 if (select(syndbg
->socket
+ 1, &rfds
, NULL
, NULL
, &tv
) > 0) {
299 set_pending_state(syndbg
, true);
303 static void hv_syndbg_realize(DeviceState
*dev
, Error
**errp
)
305 HvSynDbg
*syndbg
= HVSYNDBG(dev
);
307 if (!hv_syndbg_find()) {
308 error_setg(errp
, "at most one %s device is permitted", TYPE_HV_SYNDBG
);
312 if (!vmbus_bridge_find()) {
313 error_setg(errp
, "%s device requires vmbus-bridge device",
318 /* Parse and host_ip */
319 if (qemu_isdigit(syndbg
->host_ip
[0])) {
320 syndbg
->servaddr
.sin_addr
.s_addr
= inet_addr(syndbg
->host_ip
);
322 struct hostent
*he
= gethostbyname(syndbg
->host_ip
);
324 error_setg(errp
, "%s failed to resolve host name %s",
325 TYPE_HV_SYNDBG
, syndbg
->host_ip
);
328 syndbg
->servaddr
.sin_addr
= *(struct in_addr
*)he
->h_addr
;
331 syndbg
->socket
= socket(AF_INET
, SOCK_DGRAM
, 0);
332 if (syndbg
->socket
< 0) {
333 error_setg(errp
, "%s failed to create socket", TYPE_HV_SYNDBG
);
337 qemu_socket_set_nonblock(syndbg
->socket
);
339 syndbg
->servaddr
.sin_port
= htons(syndbg
->host_port
);
340 syndbg
->servaddr
.sin_family
= AF_INET
;
341 if (connect(syndbg
->socket
, (struct sockaddr
*)&syndbg
->servaddr
,
342 sizeof(syndbg
->servaddr
)) < 0) {
343 closesocket(syndbg
->socket
);
344 error_setg(errp
, "%s failed to connect to socket", TYPE_HV_SYNDBG
);
348 syndbg
->pending_page_gpa
= 0;
349 syndbg
->has_data_pending
= false;
350 hyperv_set_syndbg_handler(hv_syndbg_handler
, syndbg
);
351 qemu_set_fd_handler(syndbg
->socket
, hv_syndbg_recv_event
, NULL
, syndbg
);
354 static void hv_syndbg_unrealize(DeviceState
*dev
)
356 HvSynDbg
*syndbg
= HVSYNDBG(dev
);
358 if (syndbg
->socket
> 0) {
359 qemu_set_fd_handler(syndbg
->socket
, NULL
, NULL
, NULL
);
360 closesocket(syndbg
->socket
);
364 static const VMStateDescription vmstate_hv_syndbg
= {
365 .name
= TYPE_HV_SYNDBG
,
369 static Property hv_syndbg_properties
[] = {
370 DEFINE_PROP_STRING("host_ip", HvSynDbg
, host_ip
),
371 DEFINE_PROP_UINT16("host_port", HvSynDbg
, host_port
, 50000),
372 DEFINE_PROP_BOOL("use_hcalls", HvSynDbg
, use_hcalls
, false),
373 DEFINE_PROP_END_OF_LIST(),
376 static void hv_syndbg_class_init(ObjectClass
*klass
, void *data
)
378 DeviceClass
*dc
= DEVICE_CLASS(klass
);
380 device_class_set_props(dc
, hv_syndbg_properties
);
381 dc
->fw_name
= TYPE_HV_SYNDBG
;
382 dc
->vmsd
= &vmstate_hv_syndbg
;
383 dc
->realize
= hv_syndbg_realize
;
384 dc
->unrealize
= hv_syndbg_unrealize
;
385 dc
->user_creatable
= true;
386 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
389 static const TypeInfo hv_syndbg_type_info
= {
390 .name
= TYPE_HV_SYNDBG
,
391 .parent
= TYPE_DEVICE
,
392 .instance_size
= sizeof(HvSynDbg
),
393 .class_init
= hv_syndbg_class_init
,
396 static void hv_syndbg_register_types(void)
398 type_register_static(&hv_syndbg_type_info
);
401 type_init(hv_syndbg_register_types
)