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