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