qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

syndbg.c (11910B)


      1 /*
      2  * QEMU Hyper-V Synthetic Debugging device
      3  *
      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.
      6  */
      7 
      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"
     17 #include "cpu.h"
     18 #include "hw/hyperv/hyperv.h"
     19 #include "hw/hyperv/vmbus-bridge.h"
     20 #include "hw/hyperv/hyperv-proto.h"
     21 #include "net/net.h"
     22 #include "net/eth.h"
     23 #include "net/checksum.h"
     24 #include "trace.h"
     25 
     26 #define TYPE_HV_SYNDBG       "hv-syndbg"
     27 
     28 typedef struct HvSynDbg {
     29     DeviceState parent_obj;
     30 
     31     char *host_ip;
     32     uint16_t host_port;
     33     bool use_hcalls;
     34 
     35     uint32_t target_ip;
     36     struct sockaddr_in servaddr;
     37     int socket;
     38     bool has_data_pending;
     39     uint64_t pending_page_gpa;
     40 } HvSynDbg;
     41 
     42 #define HVSYNDBG(obj) OBJECT_CHECK(HvSynDbg, (obj), TYPE_HV_SYNDBG)
     43 
     44 /* returns NULL unless there is exactly one HV Synth debug device */
     45 static HvSynDbg *hv_syndbg_find(void)
     46 {
     47     /* Returns NULL unless there is exactly one hvsd device */
     48     return HVSYNDBG(object_resolve_path_type("", TYPE_HV_SYNDBG, NULL));
     49 }
     50 
     51 static void set_pending_state(HvSynDbg *syndbg, bool has_pending)
     52 {
     53     hwaddr out_len;
     54     void *out_data;
     55 
     56     syndbg->has_data_pending = has_pending;
     57 
     58     if (!syndbg->pending_page_gpa) {
     59         return;
     60     }
     61 
     62     out_len = 1;
     63     out_data = cpu_physical_memory_map(syndbg->pending_page_gpa, &out_len, 1);
     64     if (out_data) {
     65         *(uint8_t *)out_data = !!has_pending;
     66         cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
     67     }
     68 }
     69 
     70 static bool get_udb_pkt_data(void *p, uint32_t len, uint32_t *data_ofs,
     71                              uint32_t *src_ip)
     72 {
     73     uint32_t offset, curr_len = len;
     74 
     75     if (curr_len < sizeof(struct eth_header) ||
     76         (be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto) != ETH_P_IP)) {
     77         return false;
     78     }
     79     offset = sizeof(struct eth_header);
     80     curr_len -= sizeof(struct eth_header);
     81 
     82     if (curr_len < sizeof(struct ip_header) ||
     83         PKT_GET_IP_HDR(p)->ip_p != IP_PROTO_UDP) {
     84         return false;
     85     }
     86     offset += PKT_GET_IP_HDR_LEN(p);
     87     curr_len -= PKT_GET_IP_HDR_LEN(p);
     88 
     89     if (curr_len < sizeof(struct udp_header)) {
     90         return false;
     91     }
     92 
     93     offset += sizeof(struct udp_header);
     94     *data_ofs = offset;
     95     *src_ip = PKT_GET_IP_HDR(p)->ip_src;
     96     return true;
     97 }
     98 
     99 static uint16_t handle_send_msg(HvSynDbg *syndbg, uint64_t ingpa,
    100                                 uint32_t count, bool is_raw,
    101                                 uint32_t *pending_count)
    102 {
    103     uint16_t ret;
    104     hwaddr data_len;
    105     void *debug_data = NULL;
    106     uint32_t udp_data_ofs = 0;
    107     const void *pkt_data;
    108     int sent_count;
    109 
    110     data_len = count;
    111     debug_data = cpu_physical_memory_map(ingpa, &data_len, 0);
    112     if (!debug_data || data_len < count) {
    113         ret = HV_STATUS_INSUFFICIENT_MEMORY;
    114         goto cleanup;
    115     }
    116 
    117     if (is_raw &&
    118         !get_udb_pkt_data(debug_data, count, &udp_data_ofs,
    119                           &syndbg->target_ip)) {
    120         ret = HV_STATUS_SUCCESS;
    121         goto cleanup;
    122     }
    123 
    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;
    129         goto cleanup;
    130     }
    131 
    132     *pending_count = count - (sent_count + udp_data_ofs);
    133     ret = HV_STATUS_SUCCESS;
    134 cleanup:
    135     if (debug_data) {
    136         cpu_physical_memory_unmap(debug_data, count, 0, data_len);
    137     }
    138 
    139     return ret;
    140 }
    141 
    142 #define UDP_PKT_HEADER_SIZE \
    143     (sizeof(struct eth_header) + sizeof(struct ip_header) +\
    144      sizeof(struct udp_header))
    145 
    146 static bool create_udp_pkt(HvSynDbg *syndbg, void *pkt, uint32_t pkt_len,
    147                            void *udp_data, uint32_t udp_data_len)
    148 {
    149     struct udp_header *udp_part;
    150 
    151     if (pkt_len < (UDP_PKT_HEADER_SIZE + udp_data_len)) {
    152         return false;
    153     }
    154 
    155     /* Setup the eth */
    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);
    159 
    160     /* Setup the 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) +
    172                     udp_data_len);
    173     eth_fix_ip4_checksum(PKT_GET_IP_HDR(pkt), PKT_GET_IP_HDR_LEN(pkt));
    174 
    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);
    183     return true;
    184 }
    185 
    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)
    189 {
    190     uint16_t ret;
    191     uint8_t data_buf[TARGET_PAGE_SIZE - UDP_PKT_HEADER_SIZE];
    192     hwaddr out_len;
    193     void *out_data;
    194     ssize_t recv_byte_count;
    195 
    196     /* TODO: Handle options and timeout */
    197     (void)options;
    198     (void)timeout;
    199 
    200     if (!syndbg->has_data_pending) {
    201         recv_byte_count = 0;
    202     } else {
    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;
    207         }
    208     }
    209 
    210     if (!recv_byte_count) {
    211         *retrieved_count = 0;
    212         return HV_STATUS_NO_DATA;
    213     }
    214 
    215     set_pending_state(syndbg, false);
    216 
    217     out_len = recv_byte_count;
    218     if (is_raw) {
    219         out_len += UDP_PKT_HEADER_SIZE;
    220     }
    221     out_data = cpu_physical_memory_map(outgpa, &out_len, 1);
    222     if (!out_data) {
    223         return HV_STATUS_INSUFFICIENT_MEMORY;
    224     }
    225 
    226     if (is_raw &&
    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);
    234     }
    235 
    236     *retrieved_count = recv_byte_count;
    237     if (is_raw) {
    238         *retrieved_count += UDP_PKT_HEADER_SIZE;
    239     }
    240     ret = HV_STATUS_SUCCESS;
    241 
    242 cleanup_out_data:
    243     cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
    244     return ret;
    245 }
    246 
    247 static uint16_t hv_syndbg_handler(void *context, HvSynDbgMsg *msg)
    248 {
    249     HvSynDbg *syndbg = context;
    250     uint16_t ret = HV_STATUS_INVALID_HYPERCALL_CODE;
    251 
    252     switch (msg->type) {
    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;
    259         break;
    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);
    263         break;
    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,
    267                               msg->u.recv.timeout,
    268                               &msg->u.recv.retrieved_count);
    269         break;
    270     case HV_SYNDBG_MSG_SET_PENDING_PAGE:
    271         syndbg->pending_page_gpa = msg->u.pending_page.buf_gpa;
    272         ret = HV_STATUS_SUCCESS;
    273         break;
    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;
    278         }
    279         ret = HV_STATUS_SUCCESS;
    280         break;
    281     default:
    282         break;
    283     }
    284 
    285     return ret;
    286 }
    287 
    288 static void hv_syndbg_recv_event(void *opaque)
    289 {
    290     HvSynDbg *syndbg = opaque;
    291     struct timeval tv;
    292     fd_set rfds;
    293 
    294     tv.tv_sec = 0;
    295     tv.tv_usec = 0;
    296     FD_ZERO(&rfds);
    297     FD_SET(syndbg->socket, &rfds);
    298     if (select(syndbg->socket + 1, &rfds, NULL, NULL, &tv) > 0) {
    299         set_pending_state(syndbg, true);
    300     }
    301 }
    302 
    303 static void hv_syndbg_realize(DeviceState *dev, Error **errp)
    304 {
    305     HvSynDbg *syndbg = HVSYNDBG(dev);
    306 
    307     if (!hv_syndbg_find()) {
    308         error_setg(errp, "at most one %s device is permitted", TYPE_HV_SYNDBG);
    309         return;
    310     }
    311 
    312     if (!vmbus_bridge_find()) {
    313         error_setg(errp, "%s device requires vmbus-bridge device",
    314                    TYPE_HV_SYNDBG);
    315         return;
    316     }
    317 
    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);
    321     } else {
    322         struct hostent *he = gethostbyname(syndbg->host_ip);
    323         if (!he) {
    324             error_setg(errp, "%s failed to resolve host name %s",
    325                        TYPE_HV_SYNDBG, syndbg->host_ip);
    326             return;
    327         }
    328         syndbg->servaddr.sin_addr = *(struct in_addr *)he->h_addr;
    329     }
    330 
    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);
    334         return;
    335     }
    336 
    337     qemu_socket_set_nonblock(syndbg->socket);
    338 
    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);
    345         return;
    346     }
    347 
    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);
    352 }
    353 
    354 static void hv_syndbg_unrealize(DeviceState *dev)
    355 {
    356     HvSynDbg *syndbg = HVSYNDBG(dev);
    357 
    358     if (syndbg->socket > 0) {
    359         qemu_set_fd_handler(syndbg->socket, NULL, NULL, NULL);
    360         closesocket(syndbg->socket);
    361     }
    362 }
    363 
    364 static const VMStateDescription vmstate_hv_syndbg = {
    365     .name = TYPE_HV_SYNDBG,
    366     .unmigratable = 1,
    367 };
    368 
    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(),
    374 };
    375 
    376 static void hv_syndbg_class_init(ObjectClass *klass, void *data)
    377 {
    378     DeviceClass *dc = DEVICE_CLASS(klass);
    379 
    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);
    387 }
    388 
    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,
    394 };
    395 
    396 static void hv_syndbg_register_types(void)
    397 {
    398     type_register_static(&hv_syndbg_type_info);
    399 }
    400 
    401 type_init(hv_syndbg_register_types)