cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

virtio-net.c (3676B)


      1/*
      2 * Virtio-net driver for the s390-ccw firmware
      3 *
      4 * Copyright 2017 Thomas Huth, Red Hat Inc.
      5 *
      6 * This code is free software; you can redistribute it and/or modify it
      7 * under the terms of the GNU General Public License as published by the
      8 * Free Software Foundation; either version 2 of the License, or (at your
      9 * option) any later version.
     10 */
     11
     12#include <stdint.h>
     13#include <stdbool.h>
     14#include <stdio.h>
     15#include <stdlib.h>
     16#include <string.h>
     17#include <unistd.h>
     18#include <sys/socket.h>
     19#include <ethernet.h>
     20#include "s390-ccw.h"
     21#include "virtio.h"
     22#include "s390-time.h"
     23#include "helper.h"
     24
     25#ifndef DEBUG_VIRTIO_NET
     26#define DEBUG_VIRTIO_NET 0
     27#endif
     28
     29#define VIRTIO_NET_F_MAC_BIT  (1 << 5)
     30
     31#define VQ_RX 0         /* Receive queue */
     32#define VQ_TX 1         /* Transmit queue */
     33
     34struct VirtioNetHdr {
     35    uint8_t flags;
     36    uint8_t gso_type;
     37    uint16_t hdr_len;
     38    uint16_t gso_size;
     39    uint16_t csum_start;
     40    uint16_t csum_offset;
     41    /*uint16_t num_buffers;*/ /* Only with VIRTIO_NET_F_MRG_RXBUF or VIRTIO1 */
     42};
     43typedef struct VirtioNetHdr VirtioNetHdr;
     44
     45static uint16_t rx_last_idx;  /* Last index in receive queue "used" ring */
     46
     47int virtio_net_init(void *mac_addr)
     48{
     49    VDev *vdev = virtio_get_device();
     50    VRing *rxvq = &vdev->vrings[VQ_RX];
     51    void *buf;
     52    int i;
     53
     54    vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
     55    virtio_setup_ccw(vdev);
     56
     57    IPL_assert(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT,
     58               "virtio-net device does not support the MAC address feature");
     59    memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN);
     60
     61    for (i = 0; i < 64; i++) {
     62        buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr));
     63        IPL_assert(buf != NULL, "Can not allocate memory for receive buffers");
     64        vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr),
     65                       VRING_DESC_F_WRITE);
     66    }
     67    vring_notify(rxvq);
     68
     69    return 0;
     70}
     71
     72int send(int fd, const void *buf, int len, int flags)
     73{
     74    VirtioNetHdr tx_hdr;
     75    VDev *vdev = virtio_get_device();
     76    VRing *txvq = &vdev->vrings[VQ_TX];
     77
     78    /* Set up header - we do not use anything special, so simply clear it */
     79    memset(&tx_hdr, 0, sizeof(tx_hdr));
     80
     81    vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT);
     82    vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN);
     83    while (!vr_poll(txvq)) {
     84        yield();
     85    }
     86    if (drain_irqs(txvq->schid)) {
     87        puts("send: drain irqs failed");
     88        return -1;
     89    }
     90
     91    return len;
     92}
     93
     94int recv(int fd, void *buf, int maxlen, int flags)
     95{
     96    VDev *vdev = virtio_get_device();
     97    VRing *rxvq = &vdev->vrings[VQ_RX];
     98    int len, id;
     99    uint8_t *pkt;
    100
    101    if (rx_last_idx == rxvq->used->idx) {
    102        return 0;
    103    }
    104
    105    len = rxvq->used->ring[rx_last_idx % rxvq->num].len - sizeof(VirtioNetHdr);
    106    if (len > maxlen) {
    107        puts("virtio-net: Receive buffer too small");
    108        len = maxlen;
    109    }
    110    id = rxvq->used->ring[rx_last_idx % rxvq->num].id % rxvq->num;
    111    pkt = (uint8_t *)(rxvq->desc[id].addr + sizeof(VirtioNetHdr));
    112
    113#if DEBUG_VIRTIO_NET   /* Dump packet */
    114    int i;
    115    printf("\nbuf %p: len=%i\n", (void *)rxvq->desc[id].addr, len);
    116    for (i = 0; i < 64; i++) {
    117        printf(" %02x", pkt[i]);
    118        if ((i % 16) == 15) {
    119            printf("\n");
    120        }
    121    }
    122    printf("\n");
    123#endif
    124
    125    /* Copy data to destination buffer */
    126    memcpy(buf, pkt, len);
    127
    128    /* Mark buffer as available to the host again */
    129    rxvq->avail->ring[rxvq->avail->idx % rxvq->num] = id;
    130    rxvq->avail->idx = rxvq->avail->idx + 1;
    131    vring_notify(rxvq);
    132
    133    /* Move index to next entry */
    134    rx_last_idx = rx_last_idx + 1;
    135
    136    return len;
    137}