1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10 11#include <platsupport/io.h> 12 13#include <sel4vmmplatsupport/drivers/virtio.h> 14#include <sel4vmmplatsupport/drivers/virtio_con.h> 15 16#include <pci/helper.h> 17#include <sel4vmmplatsupport/drivers/pci_helper.h> 18 19#define QUEUE_SIZE 128 20 21static ps_io_ops_t ops; 22 23static int virtio_con_io_in(void *cookie, unsigned int port_no, unsigned int size, unsigned int *result) 24{ 25 virtio_con_t *con = (virtio_con_t *)cookie; 26 unsigned int offset = port_no - con->iobase; 27 unsigned int val; 28 int err = con->emul->io_in(con->emul, offset, size, &val); 29 if (err) { 30 return err; 31 } 32 *result = val; 33 return 0; 34} 35 36static int virtio_con_io_out(void *cookie, unsigned int port_no, unsigned int size, unsigned int value) 37{ 38 int ret; 39 virtio_con_t *con = (virtio_con_t *)cookie; 40 unsigned int offset = port_no - con->iobase; 41 ret = con->emul->io_out(con->emul, offset, size, value); 42 return 0; 43} 44 45static int emul_con_driver_init(struct console_passthrough *driver, ps_io_ops_t io_ops, void *config) 46{ 47 virtio_con_t *con = (virtio_con_t *)config; 48 *driver = con->emul_driver_funcs; 49 return 0; 50} 51 52static vmm_pci_entry_t vmm_virtio_console_pci_bar(unsigned int iobase, 53 size_t iobase_size_bits, unsigned int interrupt_pin, unsigned int interrupt_line) 54{ 55 vmm_pci_device_def_t *pci_config; 56 int err = ps_calloc(&ops.malloc_ops, 1, sizeof(*pci_config), (void **)&pci_config); 57 ZF_LOGF_IF(err, "Failed to allocate pci config"); 58 *pci_config = (vmm_pci_device_def_t) { 59 .vendor_id = VIRTIO_PCI_VENDOR_ID, 60 .device_id = VIRTIO_CONSOLE_PCI_DEVICE_ID, 61 .command = PCI_COMMAND_IO | PCI_COMMAND_MEMORY, 62 .header_type = PCI_HEADER_TYPE_NORMAL, 63 .subsystem_vendor_id = VIRTIO_PCI_SUBSYSTEM_VENDOR_ID, 64 .subsystem_id = VIRTIO_ID_CONSOLE, 65 .interrupt_pin = interrupt_pin, 66 .interrupt_line = interrupt_line, 67 .bar0 = iobase | PCI_BASE_ADDRESS_SPACE_IO, 68 .cache_line_size = 64, 69 .latency_timer = 64, 70 .prog_if = VIRTIO_PCI_CLASS_CONSOLE & 0xff, 71 .subclass = (VIRTIO_PCI_CLASS_CONSOLE >> 8) & 0xff, 72 .class_code = (VIRTIO_PCI_CLASS_CONSOLE >> 16) & 0xff, 73 }; 74 vmm_pci_entry_t entry = (vmm_pci_entry_t) { 75 .cookie = pci_config, 76 .ioread = vmm_pci_mem_device_read, 77 .iowrite = vmm_pci_mem_device_write 78 }; 79 80 vmm_pci_bar_t bars[1] = {{ 81 .mem_type = NON_MEM, 82 .address = iobase, 83 .size_bits = iobase_size_bits 84 } 85 }; 86 return vmm_pci_create_passthrough_bar_emulation(entry, 1, bars); 87} 88 89virtio_con_t *common_make_virtio_con(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *ioport, 90 ioport_range_t ioport_range, ioport_type_t port_type, unsigned int interrupt_pin, unsigned int interrupt_line, 91 struct console_passthrough backend) 92{ 93 int err = ps_new_stdlib_malloc_ops(&ops.malloc_ops); 94 ZF_LOGF_IF(err, "Failed to get malloc ops"); 95 96 virtio_con_t *con; 97 err = ps_calloc(&ops.malloc_ops, 1, sizeof(*con), (void **)&con); 98 ZF_LOGF_IF(err, "Failed to allocate virtio con"); 99 100 ioport_interface_t virtio_io_interface = {con, virtio_con_io_in, virtio_con_io_out, "VIRTIO CON"}; 101 ioport_entry_t *io_entry = vmm_io_port_add_handler(ioport, ioport_range, virtio_io_interface, port_type); 102 if (!io_entry) { 103 ZF_LOGE("Failed to add vmm io port handler"); 104 return NULL; 105 } 106 107 size_t iobase_size_bits = BYTES_TO_SIZE_BITS(io_entry->range.size); 108 con->iobase = io_entry->range.start; 109 vmm_pci_entry_t con_entry = vmm_virtio_console_pci_bar(io_entry->range.start, iobase_size_bits, interrupt_pin, 110 interrupt_line); 111 vmm_pci_add_entry(pci, con_entry, NULL); 112 113 ps_io_ops_t ioops; 114 con->emul_driver_funcs = backend; 115 con->emul = virtio_emul_init(ioops, QUEUE_SIZE, vm, emul_con_driver_init, con, VIRTIO_CONSOLE); 116 117 assert(con->emul); 118 return con; 119} 120