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#include <sel4vm/guest_memory.h> 12 13#include <sel4vmmplatsupport/device.h> 14#include <sel4vmmplatsupport/plat/device_map.h> 15#include <sel4vmmplatsupport/plat/vuart.h> 16#include <sel4vmmplatsupport/plat/devices.h> 17 18#define VUART_BUFLEN 300 19 20#define ULCON 0x000 /* line control */ 21#define UCON 0x004 /* control */ 22#define UFCON 0x008 /* fifo control */ 23#define UMCON 0x00C /* modem control */ 24#define UTRSTAT 0x010 /* TX/RX status */ 25#define UERSTAT 0x014 /* RX error status */ 26#define UFSTAT 0x018 /* FIFO status */ 27#define UMSTAT 0x01C /* modem status */ 28#define UTXH 0x020 /* TX buffer */ 29#define URXH 0x024 /* RX buffer */ 30#define UBRDIV 0x028 /* baud rate divisor */ 31#define UFRACVAL 0x02C /* divisor fractional value */ 32#define UINTP 0x030 /* interrupt pending */ 33#define UINTSP 0x034 /* interrupt source pending */ 34#define UINTM 0x038 /* interrupt mask */ 35#define UART_SIZE 0x03C 36 37 38 39struct vuart_priv { 40 void *regs; 41 char buffer[VUART_BUFLEN]; 42 int buf_pos; 43 vm_t *vm; 44}; 45 46static inline void *vuart_priv_get_regs(struct device *d) 47{ 48 return ((struct vuart_priv *)d->priv)->regs; 49} 50 51static void vuart_reset(struct device *d) 52{ 53 const uint32_t reset_data[] = { 54 0x00000003, 0x000003c5, 0x00000111, 0x00000000, 55 0x00000002, 0x00000000, 0x00010000, 0x00000011, 56 0x00000000, 0x00000000, 0x00000021, 0x0000000b, 57 0x00000004, 0x00000004, 0x00000000 58 }; 59 assert(sizeof(reset_data) == UART_SIZE); 60 memcpy(vuart_priv_get_regs(d), reset_data, sizeof(reset_data)); 61} 62 63static void flush_vconsole_device(struct device *d) 64{ 65 struct vuart_priv *vuart_data; 66 char *buf; 67 int i; 68 assert(d->priv); 69 vuart_data = (struct vuart_priv *)d->priv; 70 buf = vuart_data->buffer; 71 for (i = 0; i < vuart_data->buf_pos; i++) { 72 if (buf[i] != '\033') { 73 putchar(buf[i]); 74 } else { 75 while (i < vuart_data->buf_pos && buf[i] != 'm') { 76 i++; 77 } 78 } 79 } 80 vuart_data->buf_pos = 0; 81} 82 83static void vuart_putchar(struct device *d, char c) 84{ 85 struct vuart_priv *vuart_data; 86 assert(d->priv); 87 vuart_data = (struct vuart_priv *)d->priv; 88 89 if (vuart_data->buf_pos == VUART_BUFLEN) { 90 flush_vconsole_device(d); 91 } 92 assert(vuart_data->buf_pos < VUART_BUFLEN); 93 vuart_data->buffer[vuart_data->buf_pos++] = c; 94 95 if ((c & 0xff) == '\n') { 96 flush_vconsole_device(d); 97 } 98} 99 100static memory_fault_result_t handle_vuart_fault(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, size_t fault_length, 101 void *cookie) 102{ 103 uint32_t *reg; 104 int offset; 105 uint32_t mask; 106 struct device *dev; 107 dev = (struct device *)cookie; 108 109 /* Gather fault information */ 110 offset = fault_addr - dev->pstart; 111 reg = (uint32_t *)(vuart_priv_get_regs(dev) + offset); 112 mask = get_vcpu_fault_data_mask(vcpu); 113 /* Handle the fault */ 114 if (offset < 0 || UART_SIZE <= offset) { 115 /* Out of range, treat as SBZ */ 116 set_vcpu_fault_data(vcpu, 0); 117 return FAULT_IGNORE; 118 119 } else if (is_vcpu_read_fault(vcpu)) { 120 /* Blindly read out data */ 121 set_vcpu_fault_data(vcpu, *reg); 122 advance_vcpu_fault(vcpu); 123 124 } else { /* if(fault_is_write(fault))*/ 125 /* Blindly write to the device */ 126 uint32_t v; 127 v = *reg & ~mask; 128 v |= get_vcpu_fault_data(vcpu) & mask; 129 *reg = v; 130 /* If it was the TX buffer, we send to the local stdout */ 131 if (offset == UTXH) { 132 vuart_putchar(dev, get_vcpu_fault_data(vcpu)); 133 } 134 advance_vcpu_fault(vcpu); 135 } 136 return FAULT_HANDLED; 137} 138 139const struct device dev_uart0 = { 140 .name = "uart0", 141 .pstart = UART0_PADDR, 142 .size = 0x1000, 143 .priv = NULL 144}; 145 146const struct device dev_uart1 = { 147 .name = "uart1", 148 .pstart = UART1_PADDR, 149 .size = 0x1000, 150 .priv = NULL 151}; 152 153const struct device dev_uart2 = { 154 .name = "uart2.console", 155 .pstart = UART2_PADDR, 156 .size = 0x1000, 157 .priv = NULL 158}; 159 160 161 162const struct device dev_uart3 = { 163 .name = "uart3", 164 .pstart = UART3_PADDR, 165 .size = 0x1000, 166 .priv = NULL 167}; 168 169 170int vm_install_vconsole(vm_t *vm) 171{ 172 struct vuart_priv *vuart_data; 173 struct device *d; 174 int err; 175 176 d = (struct device *)calloc(1, sizeof(struct device)); 177 if (!d) { 178 return -1; 179 } 180 181 *d = dev_vconsole; 182 /* Initialise the virtual device */ 183 vuart_data = calloc(1, sizeof(struct vuart_priv)); 184 if (vuart_data == NULL) { 185 assert(vuart_data); 186 return -1; 187 } 188 vuart_data->vm = vm; 189 190 vuart_data->regs = calloc(1, UART_SIZE); 191 if (vuart_data->regs == NULL) { 192 assert(vuart_data->regs); 193 return -1; 194 } 195 196 vm_memory_reservation_t *reservation = vm_reserve_memory_at(vm, d->pstart, d->size, 197 handle_vuart_fault, (void *)d); 198 if (!reservation) { 199 return -1; 200 } 201 d->priv = vuart_data; 202 vuart_reset(d); 203 return 0; 204} 205 206 207int vm_install_ac_uart(vm_t *vm, const struct device *d) 208{ 209 int err; 210 int mask_size = UART_SIZE; 211 uint32_t *mask = (uint32_t *)calloc(1, mask_size); 212 err = vm_install_generic_ac_device(vm, d, mask, mask_size, VACDEV_MASK_ONLY); 213 if (err) { 214 free(mask); 215 return -1; 216 } else { 217 mask[ULCON / 4] = 0x0; 218 mask[UCON / 4] = 0x0; 219 mask[UFCON / 4] = 0x0; 220 mask[UMCON / 4] = 0x0; 221 mask[UTRSTAT / 4] = 0x0; 222 mask[UERSTAT / 4] = 0x0; 223 mask[UFSTAT / 4] = 0x0; 224 mask[UMSTAT / 4] = 0x0; 225 mask[UTXH / 4] = 0xffffffff; 226 mask[URXH / 4] = 0xffffffff; 227 mask[UBRDIV / 4] = 0x0; 228 mask[UFRACVAL / 4] = 0x0; 229 mask[UINTP / 4] = 0xffffffff; 230 mask[UINTSP / 4] = 0xffffffff; 231 mask[UINTM / 4] = 0xffffffff; 232 return 0; 233 } 234} 235