18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Oracle Corporation 48c2ecf20Sopenharmony_ci * Authors: Hans de Goede <hdegoede@redhat.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "vbox_drv.h" 88c2ecf20Sopenharmony_ci#include "vboxvideo_vbe.h" 98c2ecf20Sopenharmony_ci#include "hgsmi_defs.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* One-at-a-Time Hash from https://www.burtleburtle.net/bob/hash/doobs.html */ 128c2ecf20Sopenharmony_cistatic u32 hgsmi_hash_process(u32 hash, const u8 *data, int size) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci while (size--) { 158c2ecf20Sopenharmony_ci hash += *data++; 168c2ecf20Sopenharmony_ci hash += (hash << 10); 178c2ecf20Sopenharmony_ci hash ^= (hash >> 6); 188c2ecf20Sopenharmony_ci } 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci return hash; 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic u32 hgsmi_hash_end(u32 hash) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci hash += (hash << 3); 268c2ecf20Sopenharmony_ci hash ^= (hash >> 11); 278c2ecf20Sopenharmony_ci hash += (hash << 15); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci return hash; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Not really a checksum but that is the naming used in all vbox code */ 338c2ecf20Sopenharmony_cistatic u32 hgsmi_checksum(u32 offset, 348c2ecf20Sopenharmony_ci const struct hgsmi_buffer_header *header, 358c2ecf20Sopenharmony_ci const struct hgsmi_buffer_tail *tail) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci u32 checksum; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci checksum = hgsmi_hash_process(0, (u8 *)&offset, sizeof(offset)); 408c2ecf20Sopenharmony_ci checksum = hgsmi_hash_process(checksum, (u8 *)header, sizeof(*header)); 418c2ecf20Sopenharmony_ci /* 4 -> Do not checksum the checksum itself */ 428c2ecf20Sopenharmony_ci checksum = hgsmi_hash_process(checksum, (u8 *)tail, 4); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return hgsmi_hash_end(checksum); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_civoid *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size, 488c2ecf20Sopenharmony_ci u8 channel, u16 channel_info) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct hgsmi_buffer_header *h; 518c2ecf20Sopenharmony_ci struct hgsmi_buffer_tail *t; 528c2ecf20Sopenharmony_ci size_t total_size; 538c2ecf20Sopenharmony_ci dma_addr_t offset; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci total_size = size + sizeof(*h) + sizeof(*t); 568c2ecf20Sopenharmony_ci h = gen_pool_dma_alloc(guest_pool, total_size, &offset); 578c2ecf20Sopenharmony_ci if (!h) 588c2ecf20Sopenharmony_ci return NULL; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci t = (struct hgsmi_buffer_tail *)((u8 *)h + sizeof(*h) + size); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci h->flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE; 638c2ecf20Sopenharmony_ci h->data_size = size; 648c2ecf20Sopenharmony_ci h->channel = channel; 658c2ecf20Sopenharmony_ci h->channel_info = channel_info; 668c2ecf20Sopenharmony_ci memset(&h->u.header_data, 0, sizeof(h->u.header_data)); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci t->reserved = 0; 698c2ecf20Sopenharmony_ci t->checksum = hgsmi_checksum(offset, h, t); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return (u8 *)h + sizeof(*h); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_civoid hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct hgsmi_buffer_header *h = 778c2ecf20Sopenharmony_ci (struct hgsmi_buffer_header *)((u8 *)buf - sizeof(*h)); 788c2ecf20Sopenharmony_ci size_t total_size = h->data_size + sizeof(*h) + 798c2ecf20Sopenharmony_ci sizeof(struct hgsmi_buffer_tail); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci gen_pool_free(guest_pool, (unsigned long)h, total_size); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciint hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci phys_addr_t offset; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci offset = gen_pool_virt_to_phys(guest_pool, (unsigned long)buf - 898c2ecf20Sopenharmony_ci sizeof(struct hgsmi_buffer_header)); 908c2ecf20Sopenharmony_ci outl(offset, VGA_PORT_HGSMI_GUEST); 918c2ecf20Sopenharmony_ci /* Make the compiler aware that the host has changed memory. */ 928c2ecf20Sopenharmony_ci mb(); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 96