1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7/* VMM PCI Driver, which manages the host's PCI devices, and handles guest OS PCI config space 8 * read & writes. 9 */ 10 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14 15#include <sel4/sel4.h> 16#include <pci/pci.h> 17#include <pci/helper.h> 18 19#include <sel4vmmplatsupport/drivers/pci.h> 20#include <sel4vmmplatsupport/drivers/pci_helper.h> 21 22#define NUM_DEVICES 32 23#define NUM_FUNCTIONS 8 24 25int vmm_pci_init(vmm_pci_space_t **space) 26{ 27 vmm_pci_space_t *pci_space = (vmm_pci_space_t *)calloc(1, sizeof(vmm_pci_space_t)); 28 if (!pci_space) { 29 ZF_LOGE("Failed to calloc memory for pci space"); 30 return -1; 31 } 32 33 for (int i = 0; i < NUM_DEVICES; i++) { 34 for (int j = 0; j < NUM_FUNCTIONS; j++) { 35 pci_space->bus0[i][j] = NULL; 36 } 37 } 38 pci_space->conf_port_addr = 0; 39 /* Define the initial PCI bridge */ 40 vmm_pci_device_def_t *bridge = calloc(1, sizeof(*bridge)); 41 if (!bridge) { 42 ZF_LOGE("Failed to calloc memory for pci bridge"); 43 return -1; 44 } 45 define_pci_host_bridge(bridge); 46 *space = pci_space; 47 return vmm_pci_add_entry(pci_space, (vmm_pci_entry_t) { 48 .cookie = bridge, .ioread = vmm_pci_mem_device_read, .iowrite = vmm_pci_entry_ignore_write 49 }, NULL); 50} 51 52int vmm_pci_add_entry(vmm_pci_space_t *space, vmm_pci_entry_t entry, vmm_pci_address_t *addr) 53{ 54 /* Find empty dev */ 55 for (int i = 0; i < 32; i++) { 56 if (!space->bus0[i][0]) { 57 /* Allocate an entry */ 58 space->bus0[i][0] = calloc(1, sizeof(entry)); 59 60 *space->bus0[i][0] = entry; 61 /* Report addr if reqeusted */ 62 if (addr) { 63 *addr = (vmm_pci_address_t) { 64 .bus = 0, .dev = i, .fun = 0 65 }; 66 } 67 ZF_LOGI("Adding virtual PCI device at %02x:%02x.%d", 0, i, 0); 68 return 0; 69 } 70 } 71 ZF_LOGE("No free device slot on bus 0 to add virtual pci device"); 72 return -1; 73} 74 75void make_addr_reg_from_config(uint32_t conf, vmm_pci_address_t *addr, uint8_t *reg) 76{ 77 addr->bus = (conf >> 16) & MASK(8); 78 addr->dev = (conf >> 11) & MASK(5); 79 addr->fun = (conf >> 8) & MASK(3); 80 *reg = conf & MASK(8); 81} 82 83vmm_pci_entry_t *find_device(vmm_pci_space_t *self, vmm_pci_address_t addr) 84{ 85 if (addr.bus != 0 || addr.dev >= 32 || addr.fun >= 8) { 86 return NULL; 87 } 88 return self->bus0[addr.dev][addr.fun]; 89} 90