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