1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6#include <stdlib.h> 7#include <string.h> 8 9#include <sel4vm/guest_vm.h> 10#include <sel4vm/guest_vcpu_fault.h> 11 12#include <sel4vmmplatsupport/plat/vsysreg.h> 13#include <sel4vmmplatsupport/device.h> 14#include <sel4vmmplatsupport/plat/devices.h> 15 16struct sysreg_priv { 17 struct dma *dma_list; 18 vm_t *vm; 19 void *regs; 20}; 21 22static memory_fault_result_t handle_vsysreg_fault(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, size_t fault_length, 23 void *cookie) 24{ 25 struct device *dev = (struct device *)cookie; 26 struct sysreg_priv *sysreg_data = (struct sysreg_priv *)dev->priv; 27 volatile uint32_t *reg; 28 int offset; 29 30 /* Gather fault information */ 31 offset = fault_addr - dev->pstart; 32 reg = (uint32_t *)(sysreg_data->regs + offset); 33 /* Handle the fault */ 34 reg = (volatile uint32_t *)(sysreg_data->regs + offset); 35 if (is_vcpu_read_fault(vcpu)) { 36 set_vcpu_fault_data(vcpu, *reg); 37 ZF_LOGD("[%s] pc0x%x| r0x%x:0x%x\n", dev->name, get_vcpu_fault_ip(vcpu), 38 fault_addr, get_vcpu_fault_data(vcpu)); 39 } else { 40 ZF_LOGD("[%s] pc0x%x| w0x%x:0x%x\n", dev->name, get_vcpu_fault_ip(vcpu), 41 fault_addr, get_vcpu_fault_data(vcpu)); 42 *reg = emulate_vcpu_fault(vcpu, *reg); 43 } 44 advance_vcpu_fault(vcpu); 45 return FAULT_HANDLED; 46} 47 48const struct device dev_sysreg = { 49 .name = "sysreg", 50 .pstart = SYSREG_PADDR, 51 .size = 0x1000, 52 .priv = NULL 53}; 54 55int vm_install_vsysreg(vm_t *vm) 56{ 57 struct sysreg_priv *sysreg_data; 58 struct device *d; 59 int err; 60 61 d = (struct device *)calloc(1, sizeof(struct device)); 62 memcpy(d, &dev_sysreg, sizeof(struct device)); 63 64 /* Initialise the virtual device */ 65 sysreg_data = calloc(1, sizeof(struct sysreg_priv)); 66 if (sysreg_data == NULL) { 67 assert(sysreg_data); 68 free(d); 69 return -1; 70 } 71 sysreg_data->vm = vm; 72 73 sysreg_data->regs = ps_io_map(&vm->io_ops->io_mapper, d->pstart, PAGE_SIZE_4K, 0, PS_MEM_NORMAL); 74 if (sysreg_data->regs == NULL) { 75 free(d); 76 free(sysreg_data); 77 return -1; 78 } 79 80 d->priv = sysreg_data; 81 82 vm_memory_reservation_t *reservation = vm_reserve_memory_at(vm, d->pstart, d->size, 83 handle_vsysreg_fault, (void *)d); 84 if (!reservation) { 85 free(d); 86 free(sysreg_data); 87 return -1; 88 } 89 90 return 0; 91} 92