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/vmct.h> 13#include <sel4vmmplatsupport/plat/devices.h> 14 15#define GWSTAT_TCON (1U << 16) 16#define GWSTAT_COMP3_ADD_INC (1U << 14) 17#define GWSTAT_COMP3H (1U << 13) 18#define GWSTAT_COMP3L (1U << 12) 19#define GWSTAT_COMP2_ADD_INC (1U << 10) 20#define GWSTAT_COMP2H (1U << 9) 21#define GWSTAT_COMP2L (1U << 8) 22#define GWSTAT_COMP1_ADD_INC (1U << 6) 23#define GWSTAT_COMP1H (1U << 5) 24#define GWSTAT_COMP1L (1U << 4) 25#define GWSTAT_COMP0_ADD_INC (1U << 2) 26#define GWSTAT_COMP0H (1U << 1) 27#define GWSTAT_COMP0L (1U << 0) 28 29 30struct vmct_priv { 31 uint32_t wstat; 32 uint32_t cnt_wstat; 33 uint32_t lwstat[4]; 34}; 35 36static inline struct vmct_priv *vmct_get_priv(void *priv) 37{ 38 assert(priv); 39 return (struct vmct_priv *)priv; 40} 41 42 43static memory_fault_result_t handle_vmct_fault(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, size_t fault_length, 44 void *cookie) 45{ 46 struct vmct_priv *mct_priv; 47 int offset; 48 uint32_t mask; 49 struct device *dev = (struct device *)cookie; 50 51 mct_priv = vmct_get_priv(dev->priv); 52 53 /* Gather fault information */ 54 offset = fault_addr - dev->pstart; 55 mask = get_vcpu_fault_data_mask(vcpu); 56 /* Handle the fault */ 57 if (offset < 0x300) { 58 /*** Global ***/ 59 uint32_t *wstat; 60 uint32_t *cnt_wstat; 61 wstat = &mct_priv->wstat; 62 cnt_wstat = &mct_priv->cnt_wstat; 63 if (!is_vcpu_read_fault(vcpu)) { 64 if (offset >= 0x100 && offset < 0x108) { 65 /* Count registers */ 66 *cnt_wstat |= (1 << (offset - 0x100) / 4); 67 } else if (offset == 0x110) { 68 *cnt_wstat &= ~(get_vcpu_fault_data(vcpu) & mask); 69 } else if (offset >= 0x200 && offset < 0x244) { 70 /* compare registers */ 71 *wstat |= (1 << (offset - 0x200) / 4); 72 } else if (offset == 0x24C) { 73 /* Write status */ 74 *wstat &= ~(get_vcpu_fault_data(vcpu) & mask); 75 } else { 76 ZF_LOGD("global MCT fault on unknown offset 0x%x\n", offset); 77 } 78 } else { 79 /* read fault */ 80 if (offset == 0x110) { 81 set_vcpu_fault_data(vcpu, *cnt_wstat); 82 } else if (offset == 0x24C) { 83 set_vcpu_fault_data(vcpu, *wstat); 84 } else { 85 set_vcpu_fault_data(vcpu, 0); 86 } 87 } 88 } else { 89 /*** Local ***/ 90 int timer = (offset - 0x300) / 0x100; 91 int loffset = (offset - 0x300) - (timer * 0x100); 92 uint32_t *wstat = &mct_priv->lwstat[timer]; 93 if (is_vcpu_read_fault(vcpu)) { 94 if (loffset == 0x0) { /* tcompl */ 95 *wstat |= (1 << 1); 96 } else if (loffset == 0x8) { /* tcomph */ 97 *wstat |= (1 << 1); 98 } else if (loffset == 0x20) { /* tcon */ 99 *wstat |= (1 << 3); 100 } else if (loffset == 0x34) { /* int_en */ 101 /* Do nothing */ 102 } else if (loffset == 0x40) { /* wstat */ 103 *wstat &= ~(get_vcpu_fault_data(vcpu) & mask); 104 } else { 105 ZF_LOGD("local MCT fault on unknown offset 0x%x\n", offset); 106 } 107 } else { 108 /* read fault */ 109 if (loffset == 0x40) { 110 set_vcpu_fault_data(vcpu, *wstat); 111 } else { 112 set_vcpu_fault_data(vcpu, 0); 113 } 114 } 115 } 116 advance_vcpu_fault(vcpu); 117 return FAULT_HANDLED; 118} 119 120const struct device dev_vmct_timer = { 121 .name = "mct", 122 123 .pstart = MCT_ADDR, 124 125 .size = 0x1000, 126 .priv = NULL 127}; 128 129 130int vm_install_vmct(vm_t *vm) 131{ 132 struct vmct_priv *vmct_data; 133 struct device *d; 134 int err; 135 136 d = (struct device *)calloc(1, sizeof(struct device)); 137 if (!d) { 138 return -1; 139 } 140 memcpy(d, &dev_vmct_timer, sizeof(struct device)); 141 /* Initialise the virtual device */ 142 vmct_data = calloc(1, sizeof(struct vmct_priv)); 143 if (vmct_data == NULL) { 144 assert(vmct_data); 145 return -1; 146 } 147 d->priv = vmct_data; 148 vm_memory_reservation_t *reservation = vm_reserve_memory_at(vm, d->pstart, d->size, 149 handle_vmct_fault, (void *)d); 150 if (!reservation) { 151 free(d); 152 free(vmct_data); 153 return -1; 154 } 155 return 0; 156} 157