/root/src/xen/xen/arch/x86/pci.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
14 | | uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes) |
15 | 69.8k | { |
16 | 69.8k | unsigned long flags; |
17 | 69.8k | uint32_t value; |
18 | 69.8k | |
19 | 69.8k | BUG_ON((offset + bytes) > 4); |
20 | 69.8k | |
21 | 69.8k | spin_lock_irqsave(&pci_config_lock, flags); |
22 | 69.8k | |
23 | 69.8k | outl(cf8, 0xcf8); |
24 | 69.8k | |
25 | 69.8k | switch ( bytes ) |
26 | 69.8k | { |
27 | 4.71k | case 1: |
28 | 4.71k | value = inb(0xcfc + offset); |
29 | 4.71k | break; |
30 | 5.26k | case 2: |
31 | 5.26k | value = inw(0xcfc + offset); |
32 | 5.26k | break; |
33 | 59.8k | case 4: |
34 | 59.8k | value = inl(0xcfc + offset); |
35 | 59.8k | break; |
36 | 0 | default: |
37 | 0 | value = 0; |
38 | 0 | BUG(); |
39 | 69.8k | } |
40 | 69.8k | |
41 | 69.8k | spin_unlock_irqrestore(&pci_config_lock, flags); |
42 | 69.8k | |
43 | 69.8k | return value; |
44 | 69.8k | } |
45 | | |
46 | | void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data) |
47 | 3.42k | { |
48 | 3.42k | unsigned long flags; |
49 | 3.42k | |
50 | 3.42k | BUG_ON((offset + bytes) > 4); |
51 | 3.42k | |
52 | 3.42k | spin_lock_irqsave(&pci_config_lock, flags); |
53 | 3.42k | |
54 | 3.42k | outl(cf8, 0xcf8); |
55 | 3.42k | |
56 | 3.42k | switch ( bytes ) |
57 | 3.42k | { |
58 | 607 | case 1: |
59 | 607 | outb((uint8_t)data, 0xcfc + offset); |
60 | 607 | break; |
61 | 1.20k | case 2: |
62 | 1.20k | outw((uint16_t)data, 0xcfc + offset); |
63 | 1.20k | break; |
64 | 1.61k | case 4: |
65 | 1.61k | outl(data, 0xcfc + offset); |
66 | 1.61k | break; |
67 | 3.42k | } |
68 | 3.42k | |
69 | 3.42k | spin_unlock_irqrestore(&pci_config_lock, flags); |
70 | 3.42k | } |
71 | | |
72 | | int pci_conf_write_intercept(unsigned int seg, unsigned int bdf, |
73 | | unsigned int reg, unsigned int size, |
74 | | uint32_t *data) |
75 | 0 | { |
76 | 0 | struct pci_dev *pdev; |
77 | 0 | int rc = xsm_pci_config_permission(XSM_HOOK, current->domain, bdf, |
78 | 0 | reg, reg + size - 1, 1); |
79 | 0 |
|
80 | 0 | if ( rc < 0 ) |
81 | 0 | return rc; |
82 | 0 | ASSERT(!rc); |
83 | 0 |
|
84 | 0 | /* |
85 | 0 | * Avoid expensive operations when no hook is going to do anything |
86 | 0 | * for the access anyway. |
87 | 0 | */ |
88 | 0 | if ( reg < 64 || reg >= 256 ) |
89 | 0 | return 0; |
90 | 0 |
|
91 | 0 | pcidevs_lock(); |
92 | 0 |
|
93 | 0 | pdev = pci_get_pdev(seg, PCI_BUS(bdf), PCI_DEVFN2(bdf)); |
94 | 0 | if ( pdev ) |
95 | 0 | rc = pci_msi_conf_write_intercept(pdev, reg, size, data); |
96 | 0 |
|
97 | 0 | pcidevs_unlock(); |
98 | 0 |
|
99 | 0 | return rc; |
100 | 0 | } |