1 /******************************************************************************
2  * pci.c
3  *
4  * Architecture-dependent PCI access functions.
5  */
6 
7 #include <xen/spinlock.h>
8 #include <xen/pci.h>
9 #include <asm/io.h>
10 #include <xsm/xsm.h>
11 
12 static DEFINE_SPINLOCK(pci_config_lock);
13 
pci_conf_read(uint32_t cf8,uint8_t offset,uint8_t bytes)14 uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes)
15 {
16     unsigned long flags;
17     uint32_t value;
18 
19     BUG_ON((offset + bytes) > 4);
20 
21     spin_lock_irqsave(&pci_config_lock, flags);
22 
23     outl(cf8, 0xcf8);
24 
25     switch ( bytes )
26     {
27     case 1:
28         value = inb(0xcfc + offset);
29         break;
30     case 2:
31         value = inw(0xcfc + offset);
32         break;
33     case 4:
34         value = inl(0xcfc + offset);
35         break;
36     default:
37         value = 0;
38         BUG();
39     }
40 
41     spin_unlock_irqrestore(&pci_config_lock, flags);
42 
43     return value;
44 }
45 
pci_conf_write(uint32_t cf8,uint8_t offset,uint8_t bytes,uint32_t data)46 void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data)
47 {
48     unsigned long flags;
49 
50     BUG_ON((offset + bytes) > 4);
51 
52     spin_lock_irqsave(&pci_config_lock, flags);
53 
54     outl(cf8, 0xcf8);
55 
56     switch ( bytes )
57     {
58     case 1:
59         outb((uint8_t)data, 0xcfc + offset);
60         break;
61     case 2:
62         outw((uint16_t)data, 0xcfc + offset);
63         break;
64     case 4:
65         outl(data, 0xcfc + offset);
66         break;
67     }
68 
69     spin_unlock_irqrestore(&pci_config_lock, flags);
70 }
71 
pci_conf_write_intercept(unsigned int seg,unsigned int bdf,unsigned int reg,unsigned int size,uint32_t * data)72 int pci_conf_write_intercept(unsigned int seg, unsigned int bdf,
73                              unsigned int reg, unsigned int size,
74                              uint32_t *data)
75 {
76     struct pci_dev *pdev;
77     int rc = xsm_pci_config_permission(XSM_HOOK, current->domain, bdf,
78                                        reg, reg + size - 1, 1);
79 
80     if ( rc < 0 )
81         return rc;
82     ASSERT(!rc);
83 
84     /*
85      * Avoid expensive operations when no hook is going to do anything
86      * for the access anyway.
87      */
88     if ( reg < 64 || reg >= 256 )
89         return 0;
90 
91     pcidevs_lock();
92 
93     pdev = pci_get_pdev(seg, PCI_BUS(bdf), PCI_DEVFN2(bdf));
94     if ( pdev )
95         rc = pci_msi_conf_write_intercept(pdev, reg, size, data);
96 
97     pcidevs_unlock();
98 
99     return rc;
100 }
101