linux/drivers/staging/vboxvideo/vbox_hgsmi.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 Oracle Corporation
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the
   6 * "Software"), to deal in the Software without restriction, including
   7 * without limitation the rights to use, copy, modify, merge, publish,
   8 * distribute, sub license, and/or sell copies of the Software, and to
   9 * permit persons to whom the Software is furnished to do so, subject to
  10 * the following conditions:
  11 *
  12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  15 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  17 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  18 * USE OR OTHER DEALINGS IN THE SOFTWARE.
  19 *
  20 * The above copyright notice and this permission notice (including the
  21 * next paragraph) shall be included in all copies or substantial portions
  22 * of the Software.
  23 *
  24 * Authors: Hans de Goede <hdegoede@redhat.com>
  25 */
  26
  27#include "vbox_drv.h"
  28#include "vboxvideo_vbe.h"
  29#include "hgsmi_defs.h"
  30
  31/* One-at-a-Time Hash from http://www.burtleburtle.net/bob/hash/doobs.html */
  32static u32 hgsmi_hash_process(u32 hash, const u8 *data, int size)
  33{
  34        while (size--) {
  35                hash += *data++;
  36                hash += (hash << 10);
  37                hash ^= (hash >> 6);
  38        }
  39
  40        return hash;
  41}
  42
  43static u32 hgsmi_hash_end(u32 hash)
  44{
  45        hash += (hash << 3);
  46        hash ^= (hash >> 11);
  47        hash += (hash << 15);
  48
  49        return hash;
  50}
  51
  52/* Not really a checksum but that is the naming used in all vbox code */
  53static u32 hgsmi_checksum(u32 offset,
  54                          const struct hgsmi_buffer_header *header,
  55                          const struct hgsmi_buffer_tail *tail)
  56{
  57        u32 checksum;
  58
  59        checksum = hgsmi_hash_process(0, (u8 *)&offset, sizeof(offset));
  60        checksum = hgsmi_hash_process(checksum, (u8 *)header, sizeof(*header));
  61        /* 4 -> Do not checksum the checksum itself */
  62        checksum = hgsmi_hash_process(checksum, (u8 *)tail, 4);
  63
  64        return hgsmi_hash_end(checksum);
  65}
  66
  67void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
  68                         u8 channel, u16 channel_info)
  69{
  70        struct hgsmi_buffer_header *h;
  71        struct hgsmi_buffer_tail *t;
  72        size_t total_size;
  73        dma_addr_t offset;
  74
  75        total_size = size + sizeof(*h) + sizeof(*t);
  76        h = gen_pool_dma_alloc(guest_pool, total_size, &offset);
  77        if (!h)
  78                return NULL;
  79
  80        t = (struct hgsmi_buffer_tail *)((u8 *)h + sizeof(*h) + size);
  81
  82        h->flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
  83        h->data_size = size;
  84        h->channel = channel;
  85        h->channel_info = channel_info;
  86        memset(&h->u.header_data, 0, sizeof(h->u.header_data));
  87
  88        t->reserved = 0;
  89        t->checksum = hgsmi_checksum(offset, h, t);
  90
  91        return (u8 *)h + sizeof(*h);
  92}
  93
  94void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf)
  95{
  96        struct hgsmi_buffer_header *h =
  97                (struct hgsmi_buffer_header *)((u8 *)buf - sizeof(*h));
  98        size_t total_size = h->data_size + sizeof(*h) +
  99                                             sizeof(struct hgsmi_buffer_tail);
 100
 101        gen_pool_free(guest_pool, (unsigned long)h, total_size);
 102}
 103
 104int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf)
 105{
 106        phys_addr_t offset;
 107
 108        offset = gen_pool_virt_to_phys(guest_pool, (unsigned long)buf -
 109                                       sizeof(struct hgsmi_buffer_header));
 110        outl(offset, VGA_PORT_HGSMI_GUEST);
 111        /* Make the compiler aware that the host has changed memory. */
 112        mb();
 113
 114        return 0;
 115}
 116