xref: /kvmtool/pci.c (revision beb095eb19b0ca82e85d7c3524e5b33334e459e5)
160742802SPekka Enberg #include "kvm/pci.h"
260742802SPekka Enberg #include "kvm/ioport.h"
376f9c841SCyrill Gorcunov #include "kvm/util.h"
460742802SPekka Enberg 
560742802SPekka Enberg #include <stdint.h>
660742802SPekka Enberg 
74402a581SPekka Enberg static struct pci_config_address pci_config_address;
860742802SPekka Enberg 
9305b72ceSCyrill Gorcunov static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
1060742802SPekka Enberg {
114402a581SPekka Enberg 	struct pci_config_address *addr = data;
1260742802SPekka Enberg 
13dad5bc09SCyrill Gorcunov 	pci_config_address	= *addr;
1460742802SPekka Enberg 
1560742802SPekka Enberg 	return true;
1660742802SPekka Enberg }
1760742802SPekka Enberg 
18305b72ceSCyrill Gorcunov static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
1960742802SPekka Enberg {
204402a581SPekka Enberg 	struct pci_config_address *addr = data;
2160742802SPekka Enberg 
22305b72ceSCyrill Gorcunov 	*addr		=  pci_config_address;
2360742802SPekka Enberg 
2460742802SPekka Enberg 	return true;
2560742802SPekka Enberg }
2660742802SPekka Enberg 
27305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_address_ops = {
28305b72ceSCyrill Gorcunov 	.io_in		= pci_config_address_in,
29305b72ceSCyrill Gorcunov 	.io_out		= pci_config_address_out,
3060742802SPekka Enberg };
3160742802SPekka Enberg 
32305b72ceSCyrill Gorcunov static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
3360742802SPekka Enberg {
3460742802SPekka Enberg 	return true;
3560742802SPekka Enberg }
3660742802SPekka Enberg 
3776f9c841SCyrill Gorcunov #define PCI_VENDOR_ID_REDHAT_QUMRANET	0x1af4
3876f9c841SCyrill Gorcunov #define PCI_DEVICE_ID_VIRTIO_BLK	0x1001
3976f9c841SCyrill Gorcunov 
4076f9c841SCyrill Gorcunov static struct pci_device_header virtio_device = {
4176f9c841SCyrill Gorcunov 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
4276f9c841SCyrill Gorcunov 	.device_id		= PCI_DEVICE_ID_VIRTIO_BLK,
4376f9c841SCyrill Gorcunov 	.header_type		= PCI_HEADER_TYPE_NORMAL,
44*beb095ebSCyrill Gorcunov 	/* .class			= (0x01 << 16) | (0x01 << 8) | ((1<<7) | 	 * (1<<1)), */
45*beb095ebSCyrill Gorcunov 	.bar[0]			= (IOPORT_VIRTIO << 4) | PCI_BASE_ADDRESS_SPACE_IO,
4676f9c841SCyrill Gorcunov };
4776f9c841SCyrill Gorcunov 
4876f9c841SCyrill Gorcunov static bool pci_device_matches(uint8_t bus_number, uint8_t device_number, uint8_t function_number)
4976f9c841SCyrill Gorcunov {
5076f9c841SCyrill Gorcunov 	if (pci_config_address.bus_number != bus_number)
5176f9c841SCyrill Gorcunov 		return false;
5276f9c841SCyrill Gorcunov 
5376f9c841SCyrill Gorcunov 	if (pci_config_address.device_number != device_number)
5476f9c841SCyrill Gorcunov 		return false;
5576f9c841SCyrill Gorcunov 
5676f9c841SCyrill Gorcunov 	return pci_config_address.function_number == function_number;
5776f9c841SCyrill Gorcunov }
5876f9c841SCyrill Gorcunov 
59305b72ceSCyrill Gorcunov static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
6060742802SPekka Enberg {
61e4d2cea2SPekka Enberg 	unsigned long start;
62e4d2cea2SPekka Enberg 
63e4d2cea2SPekka Enberg 	/*
64e4d2cea2SPekka Enberg 	 * If someone accesses PCI configuration space offsets that are not
6570d08766SCyrill Gorcunov 	 * aligned to 4 bytes, it uses ioports to signify that.
66e4d2cea2SPekka Enberg 	 */
6770d08766SCyrill Gorcunov 	start = port - PCI_CONFIG_DATA;
68e4d2cea2SPekka Enberg 
69e498ea08SPekka Enberg 	if (pci_device_matches(0, 1, 0)) {
70598419d5SPekka Enberg 		unsigned long offset;
71598419d5SPekka Enberg 
72e4d2cea2SPekka Enberg 		offset = start + (pci_config_address.register_number << 2);
73598419d5SPekka Enberg 		if (offset < sizeof(struct pci_device_header)) {
74e498ea08SPekka Enberg 			void *p = &virtio_device;
7518ae021aSPekka Enberg 			memcpy(data, p + offset, size);
76598419d5SPekka Enberg 		} else
77598419d5SPekka Enberg 			memset(data, 0x00, size);
78e498ea08SPekka Enberg 	} else
79e498ea08SPekka Enberg 		memset(data, 0xff, size);
804c797ebcSCyrill Gorcunov 
8160742802SPekka Enberg 	return true;
8260742802SPekka Enberg }
8360742802SPekka Enberg 
84305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_data_ops = {
85305b72ceSCyrill Gorcunov 	.io_in		= pci_config_data_in,
86305b72ceSCyrill Gorcunov 	.io_out		= pci_config_data_out,
8760742802SPekka Enberg };
8860742802SPekka Enberg 
89*beb095ebSCyrill Gorcunov static bool virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
90*beb095ebSCyrill Gorcunov {
91*beb095ebSCyrill Gorcunov 	info("virtio_in");
92*beb095ebSCyrill Gorcunov 	return true;
93*beb095ebSCyrill Gorcunov }
94*beb095ebSCyrill Gorcunov 
95*beb095ebSCyrill Gorcunov static bool virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
96*beb095ebSCyrill Gorcunov {
97*beb095ebSCyrill Gorcunov 	info("virtio_out");
98*beb095ebSCyrill Gorcunov 	return true;
99*beb095ebSCyrill Gorcunov }
100*beb095ebSCyrill Gorcunov 
101*beb095ebSCyrill Gorcunov static struct ioport_operations virtio_io_ops = {
102*beb095ebSCyrill Gorcunov 	.io_in		= virtio_in,
103*beb095ebSCyrill Gorcunov 	.io_out		= virtio_out,
104*beb095ebSCyrill Gorcunov };
105*beb095ebSCyrill Gorcunov 
10660742802SPekka Enberg void pci__init(void)
10760742802SPekka Enberg {
108*beb095ebSCyrill Gorcunov 
109*beb095ebSCyrill Gorcunov 	ioport__register(IOPORT_VIRTIO,		&virtio_io_ops);
110*beb095ebSCyrill Gorcunov 
11170d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 0,	&pci_config_data_ops);
11270d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 1,	&pci_config_data_ops);
11370d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 2,	&pci_config_data_ops);
11470d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA + 3,	&pci_config_data_ops);
11570d08766SCyrill Gorcunov 
11670d08766SCyrill Gorcunov 	ioport__register(PCI_CONFIG_ADDRESS,	&pci_config_address_ops);
11760742802SPekka Enberg }
118