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