xref: /spdk/test/env/pci/pci_ut.c (revision fecffda6ecf8853b82edccde429b68252f0a62c5)
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