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

vugbm.c (6463B)


      1/*
      2 * Virtio vhost-user GPU Device
      3 *
      4 * DRM helpers
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7 * See the COPYING file in the top-level directory.
      8 */
      9
     10#include "qemu/osdep.h"
     11#include "vugbm.h"
     12
     13static bool
     14mem_alloc_bo(struct vugbm_buffer *buf)
     15{
     16    buf->mmap = g_malloc(buf->width * buf->height * 4);
     17    buf->stride = buf->width * 4;
     18    return true;
     19}
     20
     21static void
     22mem_free_bo(struct vugbm_buffer *buf)
     23{
     24    g_free(buf->mmap);
     25}
     26
     27static bool
     28mem_map_bo(struct vugbm_buffer *buf)
     29{
     30    return buf->mmap != NULL;
     31}
     32
     33static void
     34mem_unmap_bo(struct vugbm_buffer *buf)
     35{
     36}
     37
     38static void
     39mem_device_destroy(struct vugbm_device *dev)
     40{
     41}
     42
     43#ifdef CONFIG_MEMFD
     44struct udmabuf_create {
     45        uint32_t memfd;
     46        uint32_t flags;
     47        uint64_t offset;
     48        uint64_t size;
     49};
     50
     51#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create)
     52
     53static size_t
     54udmabuf_get_size(struct vugbm_buffer *buf)
     55{
     56    return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size);
     57}
     58
     59static bool
     60udmabuf_alloc_bo(struct vugbm_buffer *buf)
     61{
     62    int ret;
     63
     64    buf->memfd = memfd_create("udmabuf-bo", MFD_ALLOW_SEALING);
     65    if (buf->memfd < 0) {
     66        return false;
     67    }
     68
     69    ret = ftruncate(buf->memfd, udmabuf_get_size(buf));
     70    if (ret < 0) {
     71        close(buf->memfd);
     72        return false;
     73    }
     74
     75    ret = fcntl(buf->memfd, F_ADD_SEALS, F_SEAL_SHRINK);
     76    if (ret < 0) {
     77        close(buf->memfd);
     78        return false;
     79    }
     80
     81    buf->stride = buf->width * 4;
     82
     83    return true;
     84}
     85
     86static void
     87udmabuf_free_bo(struct vugbm_buffer *buf)
     88{
     89    close(buf->memfd);
     90}
     91
     92static bool
     93udmabuf_map_bo(struct vugbm_buffer *buf)
     94{
     95    buf->mmap = mmap(NULL, udmabuf_get_size(buf),
     96                     PROT_READ | PROT_WRITE, MAP_SHARED, buf->memfd, 0);
     97    if (buf->mmap == MAP_FAILED) {
     98        return false;
     99    }
    100
    101    return true;
    102}
    103
    104static bool
    105udmabuf_get_fd(struct vugbm_buffer *buf, int *fd)
    106{
    107    struct udmabuf_create create = {
    108        .memfd = buf->memfd,
    109        .offset = 0,
    110        .size = udmabuf_get_size(buf),
    111    };
    112
    113    *fd = ioctl(buf->dev->fd, UDMABUF_CREATE, &create);
    114
    115    return *fd >= 0;
    116}
    117
    118static void
    119udmabuf_unmap_bo(struct vugbm_buffer *buf)
    120{
    121    munmap(buf->mmap, udmabuf_get_size(buf));
    122}
    123
    124static void
    125udmabuf_device_destroy(struct vugbm_device *dev)
    126{
    127    close(dev->fd);
    128}
    129#endif
    130
    131#ifdef CONFIG_GBM
    132static bool
    133alloc_bo(struct vugbm_buffer *buf)
    134{
    135    struct gbm_device *dev = buf->dev->dev;
    136
    137    assert(!buf->bo);
    138
    139    buf->bo = gbm_bo_create(dev, buf->width, buf->height,
    140                            buf->format,
    141                            GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
    142
    143    if (buf->bo) {
    144        buf->stride = gbm_bo_get_stride(buf->bo);
    145        return true;
    146    }
    147
    148    return false;
    149}
    150
    151static void
    152free_bo(struct vugbm_buffer *buf)
    153{
    154    gbm_bo_destroy(buf->bo);
    155}
    156
    157static bool
    158map_bo(struct vugbm_buffer *buf)
    159{
    160    uint32_t stride;
    161
    162    buf->mmap = gbm_bo_map(buf->bo, 0, 0, buf->width, buf->height,
    163                           GBM_BO_TRANSFER_READ_WRITE, &stride,
    164                           &buf->mmap_data);
    165
    166    assert(stride == buf->stride);
    167
    168    return buf->mmap != NULL;
    169}
    170
    171static void
    172unmap_bo(struct vugbm_buffer *buf)
    173{
    174    gbm_bo_unmap(buf->bo, buf->mmap_data);
    175}
    176
    177static bool
    178get_fd(struct vugbm_buffer *buf, int *fd)
    179{
    180    *fd = gbm_bo_get_fd(buf->bo);
    181
    182    return *fd >= 0;
    183}
    184
    185static void
    186device_destroy(struct vugbm_device *dev)
    187{
    188    gbm_device_destroy(dev->dev);
    189}
    190#endif
    191
    192void
    193vugbm_device_destroy(struct vugbm_device *dev)
    194{
    195    if (!dev->inited) {
    196        return;
    197    }
    198
    199    dev->device_destroy(dev);
    200}
    201
    202void
    203vugbm_device_init(struct vugbm_device *dev, int fd)
    204{
    205    assert(!dev->inited);
    206
    207#ifdef CONFIG_GBM
    208    if (fd >= 0) {
    209        dev->dev = gbm_create_device(fd);
    210    }
    211    if (dev->dev != NULL) {
    212        dev->fd = fd;
    213        dev->alloc_bo = alloc_bo;
    214        dev->free_bo = free_bo;
    215        dev->get_fd = get_fd;
    216        dev->map_bo = map_bo;
    217        dev->unmap_bo = unmap_bo;
    218        dev->device_destroy = device_destroy;
    219        dev->inited = true;
    220    }
    221#endif
    222#ifdef CONFIG_MEMFD
    223    if (!dev->inited && g_file_test("/dev/udmabuf", G_FILE_TEST_EXISTS)) {
    224        dev->fd = open("/dev/udmabuf", O_RDWR);
    225        if (dev->fd >= 0) {
    226            g_debug("Using experimental udmabuf backend");
    227            dev->alloc_bo = udmabuf_alloc_bo;
    228            dev->free_bo = udmabuf_free_bo;
    229            dev->get_fd = udmabuf_get_fd;
    230            dev->map_bo = udmabuf_map_bo;
    231            dev->unmap_bo = udmabuf_unmap_bo;
    232            dev->device_destroy = udmabuf_device_destroy;
    233            dev->inited = true;
    234        }
    235    }
    236#endif
    237    if (!dev->inited) {
    238        g_debug("Using mem fallback");
    239        dev->alloc_bo = mem_alloc_bo;
    240        dev->free_bo = mem_free_bo;
    241        dev->map_bo = mem_map_bo;
    242        dev->unmap_bo = mem_unmap_bo;
    243        dev->device_destroy = mem_device_destroy;
    244        dev->inited = true;
    245    }
    246    assert(dev->inited);
    247}
    248
    249static bool
    250vugbm_buffer_map(struct vugbm_buffer *buf)
    251{
    252    struct vugbm_device *dev = buf->dev;
    253
    254    return dev->map_bo(buf);
    255}
    256
    257static void
    258vugbm_buffer_unmap(struct vugbm_buffer *buf)
    259{
    260    struct vugbm_device *dev = buf->dev;
    261
    262    dev->unmap_bo(buf);
    263}
    264
    265bool
    266vugbm_buffer_can_get_dmabuf_fd(struct vugbm_buffer *buffer)
    267{
    268    if (!buffer->dev->get_fd) {
    269        return false;
    270    }
    271
    272    return true;
    273}
    274
    275bool
    276vugbm_buffer_get_dmabuf_fd(struct vugbm_buffer *buffer, int *fd)
    277{
    278    if (!vugbm_buffer_can_get_dmabuf_fd(buffer) ||
    279        !buffer->dev->get_fd(buffer, fd)) {
    280        g_warning("Failed to get dmabuf");
    281        return false;
    282    }
    283
    284    if (*fd < 0) {
    285        g_warning("error: dmabuf_fd < 0");
    286        return false;
    287    }
    288
    289    return true;
    290}
    291
    292bool
    293vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev,
    294                    uint32_t width, uint32_t height)
    295{
    296    buffer->dev = dev;
    297    buffer->width = width;
    298    buffer->height = height;
    299    buffer->format = GBM_FORMAT_XRGB8888;
    300    buffer->stride = 0; /* modified during alloc */
    301    if (!dev->alloc_bo(buffer)) {
    302        g_warning("alloc_bo failed");
    303        return false;
    304    }
    305
    306    if (!vugbm_buffer_map(buffer)) {
    307        g_warning("map_bo failed");
    308        goto err;
    309    }
    310
    311    return true;
    312
    313err:
    314    dev->free_bo(buffer);
    315    return false;
    316}
    317
    318void
    319vugbm_buffer_destroy(struct vugbm_buffer *buffer)
    320{
    321    struct vugbm_device *dev = buffer->dev;
    322
    323    vugbm_buffer_unmap(buffer);
    324    dev->free_bo(buffer);
    325}