1/*
2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <stdlib.h>
8#include <sel4/sel4.h>
9#include <vka/capops.h>
10
11#include <sel4vm/guest_vm.h>
12#include <sel4vm/guest_memory.h>
13#include <sel4vm/guest_memory_helpers.h>
14#include <sel4vm/guest_irq_controller.h>
15#include <sel4vm/guest_vcpu_fault.h>
16#include <sel4vm/boot.h>
17
18#include <sel4vmmplatsupport/device.h>
19#include <sel4vmmplatsupport/guest_memory_util.h>
20#include <sel4vmmplatsupport/drivers/virtio.h>
21#include <sel4vmmplatsupport/drivers/pci_helper.h>
22#include <sel4vmmplatsupport/drivers/cross_vm_connection.h>
23
24#include <pci/helper.h>
25
26#define MAX_NUM_CONNECTIONS 32
27
28#define EVENT_BAR_EMIT_REGISTER 0x0
29#define EVENT_BAR_EMIT_REGISTER_INDEX 0
30#define EVENT_BAR_CONSUME_EVENT_REGISTER 0x4
31#define EVENT_BAR_CONSUME_EVENT_REGISTER_INDEX 1
32#define EVENT_BAR_DEVICE_NAME_REGISTER 0x8
33#define EVENT_BAR_DEVICE_NAME_MAX_LEN 50
34
35struct connection_info {
36    uintptr_t event_address;
37    void *event_registers;
38    uintptr_t dataport_address;
39    size_t dataport_size_bits;
40    crossvm_handle_t connection;
41    int connection_irq;
42};
43
44struct dataport_iterator_cookie {
45    seL4_CPtr *dataport_frames;
46    uintptr_t dataport_start;
47    size_t dataport_size;
48    vm_t *vm;
49};
50
51struct connection_info info[MAX_NUM_CONNECTIONS];
52int total_connections;
53
54static int construct_connection_bar(vm_t *vm, struct connection_info *info, int num_connections, vmm_pci_space_t *pci)
55{
56    for (int conn_idx = 0; conn_idx < num_connections; conn_idx++) {
57        vmm_pci_device_def_t *pci_config;
58        pci_config = calloc(1, sizeof(*pci_config));
59        ZF_LOGF_IF(pci_config == NULL, "Failed to allocate pci config");
60        *pci_config = (vmm_pci_device_def_t) {
61            .vendor_id = 0x1af4,
62            .device_id = 0xa111,
63            .revision_id = 0x1,
64            .subsystem_vendor_id = 0x0,
65            .subsystem_id = 0x0,
66            .interrupt_pin = 1,
67            .interrupt_line = info[conn_idx].connection_irq,
68            .bar0 = info[conn_idx].event_address | PCI_BASE_ADDRESS_SPACE_MEMORY,
69            .bar1 = info[conn_idx].dataport_address | PCI_BASE_ADDRESS_SPACE_MEMORY,
70            .command = PCI_COMMAND_MEMORY,
71            .header_type = PCI_HEADER_TYPE_NORMAL,
72            .subclass = (PCI_CLASS_MEMORY_RAM >> 8) & 0xff,
73            .class_code = (PCI_CLASS_MEMORY_RAM >> 16) & 0xff,
74        };
75
76        vmm_pci_entry_t entry = (vmm_pci_entry_t) {
77            .cookie = pci_config,
78            .ioread = vmm_pci_mem_device_read,
79            .iowrite = vmm_pci_mem_device_write
80        };
81
82        vmm_pci_bar_t bars[2] = {
83            {
84                .mem_type = PREFETCH_MEM,
85                .address = info[conn_idx].event_address,
86                /* if size_bits isn't the same for all resources then Linux tries
87                   to remap the resources which the vmm driver doesn't support.
88                 */
89                .size_bits = info[conn_idx].dataport_size_bits
90            },
91            {
92                .mem_type = PREFETCH_MEM,
93                .address = info[conn_idx].dataport_address,
94                .size_bits = info[conn_idx].dataport_size_bits
95            }
96        };
97        vmm_pci_entry_t connection_pci_bar;
98        /* TODO: Make both architecture go through the same interface */
99        if (config_set(CONFIG_ARCH_X86)) {
100            connection_pci_bar = vmm_pci_create_bar_emulation(entry, 2, bars);
101        } else if (config_set(CONFIG_ARCH_ARM)) {
102            connection_pci_bar = vmm_pci_create_passthrough_bar_emulation(entry, 2, bars);
103        }
104        vmm_pci_add_entry(pci, connection_pci_bar, NULL);
105    }
106    return 0;
107}
108
109static memory_fault_result_t handle_event_bar_fault(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr,
110                                                    size_t fault_length, void *cookie)
111{
112    struct device *d = (struct device *)cookie;
113    struct connection_info *info = (struct connection_info *)d->priv;
114    uint8_t reg = (fault_addr - d->pstart) & 0xff;
115
116    if (is_vcpu_read_fault(vcpu)) {
117        /* This shouldn't happen - the guest should have read writes to the event bar */
118        ZF_LOGE("Error: Event Bar Memory is misconfigured");
119    } else if (reg == EVENT_BAR_EMIT_REGISTER) {
120        /* Emit operation: Write to register 0 */
121        if (!info->connection.emit_fn) {
122            ZF_LOGE("Connection is not configured with an emit function\n");
123        } else {
124            info->connection.emit_fn();
125        }
126    } else if (reg == EVENT_BAR_CONSUME_EVENT_REGISTER) {
127        uint32_t mask = get_vcpu_fault_data_mask(vcpu);
128        uint32_t value = get_vcpu_fault_data(vcpu) & mask;
129        uint32_t *event_registers = (uint32_t *)info->event_registers;
130        event_registers[EVENT_BAR_CONSUME_EVENT_REGISTER_INDEX] = value;
131    } else {
132        ZF_LOGE("Event Bar register unsupported");
133    }
134    advance_vcpu_fault(vcpu);
135    return FAULT_HANDLED;
136}
137
138static int reserve_event_bar(vm_t *vm, uintptr_t event_bar_address, struct connection_info *info)
139{
140    struct device *event_bar = calloc(1, sizeof(struct device));
141    if (!event_bar) {
142        ZF_LOGE("Failed to create event bar device");
143        return -1;
144    }
145    event_bar->pstart = event_bar_address;
146    event_bar->priv = (void *)info;
147
148    info->event_registers = create_allocated_reservation_frame(vm, event_bar_address, seL4_CanRead,
149                                                               handle_event_bar_fault, event_bar);
150    if (info->event_registers == NULL) {
151        ZF_LOGE("Failed to map emulated event bar space");
152        return -1;
153    }
154    /* Zero out memory */
155    memset(info->event_registers, 0, PAGE_SIZE);
156    info->event_address = event_bar_address;
157    return 0;
158}
159
160static vm_frame_t dataport_memory_iterator(uintptr_t addr, void *cookie)
161{
162    int error;
163    cspacepath_t return_frame;
164    vm_frame_t frame_result = { seL4_CapNull, seL4_NoRights, 0, 0 };
165    struct dataport_iterator_cookie *dataport_cookie = (struct dataport_iterator_cookie *)cookie;
166    seL4_CPtr *dataport_frames = dataport_cookie->dataport_frames;
167    vm_t *vm = dataport_cookie->vm;
168    uintptr_t dataport_start = dataport_cookie->dataport_start;
169    size_t dataport_size = dataport_cookie->dataport_size;
170    int page_size = seL4_PageBits;
171
172    uintptr_t frame_start = ROUND_DOWN(addr, BIT(page_size));
173    if (frame_start <  dataport_start ||
174        frame_start > dataport_start + dataport_size) {
175        ZF_LOGE("Error: Not Dataport region");
176        return frame_result;
177    }
178    int page_idx = (frame_start - dataport_start) / BIT(page_size);
179    frame_result.cptr = dataport_frames[page_idx];
180    frame_result.rights = seL4_AllRights;
181    frame_result.vaddr = frame_start;
182    frame_result.size_bits = page_size;
183    return frame_result;
184}
185
186static int reserve_dataport_memory(vm_t *vm, crossvm_dataport_handle_t *dataport, uintptr_t dataport_address,
187                                   struct connection_info *info)
188{
189    int err;
190    size_t size = dataport->size;
191    unsigned int num_frames = dataport->num_frames;
192    seL4_CPtr *frames = dataport->frames;
193
194    vm_memory_reservation_t *dataport_reservation = vm_reserve_memory_at(vm, dataport_address, size,
195                                                                         default_error_fault_callback,
196                                                                         NULL);
197    struct dataport_iterator_cookie *dataport_cookie = malloc(sizeof(struct dataport_iterator_cookie));
198    if (!dataport_cookie) {
199        ZF_LOGE("Failed to allocate dataport iterator cookie");
200        return -1;
201    }
202    dataport_cookie->vm = vm;
203    dataport_cookie->dataport_frames = frames;
204    dataport_cookie->dataport_start = dataport_address;
205    dataport_cookie->dataport_size = size;
206    err = vm_map_reservation(vm, dataport_reservation, dataport_memory_iterator, (void *)dataport_cookie);
207    if (err) {
208        ZF_LOGE("Failed to map dataport memory");
209        return -1;
210    }
211    info->dataport_address = dataport_address;
212    info->dataport_size_bits = BYTES_TO_SIZE_BITS(size);
213    return 0;
214}
215
216static void connection_consume_ack(vm_vcpu_t *vcpu, int irq, void *cookie) {}
217
218void consume_connection_event(vm_t *vm, seL4_Word event_id, bool inject_irq)
219{
220    struct connection_info *conn_info = NULL;
221    /* Search for a connection with a matching badge */
222    for (int i = 0; i < total_connections; i++) {
223        if (info[i].connection.consume_id == event_id) {
224            conn_info = &info[i];
225            break;
226        }
227    }
228    if (conn_info == NULL) {
229        /* No match */
230        return;
231    }
232    /* We have an event - update the value in the event status register */
233    uint32_t *event_registers = (uint32_t *)conn_info->event_registers;
234    /* Increment the register to indicate a signal event occured -
235     * we assume our kernel module will clear it as it consumes interrupt */
236    event_registers[EVENT_BAR_CONSUME_EVENT_REGISTER_INDEX]++;
237    if (inject_irq) {
238        /* Inject our event interrupt */
239        int err = vm_inject_irq(vm->vcpus[BOOT_VCPU], conn_info->connection_irq);
240        if (err) {
241            ZF_LOGE("Failed to inject connection irq");
242        }
243    }
244    return;
245}
246
247static int register_consume_event(vm_t *vm, crossvm_handle_t *connection, struct connection_info *conn_info)
248{
249    if (connection->consume_id != -1 && conn_info->connection_irq > 0) {
250        /* Register an irq for the crossvm connection */
251        int err = vm_register_irq(vm->vcpus[BOOT_VCPU], conn_info->connection_irq, connection_consume_ack, NULL);
252        if (err) {
253            ZF_LOGE("Failed to register IRQ for event consume");
254            return -1;
255        }
256    }
257    return 0;
258}
259
260static int initialise_connections(vm_t *vm, uintptr_t connection_base_addr, crossvm_handle_t *connections,
261                                  int num_connections, struct connection_info *info, int connection_irq)
262{
263    int err;
264    uintptr_t connection_curr_addr = connection_base_addr;
265    for (int i = 0; i < num_connections; i++) {
266        /* We need to round everything up to the largest sized resource to prevent
267         * Linux from remapping the devices, which the vpci device can't emulate.
268         */
269        crossvm_dataport_handle_t *dataport = connections[i].dataport;
270        uintptr_t dataport_size = dataport->size;
271        err = reserve_event_bar(vm, connection_curr_addr, &info[i]);
272        if (err) {
273            ZF_LOGE("Failed to create event bar (id:%d)", i);
274            return -1;
275        }
276        connection_curr_addr += dataport_size;
277        err = reserve_dataport_memory(vm, dataport, connection_curr_addr, &info[i]);
278        if (err) {
279            ZF_LOGE("Failed to create dataport bar (id %d)", i);
280            return -1;
281        }
282        /* Register a callback event consuming (if we have one) */
283        info[i].connection_irq = connection_irq;
284        err = register_consume_event(vm, &connections[i], &info[i]);
285        if (err) {
286            ZF_LOGE("Failed to register connections consume event");
287            return -1;
288        }
289        info[i].connection = connections[i];
290        if (connections[i].connection_name == NULL) {
291            connections[i].connection_name = "connector";
292        }
293        strncpy(info[i].event_registers + EVENT_BAR_DEVICE_NAME_REGISTER, connections[i].connection_name,
294                EVENT_BAR_DEVICE_NAME_MAX_LEN);
295
296        connection_curr_addr += dataport_size;
297    }
298    return 0;
299}
300
301int cross_vm_connections_init_common(vm_t *vm, uintptr_t connection_base_addr, crossvm_handle_t *connections,
302                                     int num_connections, vmm_pci_space_t *pci, alloc_free_interrupt_fn alloc_irq)
303{
304    uintptr_t guest_paddr = 0;
305    size_t guest_size = 0;
306    if (num_connections > MAX_NUM_CONNECTIONS) {
307        ZF_LOGE("Unable to register more than %d dataports", MAX_NUM_CONNECTIONS);
308        return -1;
309    }
310    int connection_irq = alloc_irq();
311    int err = initialise_connections(vm, connection_base_addr, connections, num_connections, info, connection_irq);
312    if (err) {
313        ZF_LOGE("Failed to reserve memory for dataports");
314        return -1;
315    }
316    err = construct_connection_bar(vm, info, num_connections, pci);
317    if (err) {
318        ZF_LOGE("Failed to construct pci device for dataports");
319        return -1;
320    }
321    total_connections = num_connections;
322    return 0;
323}
324