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 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 int 103 ut_attach_cb(const struct spdk_pci_addr *addr) 104 { 105 return -ENODEV; 106 } 107 108 static void 109 ut_detach_cb(struct spdk_pci_device *dev) 110 { 111 } 112 113 static struct spdk_pci_device_provider g_ut_provider = { 114 .name = "custom", 115 .attach_cb = ut_attach_cb, 116 .detach_cb = ut_detach_cb, 117 }; 118 119 SPDK_PCI_REGISTER_DEVICE_PROVIDER(ut, &g_ut_provider); 120 121 static void 122 pci_hook_test(void) 123 { 124 struct ut_pci_dev ut_dev = {}; 125 uint32_t value_32; 126 void *bar0_vaddr; 127 uint64_t bar0_paddr, bar0_size; 128 int rc; 129 130 ut_dev.pci.type = "custom"; 131 ut_dev.pci.id.vendor_id = 0x4; 132 ut_dev.pci.id.device_id = 0x8; 133 134 /* Use add parse for initialization */ 135 spdk_pci_addr_parse(&ut_dev.pci.addr, "10000:00:01.0"); 136 CU_ASSERT(ut_dev.pci.addr.domain == 0x10000); 137 CU_ASSERT(ut_dev.pci.addr.bus == 0x0); 138 CU_ASSERT(ut_dev.pci.addr.dev == 0x1); 139 CU_ASSERT(ut_dev.pci.addr.func == 0x0); 140 141 ut_dev.pci.map_bar = ut_map_bar; 142 ut_dev.pci.unmap_bar = ut_unmap_bar; 143 ut_dev.pci.cfg_read = ut_cfg_read; 144 ut_dev.pci.cfg_write = ut_cfg_write; 145 146 /* hook the device into the PCI layer */ 147 rc = spdk_pci_hook_device(&ut_pci_driver, &ut_dev.pci); 148 CU_ASSERT_EQUAL(rc, 0); 149 150 /* try to attach a device with the matching driver and bdf */ 151 rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr); 152 CU_ASSERT(rc == 0); 153 CU_ASSERT(ut_dev.pci.internal.attached); 154 CU_ASSERT(ut_dev.attached); 155 156 /* check PCI config writes and reads */ 157 value_32 = 0xDEADBEEF; 158 rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 0); 159 CU_ASSERT(rc == 0); 160 161 value_32 = 0x0BADF00D; 162 rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 4); 163 CU_ASSERT(rc == 0); 164 165 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 0); 166 CU_ASSERT(rc == 0); 167 CU_ASSERT(value_32 == 0xDEADBEEF); 168 CU_ASSERT(memcmp(&value_32, &ut_dev.config[0], 4) == 0); 169 170 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 4); 171 CU_ASSERT(rc == 0); 172 CU_ASSERT(value_32 == 0x0BADF00D); 173 CU_ASSERT(memcmp(&value_32, &ut_dev.config[4], 4) == 0); 174 175 /* out-of-bounds write */ 176 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, sizeof(ut_dev.config)); 177 CU_ASSERT(rc != 0); 178 179 /* map a bar */ 180 rc = spdk_pci_device_map_bar(&ut_dev.pci, 0, &bar0_vaddr, &bar0_paddr, &bar0_size); 181 CU_ASSERT(rc == 0); 182 CU_ASSERT(bar0_vaddr == ut_dev.bar); 183 CU_ASSERT(bar0_size == sizeof(ut_dev.bar)); 184 spdk_pci_device_unmap_bar(&ut_dev.pci, 0, bar0_vaddr); 185 186 /* map an inaccessible bar */ 187 rc = spdk_pci_device_map_bar(&ut_dev.pci, 1, &bar0_vaddr, &bar0_paddr, &bar0_size); 188 CU_ASSERT(rc != 0); 189 190 /* test spdk_pci_device_claim() */ 191 pci_claim_test(&ut_dev.pci); 192 193 spdk_pci_device_detach(&ut_dev.pci); 194 CU_ASSERT(!ut_dev.pci.internal.attached); 195 196 /* unhook the device */ 197 spdk_pci_unhook_device(&ut_dev.pci); 198 199 /* try to attach the same device again */ 200 rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr); 201 CU_ASSERT(rc != 0); 202 } 203 204 int 205 main(int argc, char **argv) 206 { 207 CU_pSuite suite = NULL; 208 unsigned int num_failures; 209 210 if (CU_initialize_registry() != CUE_SUCCESS) { 211 return CU_get_error(); 212 } 213 214 suite = CU_add_suite("pci", NULL, NULL); 215 if (suite == NULL) { 216 CU_cleanup_registry(); 217 return CU_get_error(); 218 } 219 220 if ( 221 CU_add_test(suite, "pci_hook", pci_hook_test) == NULL 222 ) { 223 CU_cleanup_registry(); 224 return CU_get_error(); 225 } 226 227 CU_basic_set_mode(CU_BRM_VERBOSE); 228 CU_basic_run_tests(); 229 num_failures = CU_get_number_of_failures(); 230 CU_cleanup_registry(); 231 return num_failures; 232 } 233