linux/drivers/gpu/drm/vboxvideo/vbox_hgsmi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2/*
   3 * Copyright (C) 2017 Oracle Corporation
   4 * Authors: Hans de Goede <hdegoede@redhat.com>
   5 */
   6
   7#include "vbox_drv.h"
   8#include "vboxvideo_vbe.h"
   9#include "hgsmi_defs.h"
  10
  11/* One-at-a-Time Hash from https://www.burtleburtle.net/bob/hash/doobs.html */
  12static u32 hgsmi_hash_process(u32 hash, const u8 *data, int size)
  13{
  14        while (size--) {
  15                hash += *data++;
  16                hash += (hash << 10);
  17                hash ^= (hash >> 6);
  18        }
  19
  20        return hash;
  21}
  22
  23static u32 hgsmi_hash_end(u32 hash)
  24{
  25        hash += (hash << 3);
  26        hash ^= (hash >> 11);
  27        hash += (hash << 15);
  28
  29        return hash;
  30}
  31
  32/* Not really a checksum but that is the naming used in all vbox code */
  33static u32 hgsmi_checksum(u32 offset,
  34                          const struct hgsmi_buffer_header *header,
  35                          const struct hgsmi_buffer_tail *tail)
  36{
  37        u32 checksum;
  38
  39        checksum = hgsmi_hash_process(0, (u8 *)&offset, sizeof(offset));
  40        checksum = hgsmi_hash_process(checksum, (u8 *)header, sizeof(*header));
  41        /* 4 -> Do not checksum the checksum itself */
  42        checksum = hgsmi_hash_process(checksum, (u8 *)tail, 4);
  43
  44        return hgsmi_hash_end(checksum);
  45}
  46
  47void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
  48                         u8 channel, u16 channel_info)
  49{
  50        struct hgsmi_buffer_header *h;
  51        struct hgsmi_buffer_tail *t;
  52        size_t total_size;
  53        dma_addr_t offset;
  54
  55        total_size = size + sizeof(*h) + sizeof(*t);
  56        h = gen_pool_dma_alloc(guest_pool, total_size, &offset);
  57        if (!h)
  58                return NULL;
  59
  60        t = (struct hgsmi_buffer_tail *)((u8 *)h + sizeof(*h) + size);
  61
  62        h->flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
  63        h->data_size = size;
  64        h->channel = channel;
  65        h->channel_info = channel_info;
  66        memset(&h->u.header_data, 0, sizeof(h->u.header_data));
  67
  68        t->reserved = 0;
  69        t->checksum = hgsmi_checksum(offset, h, t);
  70
  71        return (u8 *)h + sizeof(*h);
  72}
  73
  74void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf)
  75{
  76        struct hgsmi_buffer_header *h =
  77                (struct hgsmi_buffer_header *)((u8 *)buf - sizeof(*h));
  78        size_t total_size = h->data_size + sizeof(*h) +
  79                                             sizeof(struct hgsmi_buffer_tail);
  80
  81        gen_pool_free(guest_pool, (unsigned long)h, total_size);
  82}
  83
  84int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf)
  85{
  86        phys_addr_t offset;
  87
  88        offset = gen_pool_virt_to_phys(guest_pool, (unsigned long)buf -
  89                                       sizeof(struct hgsmi_buffer_header));
  90        outl(offset, VGA_PORT_HGSMI_GUEST);
  91        /* Make the compiler aware that the host has changed memory. */
  92        mb();
  93
  94        return 0;
  95}
  96