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