1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <sel4vm/guest_vm.h> 8#include <sel4vm/guest_vcpu_fault.h> 9#include <sel4vm/guest_memory_helpers.h> 10 11#include <sel4vmmplatsupport/guest_memory_util.h> 12#include <sel4vmmplatsupport/device.h> 13#include <sel4vmmplatsupport/device_utils.h> 14 15int vm_install_ram_only_device(vm_t *vm, const struct device *device) 16{ 17 struct device d; 18 uintptr_t paddr; 19 int err; 20 d = *device; 21 22 vm_memory_reservation_t *reservation = vm_reserve_memory_at(vm, d.pstart, d.size, 23 default_error_fault_callback, NULL); 24 if (!reservation) { 25 return -1; 26 } 27 28 err = map_frame_alloc_reservation(vm, reservation); 29 assert(!err); 30 return err; 31} 32 33static memory_fault_result_t passthrough_device_fault(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, 34 size_t fault_length, void *cookie) 35{ 36 ZF_LOGE("Fault occured on passthrough device"); 37 return FAULT_ERROR; 38} 39 40int vm_install_passthrough_device(vm_t *vm, const struct device *device) 41{ 42 struct device d; 43 uintptr_t paddr; 44 int err; 45 d = *device; 46 for (paddr = d.pstart; paddr - d.pstart < d.size; paddr += 0x1000) { 47 void *addr; 48 vm_memory_reservation_t *reservation; 49 reservation = vm_reserve_memory_at(vm, paddr, 0x1000, passthrough_device_fault, NULL); 50 if (!reservation) { 51 return -1; 52 } 53 err = map_ut_alloc_reservation(vm, reservation); 54#ifdef PLAT_EXYNOS5 55 if (err && paddr == MCT_ADDR) { 56 printf("*****************************************\n"); 57 printf("*** Linux will try to use the MCT but ***\n"); 58 printf("*** the kernel is not exporting it! ***\n"); 59 printf("*****************************************\n"); 60 /* VMCT is not fully functional yet */ 61// err = vm_install_vmct(vm); 62 return -1; 63 } 64#endif 65 if (err) { 66 return -1; 67 } 68 } 69 return err; 70} 71 72static memory_fault_result_t handle_listening_fault(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, 73 size_t fault_length, void *cookie) 74{ 75 volatile uint32_t *reg; 76 int offset; 77 void **map; 78 struct device *d = (struct device *)cookie; 79 80 assert(d->priv); 81 map = (void **)d->priv; 82 offset = fault_addr - d->pstart; 83 84 reg = (volatile uint32_t *)(map[offset >> 12] + (offset & MASK(12))); 85 86 printf("[Listener/%s] ", d->name); 87 if (is_vcpu_read_fault(vcpu)) { 88 printf("read "); 89 set_vcpu_fault_data(vcpu, *reg); 90 } else { 91 printf("write"); 92 *reg = emulate_vcpu_fault(vcpu, *reg); 93 } 94 printf(" "); 95 seL4_Word data = get_vcpu_fault_data(vcpu); 96 seL4_Word data_mask = get_vcpu_fault_data_mask(vcpu); 97 printf("0x%x", data & data_mask); 98 printf(" address %p @ pc %p\n", (void *) fault_addr, 99 (void *) get_vcpu_fault_ip(vcpu)); 100 advance_vcpu_fault(vcpu); 101 return FAULT_HANDLED; 102} 103 104 105int vm_install_listening_device(vm_t *vm, const struct device *dev_listening) 106{ 107 struct device *d; 108 int pages; 109 int i; 110 void **map; 111 int err; 112 pages = dev_listening->size >> 12; 113 d = (struct device *)calloc(1, sizeof(struct device)); 114 if (!d) { 115 return -1; 116 } 117 memcpy(d, dev_listening, sizeof(struct device)); 118 /* Build device memory map */ 119 map = (void **)calloc(1, sizeof(void *) * pages); 120 if (map == NULL) { 121 return -1; 122 } 123 d->priv = map; 124 for (i = 0; i < pages; i++) { 125 map[i] = ps_io_map(&vm->io_ops->io_mapper, d->pstart + (i << 12), PAGE_SIZE_4K, 0, PS_MEM_NORMAL); 126 } 127 vm_memory_reservation_t *reservation = vm_reserve_memory_at(vm, d->pstart, d->size, 128 handle_listening_fault, (void *)d); 129 if (!reservation) { 130 free(d); 131 free(map); 132 return -1; 133 } 134 return 0; 135} 136 137 138static memory_fault_result_t handle_listening_ram_fault(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, 139 size_t fault_length, void *cookie) 140{ 141 volatile uint32_t *reg; 142 int offset; 143 144 struct device *d = (struct device *)cookie; 145 assert(d->priv); 146 offset = fault_addr - d->pstart; 147 148 reg = (volatile uint32_t *)(d->priv + offset); 149 150 if (is_vcpu_read_fault(vcpu)) { 151 set_vcpu_fault_data(vcpu, *reg); 152 } else { 153 *reg = emulate_vcpu_fault(vcpu, *reg); 154 } 155 printf("Listener pc%p| %s%p:%p\n", (void *) get_vcpu_fault_ip(vcpu), 156 is_vcpu_read_fault(vcpu) ? "r" : "w", 157 (void *) fault_addr, 158 (void *) get_vcpu_fault_data(vcpu)); 159 advance_vcpu_fault(vcpu); 160 return FAULT_HANDLED; 161} 162 163 164const struct device dev_listening_ram = { 165 .name = "<listing_ram>", 166 .pstart = 0x0, 167 .size = 0x1000, 168 .priv = NULL 169}; 170 171 172int vm_install_listening_ram(vm_t *vm, uintptr_t addr, size_t size) 173{ 174 struct device *d; 175 int err; 176 177 d = (struct device *)calloc(1, sizeof(struct device)); 178 if (!d) { 179 return -1; 180 } 181 memcpy(d, &dev_listening_ram, sizeof(struct device)); 182 183 d->pstart = addr; 184 d->size = size; 185 d->priv = calloc(1, 0x1000); 186 assert(d->priv); 187 if (!d->priv) { 188 ZF_LOGE("calloc failed\n"); 189 return -1; 190 } 191 192 vm_memory_reservation_t *reservation = vm_reserve_memory_at(vm, d->pstart, d->size, 193 handle_listening_ram_fault, (void *)d); 194 if (!reservation) { 195 return -1; 196 } 197 return 0; 198} 199