xref: /kvmtool/pci.c (revision 3e553514cd00c25153a6294dfc39466e3c7d3a75)
1 #include "kvm/pci.h"
2 #include "kvm/ioport.h"
3 #include "kvm/util.h"
4 
5 #include <assert.h>
6 #include <stdint.h>
7 
8 #define PCI_MAX_DEVICES			256
9 
10 static struct pci_device_header		*pci_devices[PCI_MAX_DEVICES];
11 
12 static struct pci_config_address	pci_config_address;
13 
14 static void *pci_config_address_ptr(uint16_t port)
15 {
16 	unsigned long offset;
17 	void *base;
18 
19 	offset		= port - PCI_CONFIG_ADDRESS;
20 	base		= &pci_config_address;
21 
22 	return base + offset;
23 }
24 
25 static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
26 {
27 	void *p = pci_config_address_ptr(port);
28 
29 	memcpy(p, data, size);
30 
31 	return true;
32 }
33 
34 static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
35 {
36 	void *p = pci_config_address_ptr(port);
37 
38 	memcpy(data, p, size);
39 
40 	return true;
41 }
42 
43 static struct ioport_operations pci_config_address_ops = {
44 	.io_in		= pci_config_address_in,
45 	.io_out		= pci_config_address_out,
46 };
47 
48 static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
49 {
50 	return true;
51 }
52 
53 static bool pci_device_exists(uint8_t bus_number, uint8_t device_number, uint8_t function_number)
54 {
55 	struct pci_device_header *dev;
56 
57 	if (pci_config_address.bus_number != bus_number)
58 		return false;
59 
60 	if (pci_config_address.function_number != function_number)
61 		return false;
62 
63 	if (device_number >= PCI_MAX_DEVICES)
64 		return false;
65 
66 	dev		= pci_devices[device_number];
67 
68 	return dev != NULL;
69 }
70 
71 static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
72 {
73 	unsigned long start;
74 	uint8_t dev_num;
75 
76 	/*
77 	 * If someone accesses PCI configuration space offsets that are not
78 	 * aligned to 4 bytes, it uses ioports to signify that.
79 	 */
80 	start = port - PCI_CONFIG_DATA;
81 
82 	dev_num		= pci_config_address.device_number;
83 
84 	if (pci_device_exists(0, dev_num, 0)) {
85 		unsigned long offset;
86 
87 		offset = start + (pci_config_address.register_number << 2);
88 		if (offset < sizeof(struct pci_device_header)) {
89 			void *p = pci_devices[dev_num];
90 
91 			memcpy(data, p + offset, size);
92 		} else
93 			memset(data, 0x00, size);
94 	} else
95 		memset(data, 0xff, size);
96 
97 	return true;
98 }
99 
100 static struct ioport_operations pci_config_data_ops = {
101 	.io_in		= pci_config_data_in,
102 	.io_out		= pci_config_data_out,
103 };
104 
105 void pci__register(struct pci_device_header *dev, uint8_t dev_num)
106 {
107 	assert(dev_num < PCI_MAX_DEVICES);
108 
109 	pci_devices[dev_num]	= dev;
110 }
111 
112 void pci__init(void)
113 {
114 	ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4);
115 	ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4);
116 }
117