xref: /kvmtool/pci.c (revision 76f9c8410356af8a2946f56b9faa7167b40b1ddd)
160742802SPekka Enberg #include "kvm/pci.h"
260742802SPekka Enberg #include "kvm/ioport.h"
3*76f9c841SCyrill 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 
37*76f9c841SCyrill Gorcunov static struct pci_device_header no_device = {
38*76f9c841SCyrill Gorcunov 	.vendor_id		= 0xffff,
39*76f9c841SCyrill Gorcunov 	.device_id		= 0xffff,
40*76f9c841SCyrill Gorcunov 	.revision_id		= 0xff,
41*76f9c841SCyrill Gorcunov 	.class			= 0xffffff,
42*76f9c841SCyrill Gorcunov };
43*76f9c841SCyrill Gorcunov 
44*76f9c841SCyrill Gorcunov #define PCI_VENDOR_ID_REDHAT_QUMRANET	0x1af4
45*76f9c841SCyrill Gorcunov #define PCI_DEVICE_ID_VIRTIO_BLK	0x1001
46*76f9c841SCyrill Gorcunov 
47*76f9c841SCyrill Gorcunov static struct pci_device_header virtio_device = {
48*76f9c841SCyrill Gorcunov 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
49*76f9c841SCyrill Gorcunov 	.device_id		= PCI_DEVICE_ID_VIRTIO_BLK,
50*76f9c841SCyrill Gorcunov 	.header_type		= PCI_HEADER_TYPE_NORMAL,
51*76f9c841SCyrill Gorcunov };
52*76f9c841SCyrill Gorcunov 
53*76f9c841SCyrill Gorcunov static bool pci_device_matches(uint8_t bus_number, uint8_t device_number, uint8_t function_number)
54*76f9c841SCyrill Gorcunov {
55*76f9c841SCyrill Gorcunov 	if (pci_config_address.bus_number != bus_number)
56*76f9c841SCyrill Gorcunov 		return false;
57*76f9c841SCyrill Gorcunov 
58*76f9c841SCyrill Gorcunov 	if (pci_config_address.device_number != device_number)
59*76f9c841SCyrill Gorcunov 		return false;
60*76f9c841SCyrill Gorcunov 
61*76f9c841SCyrill Gorcunov 	return pci_config_address.function_number == function_number;
62*76f9c841SCyrill Gorcunov }
63*76f9c841SCyrill Gorcunov 
64305b72ceSCyrill Gorcunov static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
6560742802SPekka Enberg {
66*76f9c841SCyrill Gorcunov 	void *p;
674c797ebcSCyrill Gorcunov 
68*76f9c841SCyrill Gorcunov 	if (pci_device_matches(0, 1, 0))
69*76f9c841SCyrill Gorcunov 		p		= &virtio_device;
70*76f9c841SCyrill Gorcunov 	else
71*76f9c841SCyrill Gorcunov 		p		= &no_device;
72*76f9c841SCyrill Gorcunov 
73*76f9c841SCyrill Gorcunov 	memcpy(data, p + (pci_config_address.register_number * 4), size);
744c797ebcSCyrill Gorcunov 
7560742802SPekka Enberg 	return true;
7660742802SPekka Enberg }
7760742802SPekka Enberg 
78305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_data_ops = {
79305b72ceSCyrill Gorcunov 	.io_in		= pci_config_data_in,
80305b72ceSCyrill Gorcunov 	.io_out		= pci_config_data_out,
8160742802SPekka Enberg };
8260742802SPekka Enberg 
8360742802SPekka Enberg void pci__init(void)
8460742802SPekka Enberg {
85305b72ceSCyrill Gorcunov 	ioport__register(PCI_CONFIG_DATA,    &pci_config_data_ops);
86305b72ceSCyrill Gorcunov 	ioport__register(PCI_CONFIG_ADDRESS, &pci_config_address_ops);
8760742802SPekka Enberg }
88