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