1 /*
2 * Generic functionality for handling accesses to the PCI configuration space
3 * from guests.
4 *
5 * Copyright (C) 2017 Citrix Systems R&D
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms and conditions of the GNU General Public
9 * License, version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with this program; If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <xen/sched.h>
21 #include <xen/vpci.h>
22
23 /* Internal struct to store the emulated PCI registers. */
24 struct vpci_register {
25 vpci_read_t *read;
26 vpci_write_t *write;
27 unsigned int size;
28 unsigned int offset;
29 void *private;
30 struct list_head node;
31 };
32
33 #ifdef __XEN__
34 extern vpci_register_init_t *const __start_vpci_array[];
35 extern vpci_register_init_t *const __end_vpci_array[];
36 #define NUM_VPCI_INIT (__end_vpci_array - __start_vpci_array)
37
vpci_remove_device(struct pci_dev * pdev)38 void vpci_remove_device(struct pci_dev *pdev)
39 {
40 spin_lock(&pdev->vpci->lock);
41 while ( !list_empty(&pdev->vpci->handlers) )
42 {
43 struct vpci_register *r = list_first_entry(&pdev->vpci->handlers,
44 struct vpci_register,
45 node);
46
47 list_del(&r->node);
48 xfree(r);
49 }
50 spin_unlock(&pdev->vpci->lock);
51 xfree(pdev->vpci->msix);
52 xfree(pdev->vpci->msi);
53 xfree(pdev->vpci);
54 pdev->vpci = NULL;
55 }
56
vpci_add_handlers(struct pci_dev * pdev)57 int __hwdom_init vpci_add_handlers(struct pci_dev *pdev)
58 {
59 unsigned int i;
60 int rc = 0;
61
62 if ( !has_vpci(pdev->domain) )
63 return 0;
64
65 pdev->vpci = xzalloc(struct vpci);
66 if ( !pdev->vpci )
67 return -ENOMEM;
68
69 INIT_LIST_HEAD(&pdev->vpci->handlers);
70 spin_lock_init(&pdev->vpci->lock);
71
72 for ( i = 0; i < NUM_VPCI_INIT; i++ )
73 {
74 rc = __start_vpci_array[i](pdev);
75 if ( rc )
76 break;
77 }
78
79 if ( rc )
80 vpci_remove_device(pdev);
81
82 return rc;
83 }
84 #endif /* __XEN__ */
85
vpci_register_cmp(const struct vpci_register * r1,const struct vpci_register * r2)86 static int vpci_register_cmp(const struct vpci_register *r1,
87 const struct vpci_register *r2)
88 {
89 /* Return 0 if registers overlap. */
90 if ( r1->offset < r2->offset + r2->size &&
91 r2->offset < r1->offset + r1->size )
92 return 0;
93 if ( r1->offset < r2->offset )
94 return -1;
95 if ( r1->offset > r2->offset )
96 return 1;
97
98 ASSERT_UNREACHABLE();
99 return 0;
100 }
101
102 /* Dummy hooks, writes are ignored, reads return 1's */
vpci_ignored_read(const struct pci_dev * pdev,unsigned int reg,void * data)103 static uint32_t vpci_ignored_read(const struct pci_dev *pdev, unsigned int reg,
104 void *data)
105 {
106 return ~(uint32_t)0;
107 }
108
vpci_ignored_write(const struct pci_dev * pdev,unsigned int reg,uint32_t val,void * data)109 static void vpci_ignored_write(const struct pci_dev *pdev, unsigned int reg,
110 uint32_t val, void *data)
111 {
112 }
113
vpci_hw_read16(const struct pci_dev * pdev,unsigned int reg,void * data)114 uint32_t vpci_hw_read16(const struct pci_dev *pdev, unsigned int reg,
115 void *data)
116 {
117 return pci_conf_read16(pdev->sbdf, reg);
118 }
119
vpci_hw_read32(const struct pci_dev * pdev,unsigned int reg,void * data)120 uint32_t vpci_hw_read32(const struct pci_dev *pdev, unsigned int reg,
121 void *data)
122 {
123 return pci_conf_read32(pdev->sbdf, reg);
124 }
125
vpci_add_register(struct vpci * vpci,vpci_read_t * read_handler,vpci_write_t * write_handler,unsigned int offset,unsigned int size,void * data)126 int vpci_add_register(struct vpci *vpci, vpci_read_t *read_handler,
127 vpci_write_t *write_handler, unsigned int offset,
128 unsigned int size, void *data)
129 {
130 struct list_head *prev;
131 struct vpci_register *r;
132
133 /* Some sanity checks. */
134 if ( (size != 1 && size != 2 && size != 4) ||
135 offset >= PCI_CFG_SPACE_EXP_SIZE || (offset & (size - 1)) ||
136 (!read_handler && !write_handler) )
137 return -EINVAL;
138
139 r = xmalloc(struct vpci_register);
140 if ( !r )
141 return -ENOMEM;
142
143 r->read = read_handler ?: vpci_ignored_read;
144 r->write = write_handler ?: vpci_ignored_write;
145 r->size = size;
146 r->offset = offset;
147 r->private = data;
148
149 spin_lock(&vpci->lock);
150
151 /* The list of handlers must be kept sorted at all times. */
152 list_for_each ( prev, &vpci->handlers )
153 {
154 const struct vpci_register *this =
155 list_entry(prev, const struct vpci_register, node);
156 int cmp = vpci_register_cmp(r, this);
157
158 if ( cmp < 0 )
159 break;
160 if ( cmp == 0 )
161 {
162 spin_unlock(&vpci->lock);
163 xfree(r);
164 return -EEXIST;
165 }
166 }
167
168 list_add_tail(&r->node, prev);
169 spin_unlock(&vpci->lock);
170
171 return 0;
172 }
173
vpci_remove_register(struct vpci * vpci,unsigned int offset,unsigned int size)174 int vpci_remove_register(struct vpci *vpci, unsigned int offset,
175 unsigned int size)
176 {
177 const struct vpci_register r = { .offset = offset, .size = size };
178 struct vpci_register *rm;
179
180 spin_lock(&vpci->lock);
181 list_for_each_entry ( rm, &vpci->handlers, node )
182 {
183 int cmp = vpci_register_cmp(&r, rm);
184
185 /*
186 * NB: do not use a switch so that we can use break to
187 * get out of the list loop earlier if required.
188 */
189 if ( !cmp && rm->offset == offset && rm->size == size )
190 {
191 list_del(&rm->node);
192 spin_unlock(&vpci->lock);
193 xfree(rm);
194 return 0;
195 }
196 if ( cmp <= 0 )
197 break;
198 }
199 spin_unlock(&vpci->lock);
200
201 return -ENOENT;
202 }
203
204 /* Wrappers for performing reads/writes to the underlying hardware. */
vpci_read_hw(pci_sbdf_t sbdf,unsigned int reg,unsigned int size)205 static uint32_t vpci_read_hw(pci_sbdf_t sbdf, unsigned int reg,
206 unsigned int size)
207 {
208 uint32_t data;
209
210 switch ( size )
211 {
212 case 4:
213 data = pci_conf_read32(sbdf, reg);
214 break;
215
216 case 3:
217 /*
218 * This is possible because a 4byte read can have 1byte trapped and
219 * the rest passed-through.
220 */
221 if ( reg & 1 )
222 {
223 data = pci_conf_read8(sbdf, reg);
224 data |= pci_conf_read16(sbdf, reg + 1) << 8;
225 }
226 else
227 {
228 data = pci_conf_read16(sbdf, reg);
229 data |= pci_conf_read8(sbdf, reg + 2) << 16;
230 }
231 break;
232
233 case 2:
234 data = pci_conf_read16(sbdf, reg);
235 break;
236
237 case 1:
238 data = pci_conf_read8(sbdf, reg);
239 break;
240
241 default:
242 ASSERT_UNREACHABLE();
243 data = ~(uint32_t)0;
244 break;
245 }
246
247 return data;
248 }
249
vpci_write_hw(pci_sbdf_t sbdf,unsigned int reg,unsigned int size,uint32_t data)250 static void vpci_write_hw(pci_sbdf_t sbdf, unsigned int reg, unsigned int size,
251 uint32_t data)
252 {
253 switch ( size )
254 {
255 case 4:
256 pci_conf_write32(sbdf, reg, data);
257 break;
258
259 case 3:
260 /*
261 * This is possible because a 4byte write can have 1byte trapped and
262 * the rest passed-through.
263 */
264 if ( reg & 1 )
265 {
266 pci_conf_write8(sbdf, reg, data);
267 pci_conf_write16(sbdf, reg + 1, data >> 8);
268 }
269 else
270 {
271 pci_conf_write16(sbdf, reg, data);
272 pci_conf_write8(sbdf, reg + 2, data >> 16);
273 }
274 break;
275
276 case 2:
277 pci_conf_write16(sbdf, reg, data);
278 break;
279
280 case 1:
281 pci_conf_write8(sbdf, reg, data);
282 break;
283
284 default:
285 ASSERT_UNREACHABLE();
286 break;
287 }
288 }
289
290 /*
291 * Merge new data into a partial result.
292 *
293 * Copy the value found in 'new' from [0, size) left shifted by
294 * 'offset' into 'data'. Note that both 'size' and 'offset' are
295 * in byte units.
296 */
merge_result(uint32_t data,uint32_t new,unsigned int size,unsigned int offset)297 static uint32_t merge_result(uint32_t data, uint32_t new, unsigned int size,
298 unsigned int offset)
299 {
300 uint32_t mask = 0xffffffff >> (32 - 8 * size);
301
302 return (data & ~(mask << (offset * 8))) | ((new & mask) << (offset * 8));
303 }
304
vpci_read(pci_sbdf_t sbdf,unsigned int reg,unsigned int size)305 uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, unsigned int size)
306 {
307 const struct domain *d = current->domain;
308 const struct pci_dev *pdev;
309 const struct vpci_register *r;
310 unsigned int data_offset = 0;
311 uint32_t data = ~(uint32_t)0;
312
313 if ( !size )
314 {
315 ASSERT_UNREACHABLE();
316 return data;
317 }
318
319 /* Find the PCI dev matching the address. */
320 pdev = pci_get_pdev_by_domain(d, sbdf.seg, sbdf.bus, sbdf.devfn);
321 if ( !pdev )
322 return vpci_read_hw(sbdf, reg, size);
323
324 spin_lock(&pdev->vpci->lock);
325
326 /* Read from the hardware or the emulated register handlers. */
327 list_for_each_entry ( r, &pdev->vpci->handlers, node )
328 {
329 const struct vpci_register emu = {
330 .offset = reg + data_offset,
331 .size = size - data_offset
332 };
333 int cmp = vpci_register_cmp(&emu, r);
334 uint32_t val;
335 unsigned int read_size;
336
337 if ( cmp < 0 )
338 break;
339 if ( cmp > 0 )
340 continue;
341
342 if ( emu.offset < r->offset )
343 {
344 /* Heading gap, read partial content from hardware. */
345 read_size = r->offset - emu.offset;
346 val = vpci_read_hw(sbdf, emu.offset, read_size);
347 data = merge_result(data, val, read_size, data_offset);
348 data_offset += read_size;
349 }
350
351 val = r->read(pdev, r->offset, r->private);
352
353 /* Check if the read is in the middle of a register. */
354 if ( r->offset < emu.offset )
355 val >>= (emu.offset - r->offset) * 8;
356
357 /* Find the intersection size between the two sets. */
358 read_size = min(emu.offset + emu.size, r->offset + r->size) -
359 max(emu.offset, r->offset);
360 /* Merge the emulated data into the native read value. */
361 data = merge_result(data, val, read_size, data_offset);
362 data_offset += read_size;
363 if ( data_offset == size )
364 break;
365 ASSERT(data_offset < size);
366 }
367
368 if ( data_offset < size )
369 {
370 /* Tailing gap, read the remaining. */
371 uint32_t tmp_data = vpci_read_hw(sbdf, reg + data_offset,
372 size - data_offset);
373
374 data = merge_result(data, tmp_data, size - data_offset, data_offset);
375 }
376 spin_unlock(&pdev->vpci->lock);
377
378 return data & (0xffffffff >> (32 - 8 * size));
379 }
380
381 /*
382 * Perform a maybe partial write to a register.
383 *
384 * Note that this will only work for simple registers, if Xen needs to
385 * trap accesses to rw1c registers (like the status PCI header register)
386 * the logic in vpci_write will have to be expanded in order to correctly
387 * deal with them.
388 */
vpci_write_helper(const struct pci_dev * pdev,const struct vpci_register * r,unsigned int size,unsigned int offset,uint32_t data)389 static void vpci_write_helper(const struct pci_dev *pdev,
390 const struct vpci_register *r, unsigned int size,
391 unsigned int offset, uint32_t data)
392 {
393 ASSERT(size <= r->size);
394
395 if ( size != r->size )
396 {
397 uint32_t val;
398
399 val = r->read(pdev, r->offset, r->private);
400 data = merge_result(val, data, size, offset);
401 }
402
403 r->write(pdev, r->offset, data & (0xffffffff >> (32 - 8 * r->size)),
404 r->private);
405 }
406
vpci_write(pci_sbdf_t sbdf,unsigned int reg,unsigned int size,uint32_t data)407 void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned int size,
408 uint32_t data)
409 {
410 const struct domain *d = current->domain;
411 const struct pci_dev *pdev;
412 const struct vpci_register *r;
413 unsigned int data_offset = 0;
414 const unsigned long *ro_map = pci_get_ro_map(sbdf.seg);
415
416 if ( !size )
417 {
418 ASSERT_UNREACHABLE();
419 return;
420 }
421
422 if ( ro_map && test_bit(sbdf.bdf, ro_map) )
423 /* Ignore writes to read-only devices. */
424 return;
425
426 /*
427 * Find the PCI dev matching the address.
428 * Passthrough everything that's not trapped.
429 */
430 pdev = pci_get_pdev_by_domain(d, sbdf.seg, sbdf.bus, sbdf.devfn);
431 if ( !pdev )
432 {
433 vpci_write_hw(sbdf, reg, size, data);
434 return;
435 }
436
437 spin_lock(&pdev->vpci->lock);
438
439 /* Write the value to the hardware or emulated registers. */
440 list_for_each_entry ( r, &pdev->vpci->handlers, node )
441 {
442 const struct vpci_register emu = {
443 .offset = reg + data_offset,
444 .size = size - data_offset
445 };
446 int cmp = vpci_register_cmp(&emu, r);
447 unsigned int write_size;
448
449 if ( cmp < 0 )
450 break;
451 if ( cmp > 0 )
452 continue;
453
454 if ( emu.offset < r->offset )
455 {
456 /* Heading gap, write partial content to hardware. */
457 vpci_write_hw(sbdf, emu.offset, r->offset - emu.offset,
458 data >> (data_offset * 8));
459 data_offset += r->offset - emu.offset;
460 }
461
462 /* Find the intersection size between the two sets. */
463 write_size = min(emu.offset + emu.size, r->offset + r->size) -
464 max(emu.offset, r->offset);
465 vpci_write_helper(pdev, r, write_size, reg + data_offset - r->offset,
466 data >> (data_offset * 8));
467 data_offset += write_size;
468 if ( data_offset == size )
469 break;
470 ASSERT(data_offset < size);
471 }
472
473 if ( data_offset < size )
474 /* Tailing gap, write the remaining. */
475 vpci_write_hw(sbdf, reg + data_offset, size - data_offset,
476 data >> (data_offset * 8));
477
478 spin_unlock(&pdev->vpci->lock);
479 }
480
481 /*
482 * Local variables:
483 * mode: C
484 * c-file-style: "BSD"
485 * c-basic-offset: 4
486 * tab-width: 4
487 * indent-tabs-mode: nil
488 * End:
489 */
490