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