1 /*
2  * Unit tests for the generic vPCI handler code.
3  *
4  * Copyright (C) 2017 Citrix Systems R&D
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms and conditions of the GNU General Public
8  * License, version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "emul.h"
20 
21 /* Single vcpu (current), and single domain with a single PCI device. */
22 static struct vpci vpci;
23 
24 const static struct domain d;
25 
26 const struct pci_dev test_pdev = {
27     .vpci = &vpci,
28 };
29 
30 const static struct vcpu v = {
31     .domain = &d
32 };
33 
34 const struct vcpu *current = &v;
35 
36 /* Dummy hooks, write stores data, read fetches it. */
vpci_read8(const struct pci_dev * pdev,unsigned int reg,void * data)37 static uint32_t vpci_read8(const struct pci_dev *pdev, unsigned int reg,
38                            void *data)
39 {
40     return *(uint8_t *)data;
41 }
42 
vpci_write8(const struct pci_dev * pdev,unsigned int reg,uint32_t val,void * data)43 static void vpci_write8(const struct pci_dev *pdev, unsigned int reg,
44                         uint32_t val, void *data)
45 {
46     *(uint8_t *)data = val;
47 }
48 
vpci_read16(const struct pci_dev * pdev,unsigned int reg,void * data)49 static uint32_t vpci_read16(const struct pci_dev *pdev, unsigned int reg,
50                             void *data)
51 {
52     return *(uint16_t *)data;
53 }
54 
vpci_write16(const struct pci_dev * pdev,unsigned int reg,uint32_t val,void * data)55 static void vpci_write16(const struct pci_dev *pdev, unsigned int reg,
56                          uint32_t val, void *data)
57 {
58     *(uint16_t *)data = val;
59 }
60 
vpci_read32(const struct pci_dev * pdev,unsigned int reg,void * data)61 static uint32_t vpci_read32(const struct pci_dev *pdev, unsigned int reg,
62                             void *data)
63 {
64     return *(uint32_t *)data;
65 }
66 
vpci_write32(const struct pci_dev * pdev,unsigned int reg,uint32_t val,void * data)67 static void vpci_write32(const struct pci_dev *pdev, unsigned int reg,
68                          uint32_t val, void *data)
69 {
70     *(uint32_t *)data = val;
71 }
72 
73 #define VPCI_READ(reg, size, data) ({                           \
74     data = vpci_read((pci_sbdf_t){ .sbdf = 0 }, reg, size);     \
75 })
76 
77 #define VPCI_READ_CHECK(reg, size, expected) ({                 \
78     uint32_t rd;                                                \
79                                                                 \
80     VPCI_READ(reg, size, rd);                                   \
81     assert(rd == (expected));                                   \
82 })
83 
84 #define VPCI_WRITE(reg, size, data) ({                          \
85     vpci_write((pci_sbdf_t){ .sbdf = 0 }, reg, size, data);     \
86 })
87 
88 #define VPCI_WRITE_CHECK(reg, size, data) ({                    \
89     VPCI_WRITE(reg, size, data);                                \
90     VPCI_READ_CHECK(reg, size, data);                           \
91 })
92 
93 #define VPCI_ADD_REG(fread, fwrite, off, size, store)                       \
94     assert(!vpci_add_register(test_pdev.vpci, fread, fwrite, off, size,     \
95                               &store))
96 
97 #define VPCI_ADD_INVALID_REG(fread, fwrite, off, size)                      \
98     assert(vpci_add_register(test_pdev.vpci, fread, fwrite, off, size, NULL))
99 
100 #define VPCI_REMOVE_REG(off, size)                                          \
101     assert(!vpci_remove_register(test_pdev.vpci, off, size))
102 
103 #define VPCI_REMOVE_INVALID_REG(off, size)                                  \
104     assert(vpci_remove_register(test_pdev.vpci, off, size))
105 
106 /* Read a 32b register using all possible sizes. */
multiread4_check(unsigned int reg,uint32_t val)107 void multiread4_check(unsigned int reg, uint32_t val)
108 {
109     unsigned int i;
110 
111     /* Read using bytes. */
112     for ( i = 0; i < 4; i++ )
113         VPCI_READ_CHECK(reg + i, 1, (val >> (i * 8)) & UINT8_MAX);
114 
115     /* Read using 2bytes. */
116     for ( i = 0; i < 2; i++ )
117         VPCI_READ_CHECK(reg + i * 2, 2, (val >> (i * 2 * 8)) & UINT16_MAX);
118 
119     VPCI_READ_CHECK(reg, 4, val);
120 }
121 
multiwrite4_check(unsigned int reg)122 void multiwrite4_check(unsigned int reg)
123 {
124     unsigned int i;
125     uint32_t val = 0xa2f51732;
126 
127     /* Write using bytes. */
128     for ( i = 0; i < 4; i++ )
129         VPCI_WRITE_CHECK(reg + i, 1, (val >> (i * 8)) & UINT8_MAX);
130     multiread4_check(reg, val);
131 
132     /* Change the value each time to be sure writes work fine. */
133     val = 0x2b836fda;
134     /* Write using 2bytes. */
135     for ( i = 0; i < 2; i++ )
136         VPCI_WRITE_CHECK(reg + i * 2, 2, (val >> (i * 2 * 8)) & UINT16_MAX);
137     multiread4_check(reg, val);
138 
139     val = 0xc4693beb;
140     VPCI_WRITE_CHECK(reg, 4, val);
141     multiread4_check(reg, val);
142 }
143 
144 int
main(int argc,char ** argv)145 main(int argc, char **argv)
146 {
147     /* Index storage by offset. */
148     uint32_t r0 = 0xdeadbeef;
149     uint8_t r5 = 0xef;
150     uint8_t r6 = 0xbe;
151     uint8_t r7 = 0xef;
152     uint16_t r12 = 0x8696;
153     uint8_t r16[4] = { };
154     uint16_t r20[2] = { };
155     uint32_t r24 = 0;
156     uint8_t r28, r30;
157     unsigned int i;
158     int rc;
159 
160     INIT_LIST_HEAD(&vpci.handlers);
161     spin_lock_init(&vpci.lock);
162 
163     VPCI_ADD_REG(vpci_read32, vpci_write32, 0, 4, r0);
164     VPCI_READ_CHECK(0, 4, r0);
165     VPCI_WRITE_CHECK(0, 4, 0xbcbcbcbc);
166 
167     VPCI_ADD_REG(vpci_read8, vpci_write8, 5, 1, r5);
168     VPCI_READ_CHECK(5, 1, r5);
169     VPCI_WRITE_CHECK(5, 1, 0xba);
170 
171     VPCI_ADD_REG(vpci_read8, vpci_write8, 6, 1, r6);
172     VPCI_READ_CHECK(6, 1, r6);
173     VPCI_WRITE_CHECK(6, 1, 0xba);
174 
175     VPCI_ADD_REG(vpci_read8, vpci_write8, 7, 1, r7);
176     VPCI_READ_CHECK(7, 1, r7);
177     VPCI_WRITE_CHECK(7, 1, 0xbd);
178 
179     VPCI_ADD_REG(vpci_read16, vpci_write16, 12, 2, r12);
180     VPCI_READ_CHECK(12, 2, r12);
181     VPCI_READ_CHECK(12, 4, 0xffff8696);
182 
183     /*
184      * At this point we have the following layout:
185      *
186      * Note that this refers to the position of the variables,
187      * but the value has already changed from the one given at
188      * initialization time because write tests have been performed.
189      *
190      * 32    24    16     8     0
191      *  +-----+-----+-----+-----+
192      *  |          r0           | 0
193      *  +-----+-----+-----+-----+
194      *  | r7  |  r6 |  r5 |/////| 32
195      *  +-----+-----+-----+-----|
196      *  |///////////////////////| 64
197      *  +-----------+-----------+
198      *  |///////////|    r12    | 96
199      *  +-----------+-----------+
200      *             ...
201      *  / = unhandled.
202      */
203 
204     /* Try to add an overlapping register handler. */
205     VPCI_ADD_INVALID_REG(vpci_read32, vpci_write32, 4, 4);
206 
207     /* Try to add a non-aligned register. */
208     VPCI_ADD_INVALID_REG(vpci_read16, vpci_write16, 15, 2);
209 
210     /* Try to add a register with wrong size. */
211     VPCI_ADD_INVALID_REG(vpci_read16, vpci_write16, 8, 3);
212 
213     /* Try to add a register with missing handlers. */
214     VPCI_ADD_INVALID_REG(NULL, NULL, 8, 2);
215 
216     /* Read/write of unset register. */
217     VPCI_READ_CHECK(8, 4, 0xffffffff);
218     VPCI_READ_CHECK(8, 2, 0xffff);
219     VPCI_READ_CHECK(8, 1, 0xff);
220     VPCI_WRITE(10, 2, 0xbeef);
221     VPCI_READ_CHECK(10, 2, 0xffff);
222 
223     /* Read of multiple registers */
224     VPCI_WRITE_CHECK(7, 1, 0xbd);
225     VPCI_READ_CHECK(4, 4, 0xbdbabaff);
226 
227     /* Partial read of a register. */
228     VPCI_WRITE_CHECK(0, 4, 0x1a1b1c1d);
229     VPCI_READ_CHECK(2, 1, 0x1b);
230     VPCI_READ_CHECK(6, 2, 0xbdba);
231 
232     /* Write of multiple registers. */
233     VPCI_WRITE_CHECK(4, 4, 0xaabbccff);
234 
235     /* Partial write of a register. */
236     VPCI_WRITE_CHECK(2, 1, 0xfe);
237     VPCI_WRITE_CHECK(6, 2, 0xfebc);
238 
239     /*
240      * Test all possible read/write size combinations.
241      *
242      * Place 4 1B registers at 128bits (16B), 2 2B registers at 160bits
243      * (20B) and finally 1 4B register at 192bits (24B).
244      *
245      * Then perform all possible write and read sizes on each of them.
246      *
247      *               ...
248      * 32     24     16      8      0
249      *  +------+------+------+------+
250      *  |r16[3]|r16[2]|r16[1]|r16[0]| 16
251      *  +------+------+------+------+
252      *  |    r20[1]   |    r20[0]   | 20
253      *  +-------------+-------------|
254      *  |            r24            | 24
255      *  +-------------+-------------+
256      *
257      */
258     VPCI_ADD_REG(vpci_read8, vpci_write8, 16, 1, r16[0]);
259     VPCI_ADD_REG(vpci_read8, vpci_write8, 17, 1, r16[1]);
260     VPCI_ADD_REG(vpci_read8, vpci_write8, 18, 1, r16[2]);
261     VPCI_ADD_REG(vpci_read8, vpci_write8, 19, 1, r16[3]);
262 
263     VPCI_ADD_REG(vpci_read16, vpci_write16, 20, 2, r20[0]);
264     VPCI_ADD_REG(vpci_read16, vpci_write16, 22, 2, r20[1]);
265 
266     VPCI_ADD_REG(vpci_read32, vpci_write32, 24, 4, r24);
267 
268     /* Check the initial value is 0. */
269     multiread4_check(16, 0);
270     multiread4_check(20, 0);
271     multiread4_check(24, 0);
272 
273     multiwrite4_check(16);
274     multiwrite4_check(20);
275     multiwrite4_check(24);
276 
277     /*
278      * Check multiple non-consecutive gaps on the same read/write:
279      *
280      * 32     24     16      8      0
281      *  +------+------+------+------+
282      *  |//////|  r30 |//////|  r28 | 28
283      *  +------+------+------+------+
284      *
285      */
286     VPCI_ADD_REG(vpci_read8, vpci_write8, 28, 1, r28);
287     VPCI_ADD_REG(vpci_read8, vpci_write8, 30, 1, r30);
288     VPCI_WRITE_CHECK(28, 4, 0xffacffdc);
289 
290     /* Finally try to remove a couple of registers. */
291     VPCI_REMOVE_REG(28, 1);
292     VPCI_REMOVE_REG(24, 4);
293     VPCI_REMOVE_REG(12, 2);
294 
295     VPCI_REMOVE_INVALID_REG(20, 1);
296     VPCI_REMOVE_INVALID_REG(16, 2);
297     VPCI_REMOVE_INVALID_REG(30, 2);
298 
299     return 0;
300 }
301 
302 /*
303  * Local variables:
304  * mode: C
305  * c-file-style: "BSD"
306  * c-basic-offset: 4
307  * indent-tabs-mode: nil
308  * End:
309  */
310