vbox_hgsmi.c 2.3 KB

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