xref: /kvmtool/pci.c (revision b30d05ad0a9ee697ba41a09f05273d63d2f36fb2)
160742802SPekka Enberg #include "kvm/pci.h"
260742802SPekka Enberg #include "kvm/ioport.h"
376f9c841SCyrill Gorcunov #include "kvm/util.h"
460742802SPekka Enberg 
5*b30d05adSPekka Enberg #include <assert.h>
660742802SPekka Enberg #include <stdint.h>
760742802SPekka Enberg 
8*b30d05adSPekka Enberg #define PCI_MAX_DEVICES			256
9*b30d05adSPekka Enberg 
10*b30d05adSPekka Enberg static struct pci_device_header		*pci_devices[PCI_MAX_DEVICES];
11*b30d05adSPekka Enberg 
124402a581SPekka Enberg static struct pci_config_address	pci_config_address;
1360742802SPekka Enberg 
14ba824677SPekka Enberg static void *pci_config_address_ptr(uint16_t port)
15ba824677SPekka Enberg {
16ba824677SPekka Enberg 	unsigned long offset;
17ba824677SPekka Enberg 	void *base;
18ba824677SPekka Enberg 
19ba824677SPekka Enberg 	offset		= port - PCI_CONFIG_ADDRESS;
20ba824677SPekka Enberg 	base		= &pci_config_address;
21ba824677SPekka Enberg 
22ba824677SPekka Enberg 	return base + offset;
23ba824677SPekka Enberg }
24ba824677SPekka Enberg 
25305b72ceSCyrill Gorcunov static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
2660742802SPekka Enberg {
27ba824677SPekka Enberg 	void *p = pci_config_address_ptr(port);
2860742802SPekka Enberg 
29ba824677SPekka Enberg 	memcpy(p, data, size);
3060742802SPekka Enberg 
3160742802SPekka Enberg 	return true;
3260742802SPekka Enberg }
3360742802SPekka Enberg 
34305b72ceSCyrill Gorcunov static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
3560742802SPekka Enberg {
36ba824677SPekka Enberg 	void *p = pci_config_address_ptr(port);
3760742802SPekka Enberg 
38ba824677SPekka Enberg 	memcpy(data, p, size);
3960742802SPekka Enberg 
4060742802SPekka Enberg 	return true;
4160742802SPekka Enberg }
4260742802SPekka Enberg 
43305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_address_ops = {
44305b72ceSCyrill Gorcunov 	.io_in		= pci_config_address_in,
45305b72ceSCyrill Gorcunov 	.io_out		= pci_config_address_out,
4660742802SPekka Enberg };
4760742802SPekka Enberg 
48305b72ceSCyrill Gorcunov static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
4960742802SPekka Enberg {
5060742802SPekka Enberg 	return true;
5160742802SPekka Enberg }
5260742802SPekka Enberg 
53*b30d05adSPekka Enberg static bool pci_device_exists(uint8_t bus_number, uint8_t device_number, uint8_t function_number)
5476f9c841SCyrill Gorcunov {
55*b30d05adSPekka Enberg 	struct pci_device_header *dev;
56*b30d05adSPekka Enberg 
5776f9c841SCyrill Gorcunov 	if (pci_config_address.bus_number != bus_number)
5876f9c841SCyrill Gorcunov 		return false;
5976f9c841SCyrill Gorcunov 
60*b30d05adSPekka Enberg 	if (pci_config_address.function_number != function_number)
6176f9c841SCyrill Gorcunov 		return false;
6276f9c841SCyrill Gorcunov 
63*b30d05adSPekka Enberg 	if (device_number >= PCI_MAX_DEVICES)
64*b30d05adSPekka Enberg 		return false;
65*b30d05adSPekka Enberg 
66*b30d05adSPekka Enberg 	dev		= pci_devices[device_number];
67*b30d05adSPekka Enberg 
68*b30d05adSPekka Enberg 	return dev != NULL;
6976f9c841SCyrill Gorcunov }
7076f9c841SCyrill Gorcunov 
71305b72ceSCyrill Gorcunov static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
7260742802SPekka Enberg {
73e4d2cea2SPekka Enberg 	unsigned long start;
74*b30d05adSPekka Enberg 	uint8_t dev_num;
75e4d2cea2SPekka Enberg 
76e4d2cea2SPekka Enberg 	/*
77e4d2cea2SPekka Enberg 	 * If someone accesses PCI configuration space offsets that are not
7870d08766SCyrill Gorcunov 	 * aligned to 4 bytes, it uses ioports to signify that.
79e4d2cea2SPekka Enberg 	 */
8070d08766SCyrill Gorcunov 	start = port - PCI_CONFIG_DATA;
81e4d2cea2SPekka Enberg 
82*b30d05adSPekka Enberg 	dev_num		= pci_config_address.device_number;
83*b30d05adSPekka Enberg 
84*b30d05adSPekka Enberg 	if (pci_device_exists(0, dev_num, 0)) {
85598419d5SPekka Enberg 		unsigned long offset;
86598419d5SPekka Enberg 
87e4d2cea2SPekka Enberg 		offset = start + (pci_config_address.register_number << 2);
88598419d5SPekka Enberg 		if (offset < sizeof(struct pci_device_header)) {
89*b30d05adSPekka Enberg 			void *p = pci_devices[dev_num];
90*b30d05adSPekka Enberg 
9118ae021aSPekka Enberg 			memcpy(data, p + offset, size);
92598419d5SPekka Enberg 		} else
93598419d5SPekka Enberg 			memset(data, 0x00, size);
94e498ea08SPekka Enberg 	} else
95e498ea08SPekka Enberg 		memset(data, 0xff, size);
964c797ebcSCyrill Gorcunov 
9760742802SPekka Enberg 	return true;
9860742802SPekka Enberg }
9960742802SPekka Enberg 
100305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_data_ops = {
101305b72ceSCyrill Gorcunov 	.io_in		= pci_config_data_in,
102305b72ceSCyrill Gorcunov 	.io_out		= pci_config_data_out,
10360742802SPekka Enberg };
10460742802SPekka Enberg 
105*b30d05adSPekka Enberg void pci__register(struct pci_device_header *dev, uint8_t dev_num)
106beb095ebSCyrill Gorcunov {
107*b30d05adSPekka Enberg 	assert(dev_num < PCI_MAX_DEVICES);
108beb095ebSCyrill Gorcunov 
109*b30d05adSPekka Enberg 	pci_devices[dev_num]	= dev;
110beb095ebSCyrill Gorcunov }
111beb095ebSCyrill Gorcunov 
11260742802SPekka Enberg void pci__init(void)
11360742802SPekka Enberg {
11470d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops);
11570d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 1, &pci_config_data_ops);
11670d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 2, &pci_config_data_ops);
11770d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 3, &pci_config_data_ops);
11870d08766SCyrill Gorcunov 
119ba824677SPekka Enberg 	ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops);
120ba824677SPekka Enberg 	ioport__register(PCI_CONFIG_ADDRESS + 1, &pci_config_address_ops);
121ba824677SPekka Enberg 	ioport__register(PCI_CONFIG_ADDRESS + 2, &pci_config_address_ops);
122ba824677SPekka Enberg 	ioport__register(PCI_CONFIG_ADDRESS + 3, &pci_config_address_ops);
12360742802SPekka Enberg }
124