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