1*5fe5eb04SJean-Philippe Brucker #include "kvm/virtio.h"
2*5fe5eb04SJean-Philippe Brucker #include "kvm/virtio-mmio.h"
3*5fe5eb04SJean-Philippe Brucker
4*5fe5eb04SJean-Philippe Brucker #include <linux/byteorder.h>
5*5fe5eb04SJean-Philippe Brucker
6*5fe5eb04SJean-Philippe Brucker #define vmmio_selected_vq(vmmio) \
7*5fe5eb04SJean-Philippe Brucker vdev->ops->get_vq((vmmio)->kvm, (vmmio)->dev, (vmmio)->hdr.queue_sel)
8*5fe5eb04SJean-Philippe Brucker
virtio_mmio_config_in(struct kvm_cpu * vcpu,u64 addr,u32 * data,u32 len,struct virtio_device * vdev)9*5fe5eb04SJean-Philippe Brucker static void virtio_mmio_config_in(struct kvm_cpu *vcpu,
10*5fe5eb04SJean-Philippe Brucker u64 addr, u32 *data, u32 len,
11*5fe5eb04SJean-Philippe Brucker struct virtio_device *vdev)
12*5fe5eb04SJean-Philippe Brucker {
13*5fe5eb04SJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio;
14*5fe5eb04SJean-Philippe Brucker u64 features = 1ULL << VIRTIO_F_VERSION_1;
15*5fe5eb04SJean-Philippe Brucker u32 val = 0;
16*5fe5eb04SJean-Philippe Brucker
17*5fe5eb04SJean-Philippe Brucker switch (addr) {
18*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_MAGIC_VALUE:
19*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_VERSION:
20*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_DEVICE_ID:
21*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_VENDOR_ID:
22*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_STATUS:
23*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_INTERRUPT_STATUS:
24*5fe5eb04SJean-Philippe Brucker val = *(u32 *)(((void *)&vmmio->hdr) + addr);
25*5fe5eb04SJean-Philippe Brucker break;
26*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_DEVICE_FEATURES:
27*5fe5eb04SJean-Philippe Brucker if (vmmio->hdr.host_features_sel > 1)
28*5fe5eb04SJean-Philippe Brucker break;
29*5fe5eb04SJean-Philippe Brucker features |= vdev->ops->get_host_features(vmmio->kvm, vmmio->dev);
30*5fe5eb04SJean-Philippe Brucker val = features >> (32 * vmmio->hdr.host_features_sel);
31*5fe5eb04SJean-Philippe Brucker break;
32*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_NUM_MAX:
33*5fe5eb04SJean-Philippe Brucker val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev,
34*5fe5eb04SJean-Philippe Brucker vmmio->hdr.queue_sel);
35*5fe5eb04SJean-Philippe Brucker break;
36*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_READY:
37*5fe5eb04SJean-Philippe Brucker val = vmmio_selected_vq(vmmio)->enabled;
38*5fe5eb04SJean-Philippe Brucker break;
39*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_DESC_LOW:
40*5fe5eb04SJean-Philippe Brucker val = vmmio_selected_vq(vmmio)->vring_addr.desc_lo;
41*5fe5eb04SJean-Philippe Brucker break;
42*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_DESC_HIGH:
43*5fe5eb04SJean-Philippe Brucker val = vmmio_selected_vq(vmmio)->vring_addr.desc_hi;
44*5fe5eb04SJean-Philippe Brucker break;
45*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_USED_LOW:
46*5fe5eb04SJean-Philippe Brucker val = vmmio_selected_vq(vmmio)->vring_addr.used_lo;
47*5fe5eb04SJean-Philippe Brucker break;
48*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_USED_HIGH:
49*5fe5eb04SJean-Philippe Brucker val = vmmio_selected_vq(vmmio)->vring_addr.used_hi;
50*5fe5eb04SJean-Philippe Brucker break;
51*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
52*5fe5eb04SJean-Philippe Brucker val = vmmio_selected_vq(vmmio)->vring_addr.avail_lo;
53*5fe5eb04SJean-Philippe Brucker break;
54*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
55*5fe5eb04SJean-Philippe Brucker val = vmmio_selected_vq(vmmio)->vring_addr.avail_hi;
56*5fe5eb04SJean-Philippe Brucker break;
57*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_CONFIG_GENERATION:
58*5fe5eb04SJean-Philippe Brucker /*
59*5fe5eb04SJean-Philippe Brucker * The config generation changes when the device updates a
60*5fe5eb04SJean-Philippe Brucker * config field larger than 32 bits, that the driver reads using
61*5fe5eb04SJean-Philippe Brucker * multiple accesses. Since kvmtool doesn't use any mutable
62*5fe5eb04SJean-Philippe Brucker * config field larger than 32 bits, the generation is constant.
63*5fe5eb04SJean-Philippe Brucker */
64*5fe5eb04SJean-Philippe Brucker break;
65*5fe5eb04SJean-Philippe Brucker default:
66*5fe5eb04SJean-Philippe Brucker return;
67*5fe5eb04SJean-Philippe Brucker }
68*5fe5eb04SJean-Philippe Brucker
69*5fe5eb04SJean-Philippe Brucker *data = cpu_to_le32(val);
70*5fe5eb04SJean-Philippe Brucker }
71*5fe5eb04SJean-Philippe Brucker
virtio_mmio_config_out(struct kvm_cpu * vcpu,u64 addr,u32 * data,u32 len,struct virtio_device * vdev)72*5fe5eb04SJean-Philippe Brucker static void virtio_mmio_config_out(struct kvm_cpu *vcpu,
73*5fe5eb04SJean-Philippe Brucker u64 addr, u32 *data, u32 len,
74*5fe5eb04SJean-Philippe Brucker struct virtio_device *vdev)
75*5fe5eb04SJean-Philippe Brucker {
76*5fe5eb04SJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio;
77*5fe5eb04SJean-Philippe Brucker struct kvm *kvm = vmmio->kvm;
78*5fe5eb04SJean-Philippe Brucker u32 val = le32_to_cpu(*data);
79*5fe5eb04SJean-Philippe Brucker u64 features;
80*5fe5eb04SJean-Philippe Brucker
81*5fe5eb04SJean-Philippe Brucker switch (addr) {
82*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
83*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
84*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_SEL:
85*5fe5eb04SJean-Philippe Brucker *(u32 *)(((void *)&vmmio->hdr) + addr) = val;
86*5fe5eb04SJean-Philippe Brucker break;
87*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_STATUS:
88*5fe5eb04SJean-Philippe Brucker vmmio->hdr.status = val;
89*5fe5eb04SJean-Philippe Brucker virtio_notify_status(kvm, vdev, vmmio->dev, val);
90*5fe5eb04SJean-Philippe Brucker break;
91*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_DRIVER_FEATURES:
92*5fe5eb04SJean-Philippe Brucker if (vmmio->hdr.guest_features_sel > 1)
93*5fe5eb04SJean-Philippe Brucker break;
94*5fe5eb04SJean-Philippe Brucker
95*5fe5eb04SJean-Philippe Brucker features = (u64)val << (32 * vmmio->hdr.guest_features_sel);
96*5fe5eb04SJean-Philippe Brucker virtio_set_guest_features(vmmio->kvm, vdev, vmmio->dev,
97*5fe5eb04SJean-Philippe Brucker features);
98*5fe5eb04SJean-Philippe Brucker break;
99*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_NUM:
100*5fe5eb04SJean-Philippe Brucker vmmio->hdr.queue_num = val;
101*5fe5eb04SJean-Philippe Brucker vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev,
102*5fe5eb04SJean-Philippe Brucker vmmio->hdr.queue_sel, val);
103*5fe5eb04SJean-Philippe Brucker break;
104*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_READY:
105*5fe5eb04SJean-Philippe Brucker if (val)
106*5fe5eb04SJean-Philippe Brucker virtio_mmio_init_vq(kvm, vdev, vmmio->hdr.queue_sel);
107*5fe5eb04SJean-Philippe Brucker else
108*5fe5eb04SJean-Philippe Brucker virtio_mmio_exit_vq(kvm, vdev, vmmio->hdr.queue_sel);
109*5fe5eb04SJean-Philippe Brucker break;
110*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_NOTIFY:
111*5fe5eb04SJean-Philippe Brucker vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val);
112*5fe5eb04SJean-Philippe Brucker break;
113*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_INTERRUPT_ACK:
114*5fe5eb04SJean-Philippe Brucker vmmio->hdr.interrupt_state &= ~val;
115*5fe5eb04SJean-Philippe Brucker break;
116*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_DESC_LOW:
117*5fe5eb04SJean-Philippe Brucker vmmio_selected_vq(vmmio)->vring_addr.desc_lo = val;
118*5fe5eb04SJean-Philippe Brucker break;
119*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_DESC_HIGH:
120*5fe5eb04SJean-Philippe Brucker vmmio_selected_vq(vmmio)->vring_addr.desc_hi = val;
121*5fe5eb04SJean-Philippe Brucker break;
122*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_USED_LOW:
123*5fe5eb04SJean-Philippe Brucker vmmio_selected_vq(vmmio)->vring_addr.used_lo = val;
124*5fe5eb04SJean-Philippe Brucker break;
125*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_USED_HIGH:
126*5fe5eb04SJean-Philippe Brucker vmmio_selected_vq(vmmio)->vring_addr.used_hi = val;
127*5fe5eb04SJean-Philippe Brucker break;
128*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
129*5fe5eb04SJean-Philippe Brucker vmmio_selected_vq(vmmio)->vring_addr.avail_lo = val;
130*5fe5eb04SJean-Philippe Brucker break;
131*5fe5eb04SJean-Philippe Brucker case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
132*5fe5eb04SJean-Philippe Brucker vmmio_selected_vq(vmmio)->vring_addr.avail_hi = val;
133*5fe5eb04SJean-Philippe Brucker break;
134*5fe5eb04SJean-Philippe Brucker };
135*5fe5eb04SJean-Philippe Brucker }
136*5fe5eb04SJean-Philippe Brucker
virtio_mmio_modern_callback(struct kvm_cpu * vcpu,u64 addr,u8 * data,u32 len,u8 is_write,void * ptr)137*5fe5eb04SJean-Philippe Brucker void virtio_mmio_modern_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
138*5fe5eb04SJean-Philippe Brucker u32 len, u8 is_write, void *ptr)
139*5fe5eb04SJean-Philippe Brucker {
140*5fe5eb04SJean-Philippe Brucker struct virtio_device *vdev = ptr;
141*5fe5eb04SJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio;
142*5fe5eb04SJean-Philippe Brucker u32 offset = addr - vmmio->addr;
143*5fe5eb04SJean-Philippe Brucker
144*5fe5eb04SJean-Philippe Brucker if (offset >= VIRTIO_MMIO_CONFIG) {
145*5fe5eb04SJean-Philippe Brucker offset -= VIRTIO_MMIO_CONFIG;
146*5fe5eb04SJean-Philippe Brucker virtio_access_config(vmmio->kvm, vdev, vmmio->dev, offset, data,
147*5fe5eb04SJean-Philippe Brucker len, is_write);
148*5fe5eb04SJean-Philippe Brucker return;
149*5fe5eb04SJean-Philippe Brucker }
150*5fe5eb04SJean-Philippe Brucker
151*5fe5eb04SJean-Philippe Brucker if (len != 4) {
152*5fe5eb04SJean-Philippe Brucker pr_debug("Invalid %s size %d at 0x%llx", is_write ? "write" :
153*5fe5eb04SJean-Philippe Brucker "read", len, addr);
154*5fe5eb04SJean-Philippe Brucker return;
155*5fe5eb04SJean-Philippe Brucker }
156*5fe5eb04SJean-Philippe Brucker
157*5fe5eb04SJean-Philippe Brucker if (is_write)
158*5fe5eb04SJean-Philippe Brucker virtio_mmio_config_out(vcpu, offset, (void *)data, len, ptr);
159*5fe5eb04SJean-Philippe Brucker else
160*5fe5eb04SJean-Philippe Brucker virtio_mmio_config_in(vcpu, offset, (void *)data, len, ptr);
161*5fe5eb04SJean-Philippe Brucker }
162