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