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