1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 8 #include "CUnit/Basic.h" 9 #include "spdk_internal/mock.h" 10 11 #include "env_dpdk/pci.c" 12 13 static void 14 pci_claim_test(struct spdk_pci_device *dev) 15 { 16 int rc = 0; 17 pid_t childPid; 18 int status, ret; 19 20 rc = spdk_pci_device_claim(dev); 21 CU_ASSERT(rc >= 0); 22 23 childPid = fork(); 24 CU_ASSERT(childPid >= 0); 25 if (childPid == 0) { 26 ret = spdk_pci_device_claim(dev); 27 CU_ASSERT(ret == -1); 28 exit(0); 29 } else { 30 waitpid(childPid, &status, 0); 31 } 32 } 33 34 static struct spdk_pci_driver ut_pci_driver; 35 36 struct ut_pci_dev { 37 struct spdk_pci_device pci; 38 char config[16]; 39 char bar[16]; 40 bool attached; 41 }; 42 43 static int 44 ut_map_bar(struct spdk_pci_device *dev, uint32_t bar, 45 void **mapped_addr, uint64_t *phys_addr, uint64_t *size) 46 { 47 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; 48 49 /* just one bar */ 50 if (bar > 0) { 51 return -1; 52 } 53 54 *mapped_addr = ut_dev->bar; 55 *phys_addr = 0; 56 *size = sizeof(ut_dev->bar); 57 return 0; 58 } 59 60 static int 61 ut_unmap_bar(struct spdk_pci_device *device, uint32_t bar, void *addr) 62 { 63 return 0; 64 } 65 66 static int 67 ut_cfg_read(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 68 { 69 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; 70 71 if (len + offset >= sizeof(ut_dev->config)) { 72 return -1; 73 } 74 75 memcpy(value, (void *)((uintptr_t)ut_dev->config + offset), len); 76 return 0; 77 } 78 79 static int 80 ut_cfg_write(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 81 { 82 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; 83 84 if (len + offset >= sizeof(ut_dev->config)) { 85 return -1; 86 } 87 88 memcpy((void *)((uintptr_t)ut_dev->config + offset), value, len); 89 return 0; 90 } 91 92 93 static int 94 ut_enum_cb(void *ctx, struct spdk_pci_device *dev) 95 { 96 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; 97 98 ut_dev->attached = true; 99 return 0; 100 } 101 102 static void 103 pci_hook_test(void) 104 { 105 struct ut_pci_dev ut_dev = {}; 106 uint32_t value_32; 107 void *bar0_vaddr; 108 uint64_t bar0_paddr, bar0_size; 109 int rc; 110 111 ut_dev.pci.type = "custom"; 112 ut_dev.pci.id.vendor_id = 0x4; 113 ut_dev.pci.id.device_id = 0x8; 114 115 /* Use add parse for initialization */ 116 spdk_pci_addr_parse(&ut_dev.pci.addr, "10000:00:01.0"); 117 CU_ASSERT(ut_dev.pci.addr.domain == 0x10000); 118 CU_ASSERT(ut_dev.pci.addr.bus == 0x0); 119 CU_ASSERT(ut_dev.pci.addr.dev == 0x1); 120 CU_ASSERT(ut_dev.pci.addr.func == 0x0); 121 122 ut_dev.pci.map_bar = ut_map_bar; 123 ut_dev.pci.unmap_bar = ut_unmap_bar; 124 ut_dev.pci.cfg_read = ut_cfg_read; 125 ut_dev.pci.cfg_write = ut_cfg_write; 126 127 /* hook the device into the PCI layer */ 128 spdk_pci_hook_device(&ut_pci_driver, &ut_dev.pci); 129 130 /* try to attach a device with the matching driver and bdf */ 131 rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr); 132 CU_ASSERT(rc == 0); 133 CU_ASSERT(ut_dev.pci.internal.attached); 134 CU_ASSERT(ut_dev.attached); 135 136 /* check PCI config writes and reads */ 137 value_32 = 0xDEADBEEF; 138 rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 0); 139 CU_ASSERT(rc == 0); 140 141 value_32 = 0x0BADF00D; 142 rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 4); 143 CU_ASSERT(rc == 0); 144 145 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 0); 146 CU_ASSERT(rc == 0); 147 CU_ASSERT(value_32 == 0xDEADBEEF); 148 CU_ASSERT(memcmp(&value_32, &ut_dev.config[0], 4) == 0); 149 150 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 4); 151 CU_ASSERT(rc == 0); 152 CU_ASSERT(value_32 == 0x0BADF00D); 153 CU_ASSERT(memcmp(&value_32, &ut_dev.config[4], 4) == 0); 154 155 /* out-of-bounds write */ 156 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, sizeof(ut_dev.config)); 157 CU_ASSERT(rc != 0); 158 159 /* map a bar */ 160 rc = spdk_pci_device_map_bar(&ut_dev.pci, 0, &bar0_vaddr, &bar0_paddr, &bar0_size); 161 CU_ASSERT(rc == 0); 162 CU_ASSERT(bar0_vaddr == ut_dev.bar); 163 CU_ASSERT(bar0_size == sizeof(ut_dev.bar)); 164 spdk_pci_device_unmap_bar(&ut_dev.pci, 0, bar0_vaddr); 165 166 /* map an inaccessible bar */ 167 rc = spdk_pci_device_map_bar(&ut_dev.pci, 1, &bar0_vaddr, &bar0_paddr, &bar0_size); 168 CU_ASSERT(rc != 0); 169 170 /* test spdk_pci_device_claim() */ 171 pci_claim_test(&ut_dev.pci); 172 173 spdk_pci_device_detach(&ut_dev.pci); 174 CU_ASSERT(!ut_dev.pci.internal.attached); 175 176 /* unhook the device */ 177 spdk_pci_unhook_device(&ut_dev.pci); 178 179 /* try to attach the same device again */ 180 rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr); 181 CU_ASSERT(rc != 0); 182 } 183 184 int 185 main(int argc, char **argv) 186 { 187 CU_pSuite suite = NULL; 188 unsigned int num_failures; 189 190 if (CU_initialize_registry() != CUE_SUCCESS) { 191 return CU_get_error(); 192 } 193 194 suite = CU_add_suite("pci", NULL, NULL); 195 if (suite == NULL) { 196 CU_cleanup_registry(); 197 return CU_get_error(); 198 } 199 200 if ( 201 CU_add_test(suite, "pci_hook", pci_hook_test) == NULL 202 ) { 203 CU_cleanup_registry(); 204 return CU_get_error(); 205 } 206 207 CU_basic_set_mode(CU_BRM_VERBOSE); 208 CU_basic_run_tests(); 209 num_failures = CU_get_number_of_failures(); 210 CU_cleanup_registry(); 211 return num_failures; 212 } 213