xref: /kvmtool/pci.c (revision 40f2fd063bdd5b9464d7b44dc677fd8a4bbf8c6a)
1 #include "kvm/pci.h"
2 #include "kvm/ioport.h"
3 #include "kvm/util.h"
4 #include "kvm/kvm.h"
5 
6 #include <assert.h>
7 
8 #define PCI_BAR_OFFSET(b)		(offsetof(struct pci_device_header, bar[b]))
9 
10 static struct pci_device_header		*pci_devices[PCI_MAX_DEVICES];
11 
12 static union pci_config_address		pci_config_address;
13 
14 /* This is within our PCI gap - in an unused area.
15  * Note this is a PCI *bus address*, is used to assign BARs etc.!
16  * (That's why it can still 32bit even with 64bit guests-- 64bit
17  * PCI isn't currently supported.)
18  */
19 static u32 io_space_blocks		= KVM_PCI_MMIO_AREA;
20 
21 u32 pci_get_io_space_block(u32 size)
22 {
23 	u32 block = io_space_blocks;
24 	io_space_blocks += size;
25 
26 	return block;
27 }
28 
29 static void *pci_config_address_ptr(u16 port)
30 {
31 	unsigned long offset;
32 	void *base;
33 
34 	offset		= port - PCI_CONFIG_ADDRESS;
35 	base		= &pci_config_address;
36 
37 	return base + offset;
38 }
39 
40 static bool pci_config_address_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
41 {
42 	void *p = pci_config_address_ptr(port);
43 
44 	memcpy(p, data, size);
45 
46 	return true;
47 }
48 
49 static bool pci_config_address_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
50 {
51 	void *p = pci_config_address_ptr(port);
52 
53 	memcpy(data, p, size);
54 
55 	return true;
56 }
57 
58 static struct ioport_operations pci_config_address_ops = {
59 	.io_in		= pci_config_address_in,
60 	.io_out		= pci_config_address_out,
61 };
62 
63 static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number)
64 {
65 	struct pci_device_header *dev;
66 
67 	if (pci_config_address.bus_number != bus_number)
68 		return false;
69 
70 	if (pci_config_address.function_number != function_number)
71 		return false;
72 
73 	if (device_number >= PCI_MAX_DEVICES)
74 		return false;
75 
76 	dev		= pci_devices[device_number];
77 
78 	return dev != NULL;
79 }
80 
81 static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
82 {
83 	/*
84 	 * If someone accesses PCI configuration space offsets that are not
85 	 * aligned to 4 bytes, it uses ioports to signify that.
86 	 */
87 	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
88 
89 	pci__config_wr(kvm, pci_config_address, data, size);
90 
91 	return true;
92 }
93 
94 static bool pci_config_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
95 {
96 	/*
97 	 * If someone accesses PCI configuration space offsets that are not
98 	 * aligned to 4 bytes, it uses ioports to signify that.
99 	 */
100 	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
101 
102 	pci__config_rd(kvm, pci_config_address, data, size);
103 
104 	return true;
105 }
106 
107 static struct ioport_operations pci_config_data_ops = {
108 	.io_in		= pci_config_data_in,
109 	.io_out		= pci_config_data_out,
110 };
111 
112 void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size)
113 {
114 	u8 dev_num;
115 
116 	dev_num		= addr.device_number;
117 
118 	if (pci_device_exists(0, dev_num, 0)) {
119 		unsigned long offset;
120 
121 		offset = addr.w & 0xff;
122 		if (offset < sizeof(struct pci_device_header)) {
123 			void *p = pci_devices[dev_num];
124 			u8 bar = (offset - PCI_BAR_OFFSET(0)) / (sizeof(u32));
125 			u32 sz = PCI_IO_SIZE;
126 
127 			if (bar < 6 && pci_devices[dev_num]->bar_size[bar])
128 				sz = pci_devices[dev_num]->bar_size[bar];
129 
130 			/*
131 			 * If the kernel masks the BAR it would expect to find the
132 			 * size of the BAR there next time it reads from it.
133 			 * When the kernel got the size it would write the address
134 			 * back.
135 			 */
136 			if (*(u32 *)(p + offset)) {
137 				/* See if kernel tries to mask one of the BARs */
138 				if ((offset >= PCI_BAR_OFFSET(0)) &&
139 				    (offset <= PCI_BAR_OFFSET(6)) &&
140 				    (ioport__read32(data)  == 0xFFFFFFFF))
141 					memcpy(p + offset, &sz, sizeof(sz));
142 				    else
143 					memcpy(p + offset, data, size);
144 			}
145 		}
146 	}
147 }
148 
149 void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size)
150 {
151 	u8 dev_num;
152 
153 	dev_num		= addr.device_number;
154 
155 	if (pci_device_exists(0, dev_num, 0)) {
156 		unsigned long offset;
157 
158 		offset = addr.w & 0xff;
159 		if (offset < sizeof(struct pci_device_header)) {
160 			void *p = pci_devices[dev_num];
161 
162 			memcpy(data, p + offset, size);
163 		} else
164 			memset(data, 0x00, size);
165 	} else
166 		memset(data, 0xff, size);
167 }
168 
169 void pci__register(struct pci_device_header *dev, u8 dev_num)
170 {
171 	assert(dev_num < PCI_MAX_DEVICES);
172 	pci_devices[dev_num]	= dev;
173 }
174 
175 struct pci_device_header *pci__find_dev(u8 dev_num)
176 {
177 	assert(dev_num < PCI_MAX_DEVICES);
178 	return pci_devices[dev_num];
179 }
180 
181 void pci__init(void)
182 {
183 	ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4, NULL);
184 	ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4, NULL);
185 }
186