]>
Commit | Line | Data |
---|---|---|
967f97fa AL |
1 | /* |
2 | * Virtio Support | |
3 | * | |
4 | * Copyright IBM, Corp. 2007 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <[email protected]> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | * the COPYING file in the top-level directory. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <inttypes.h> | |
967f97fa AL |
15 | |
16 | #include "virtio.h" | |
17 | #include "sysemu.h" | |
18 | ||
967f97fa AL |
19 | /* from Linux's linux/virtio_pci.h */ |
20 | ||
21 | /* A 32-bit r/o bitmask of the features supported by the host */ | |
22 | #define VIRTIO_PCI_HOST_FEATURES 0 | |
23 | ||
24 | /* A 32-bit r/w bitmask of features activated by the guest */ | |
25 | #define VIRTIO_PCI_GUEST_FEATURES 4 | |
26 | ||
27 | /* A 32-bit r/w PFN for the currently selected queue */ | |
28 | #define VIRTIO_PCI_QUEUE_PFN 8 | |
29 | ||
30 | /* A 16-bit r/o queue size for the currently selected queue */ | |
31 | #define VIRTIO_PCI_QUEUE_NUM 12 | |
32 | ||
33 | /* A 16-bit r/w queue selector */ | |
34 | #define VIRTIO_PCI_QUEUE_SEL 14 | |
35 | ||
36 | /* A 16-bit r/w queue notifier */ | |
37 | #define VIRTIO_PCI_QUEUE_NOTIFY 16 | |
38 | ||
39 | /* An 8-bit device status register. */ | |
40 | #define VIRTIO_PCI_STATUS 18 | |
41 | ||
42 | /* An 8-bit r/o interrupt status register. Reading the value will return the | |
43 | * current contents of the ISR and will also clear it. This is effectively | |
44 | * a read-and-acknowledge. */ | |
45 | #define VIRTIO_PCI_ISR 19 | |
46 | ||
47 | #define VIRTIO_PCI_CONFIG 20 | |
48 | ||
49 | /* Virtio ABI version, if we increment this, we break the guest driver. */ | |
50 | #define VIRTIO_PCI_ABI_VERSION 0 | |
51 | ||
f46f15bc AL |
52 | /* How many bits to shift physical queue address written to QUEUE_PFN. |
53 | * 12 is historical, and due to x86 page size. */ | |
54 | #define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 | |
55 | ||
56 | /* The alignment to use between consumer and producer parts of vring. | |
57 | * x86 pagesize again. */ | |
58 | #define VIRTIO_PCI_VRING_ALIGN 4096 | |
59 | ||
967f97fa AL |
60 | /* QEMU doesn't strictly need write barriers since everything runs in |
61 | * lock-step. We'll leave the calls to wmb() in though to make it obvious for | |
62 | * KVM or if kqemu gets SMP support. | |
63 | */ | |
64 | #define wmb() do { } while (0) | |
65 | ||
66 | typedef struct VRingDesc | |
67 | { | |
68 | uint64_t addr; | |
69 | uint32_t len; | |
70 | uint16_t flags; | |
71 | uint16_t next; | |
72 | } VRingDesc; | |
73 | ||
74 | typedef struct VRingAvail | |
75 | { | |
76 | uint16_t flags; | |
77 | uint16_t idx; | |
78 | uint16_t ring[0]; | |
79 | } VRingAvail; | |
80 | ||
81 | typedef struct VRingUsedElem | |
82 | { | |
83 | uint32_t id; | |
84 | uint32_t len; | |
85 | } VRingUsedElem; | |
86 | ||
87 | typedef struct VRingUsed | |
88 | { | |
89 | uint16_t flags; | |
90 | uint16_t idx; | |
91 | VRingUsedElem ring[0]; | |
92 | } VRingUsed; | |
93 | ||
94 | typedef struct VRing | |
95 | { | |
96 | unsigned int num; | |
97 | target_phys_addr_t desc; | |
98 | target_phys_addr_t avail; | |
99 | target_phys_addr_t used; | |
100 | } VRing; | |
101 | ||
102 | struct VirtQueue | |
103 | { | |
104 | VRing vring; | |
105 | uint32_t pfn; | |
106 | uint16_t last_avail_idx; | |
107 | int inuse; | |
108 | void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq); | |
109 | }; | |
110 | ||
111 | #define VIRTIO_PCI_QUEUE_MAX 16 | |
112 | ||
113 | /* virt queue functions */ | |
967f97fa AL |
114 | static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa) |
115 | { | |
116 | vq->vring.desc = pa; | |
117 | vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc); | |
f46f15bc AL |
118 | vq->vring.used = vring_align(vq->vring.avail + |
119 | offsetof(VRingAvail, ring[vq->vring.num]), | |
120 | VIRTIO_PCI_VRING_ALIGN); | |
967f97fa AL |
121 | } |
122 | ||
123 | static inline uint64_t vring_desc_addr(VirtQueue *vq, int i) | |
124 | { | |
125 | target_phys_addr_t pa; | |
126 | pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr); | |
127 | return ldq_phys(pa); | |
128 | } | |
129 | ||
130 | static inline uint32_t vring_desc_len(VirtQueue *vq, int i) | |
131 | { | |
132 | target_phys_addr_t pa; | |
133 | pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, len); | |
134 | return ldl_phys(pa); | |
135 | } | |
136 | ||
137 | static inline uint16_t vring_desc_flags(VirtQueue *vq, int i) | |
138 | { | |
139 | target_phys_addr_t pa; | |
140 | pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags); | |
141 | return lduw_phys(pa); | |
142 | } | |
143 | ||
144 | static inline uint16_t vring_desc_next(VirtQueue *vq, int i) | |
145 | { | |
146 | target_phys_addr_t pa; | |
147 | pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, next); | |
148 | return lduw_phys(pa); | |
149 | } | |
150 | ||
151 | static inline uint16_t vring_avail_flags(VirtQueue *vq) | |
152 | { | |
153 | target_phys_addr_t pa; | |
154 | pa = vq->vring.avail + offsetof(VRingAvail, flags); | |
155 | return lduw_phys(pa); | |
156 | } | |
157 | ||
158 | static inline uint16_t vring_avail_idx(VirtQueue *vq) | |
159 | { | |
160 | target_phys_addr_t pa; | |
161 | pa = vq->vring.avail + offsetof(VRingAvail, idx); | |
162 | return lduw_phys(pa); | |
163 | } | |
164 | ||
165 | static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) | |
166 | { | |
167 | target_phys_addr_t pa; | |
168 | pa = vq->vring.avail + offsetof(VRingAvail, ring[i]); | |
169 | return lduw_phys(pa); | |
170 | } | |
171 | ||
172 | static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val) | |
173 | { | |
174 | target_phys_addr_t pa; | |
175 | pa = vq->vring.used + offsetof(VRingUsed, ring[i].id); | |
176 | stl_phys(pa, val); | |
177 | } | |
178 | ||
179 | static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val) | |
180 | { | |
181 | target_phys_addr_t pa; | |
182 | pa = vq->vring.used + offsetof(VRingUsed, ring[i].len); | |
183 | stl_phys(pa, val); | |
184 | } | |
185 | ||
186 | static uint16_t vring_used_idx(VirtQueue *vq) | |
187 | { | |
188 | target_phys_addr_t pa; | |
189 | pa = vq->vring.used + offsetof(VRingUsed, idx); | |
190 | return lduw_phys(pa); | |
191 | } | |
192 | ||
193 | static inline void vring_used_idx_increment(VirtQueue *vq, uint16_t val) | |
194 | { | |
195 | target_phys_addr_t pa; | |
196 | pa = vq->vring.used + offsetof(VRingUsed, idx); | |
197 | stw_phys(pa, vring_used_idx(vq) + val); | |
198 | } | |
199 | ||
200 | static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) | |
201 | { | |
202 | target_phys_addr_t pa; | |
203 | pa = vq->vring.used + offsetof(VRingUsed, flags); | |
204 | stw_phys(pa, lduw_phys(pa) | mask); | |
205 | } | |
206 | ||
207 | static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) | |
208 | { | |
209 | target_phys_addr_t pa; | |
210 | pa = vq->vring.used + offsetof(VRingUsed, flags); | |
211 | stw_phys(pa, lduw_phys(pa) & ~mask); | |
212 | } | |
213 | ||
214 | void virtio_queue_set_notification(VirtQueue *vq, int enable) | |
215 | { | |
216 | if (enable) | |
217 | vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY); | |
218 | else | |
219 | vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY); | |
220 | } | |
221 | ||
222 | int virtio_queue_ready(VirtQueue *vq) | |
223 | { | |
224 | return vq->vring.avail != 0; | |
225 | } | |
226 | ||
227 | int virtio_queue_empty(VirtQueue *vq) | |
228 | { | |
229 | return vring_avail_idx(vq) == vq->last_avail_idx; | |
230 | } | |
231 | ||
232 | void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, | |
233 | unsigned int len, unsigned int idx) | |
234 | { | |
235 | unsigned int offset; | |
236 | int i; | |
237 | ||
967f97fa AL |
238 | offset = 0; |
239 | for (i = 0; i < elem->in_num; i++) { | |
240 | size_t size = MIN(len - offset, elem->in_sg[i].iov_len); | |
241 | ||
26b258e1 AL |
242 | cpu_physical_memory_unmap(elem->in_sg[i].iov_base, |
243 | elem->in_sg[i].iov_len, | |
244 | 1, size); | |
967f97fa | 245 | |
26b258e1 | 246 | offset += elem->in_sg[i].iov_len; |
967f97fa AL |
247 | } |
248 | ||
26b258e1 AL |
249 | for (i = 0; i < elem->out_num; i++) |
250 | cpu_physical_memory_unmap(elem->out_sg[i].iov_base, | |
251 | elem->out_sg[i].iov_len, | |
252 | 0, elem->out_sg[i].iov_len); | |
253 | ||
967f97fa AL |
254 | idx = (idx + vring_used_idx(vq)) % vq->vring.num; |
255 | ||
256 | /* Get a pointer to the next entry in the used ring. */ | |
257 | vring_used_ring_id(vq, idx, elem->index); | |
258 | vring_used_ring_len(vq, idx, len); | |
259 | } | |
260 | ||
261 | void virtqueue_flush(VirtQueue *vq, unsigned int count) | |
262 | { | |
263 | /* Make sure buffer is written before we update index. */ | |
264 | wmb(); | |
265 | vring_used_idx_increment(vq, count); | |
266 | vq->inuse -= count; | |
267 | } | |
268 | ||
269 | void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, | |
270 | unsigned int len) | |
271 | { | |
272 | virtqueue_fill(vq, elem, len, 0); | |
273 | virtqueue_flush(vq, 1); | |
274 | } | |
275 | ||
276 | static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) | |
277 | { | |
278 | uint16_t num_heads = vring_avail_idx(vq) - idx; | |
279 | ||
280 | /* Check it isn't doing very strange things with descriptor numbers. */ | |
bb6834cf AL |
281 | if (num_heads > vq->vring.num) { |
282 | fprintf(stderr, "Guest moved used index from %u to %u", | |
283 | idx, vring_avail_idx(vq)); | |
284 | exit(1); | |
285 | } | |
967f97fa AL |
286 | |
287 | return num_heads; | |
288 | } | |
289 | ||
290 | static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) | |
291 | { | |
292 | unsigned int head; | |
293 | ||
294 | /* Grab the next descriptor number they're advertising, and increment | |
295 | * the index we've seen. */ | |
296 | head = vring_avail_ring(vq, idx % vq->vring.num); | |
297 | ||
298 | /* If their number is silly, that's a fatal mistake. */ | |
bb6834cf AL |
299 | if (head >= vq->vring.num) { |
300 | fprintf(stderr, "Guest says index %u is available", head); | |
301 | exit(1); | |
302 | } | |
967f97fa AL |
303 | |
304 | return head; | |
305 | } | |
306 | ||
307 | static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i) | |
308 | { | |
309 | unsigned int next; | |
310 | ||
311 | /* If this descriptor says it doesn't chain, we're done. */ | |
312 | if (!(vring_desc_flags(vq, i) & VRING_DESC_F_NEXT)) | |
313 | return vq->vring.num; | |
314 | ||
315 | /* Check they're not leading us off end of descriptors. */ | |
316 | next = vring_desc_next(vq, i); | |
317 | /* Make sure compiler knows to grab that: we don't want it changing! */ | |
318 | wmb(); | |
319 | ||
bb6834cf AL |
320 | if (next >= vq->vring.num) { |
321 | fprintf(stderr, "Desc next is %u", next); | |
322 | exit(1); | |
323 | } | |
967f97fa AL |
324 | |
325 | return next; | |
326 | } | |
327 | ||
328 | int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) | |
329 | { | |
330 | unsigned int idx; | |
331 | int num_bufs, in_total, out_total; | |
332 | ||
333 | idx = vq->last_avail_idx; | |
334 | ||
335 | num_bufs = in_total = out_total = 0; | |
336 | while (virtqueue_num_heads(vq, idx)) { | |
337 | int i; | |
338 | ||
339 | i = virtqueue_get_head(vq, idx++); | |
340 | do { | |
341 | /* If we've got too many, that implies a descriptor loop. */ | |
bb6834cf AL |
342 | if (++num_bufs > vq->vring.num) { |
343 | fprintf(stderr, "Looped descriptor"); | |
344 | exit(1); | |
345 | } | |
967f97fa AL |
346 | |
347 | if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) { | |
348 | if (in_bytes > 0 && | |
349 | (in_total += vring_desc_len(vq, i)) >= in_bytes) | |
350 | return 1; | |
351 | } else { | |
352 | if (out_bytes > 0 && | |
353 | (out_total += vring_desc_len(vq, i)) >= out_bytes) | |
354 | return 1; | |
355 | } | |
356 | } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num); | |
357 | } | |
358 | ||
359 | return 0; | |
360 | } | |
361 | ||
362 | int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) | |
363 | { | |
364 | unsigned int i, head; | |
26b258e1 | 365 | target_phys_addr_t len; |
967f97fa AL |
366 | |
367 | if (!virtqueue_num_heads(vq, vq->last_avail_idx)) | |
368 | return 0; | |
369 | ||
370 | /* When we start there are none of either input nor output. */ | |
371 | elem->out_num = elem->in_num = 0; | |
372 | ||
373 | i = head = virtqueue_get_head(vq, vq->last_avail_idx++); | |
374 | do { | |
375 | struct iovec *sg; | |
26b258e1 | 376 | int is_write = 0; |
967f97fa AL |
377 | |
378 | if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) { | |
379 | elem->in_addr[elem->in_num] = vring_desc_addr(vq, i); | |
380 | sg = &elem->in_sg[elem->in_num++]; | |
26b258e1 | 381 | is_write = 1; |
967f97fa AL |
382 | } else |
383 | sg = &elem->out_sg[elem->out_num++]; | |
384 | ||
385 | /* Grab the first descriptor, and check it's OK. */ | |
386 | sg->iov_len = vring_desc_len(vq, i); | |
26b258e1 | 387 | len = sg->iov_len; |
967f97fa | 388 | |
26b258e1 AL |
389 | sg->iov_base = cpu_physical_memory_map(vring_desc_addr(vq, i), &len, is_write); |
390 | ||
391 | if (sg->iov_base == NULL || len != sg->iov_len) { | |
392 | fprintf(stderr, "virtio: trying to map MMIO memory\n"); | |
bb6834cf AL |
393 | exit(1); |
394 | } | |
967f97fa AL |
395 | |
396 | /* If we've got too many, that implies a descriptor loop. */ | |
bb6834cf AL |
397 | if ((elem->in_num + elem->out_num) > vq->vring.num) { |
398 | fprintf(stderr, "Looped descriptor"); | |
399 | exit(1); | |
400 | } | |
967f97fa AL |
401 | } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num); |
402 | ||
403 | elem->index = head; | |
404 | ||
405 | vq->inuse++; | |
406 | ||
407 | return elem->in_num + elem->out_num; | |
408 | } | |
409 | ||
410 | /* virtio device */ | |
411 | ||
412 | static VirtIODevice *to_virtio_device(PCIDevice *pci_dev) | |
413 | { | |
414 | return (VirtIODevice *)pci_dev; | |
415 | } | |
416 | ||
417 | static void virtio_update_irq(VirtIODevice *vdev) | |
418 | { | |
419 | qemu_set_irq(vdev->pci_dev.irq[0], vdev->isr & 1); | |
420 | } | |
421 | ||
69d6451c | 422 | static void virtio_reset(void *opaque) |
967f97fa AL |
423 | { |
424 | VirtIODevice *vdev = opaque; | |
425 | int i; | |
426 | ||
427 | if (vdev->reset) | |
428 | vdev->reset(vdev); | |
429 | ||
430 | vdev->features = 0; | |
431 | vdev->queue_sel = 0; | |
432 | vdev->status = 0; | |
433 | vdev->isr = 0; | |
434 | virtio_update_irq(vdev); | |
435 | ||
436 | for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { | |
437 | vdev->vq[i].vring.desc = 0; | |
438 | vdev->vq[i].vring.avail = 0; | |
439 | vdev->vq[i].vring.used = 0; | |
440 | vdev->vq[i].last_avail_idx = 0; | |
441 | vdev->vq[i].pfn = 0; | |
442 | } | |
443 | } | |
444 | ||
445 | static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) | |
446 | { | |
447 | VirtIODevice *vdev = to_virtio_device(opaque); | |
448 | ram_addr_t pa; | |
449 | ||
450 | addr -= vdev->addr; | |
451 | ||
452 | switch (addr) { | |
453 | case VIRTIO_PCI_GUEST_FEATURES: | |
8eca6b1b AL |
454 | /* Guest does not negotiate properly? We have to assume nothing. */ |
455 | if (val & (1 << VIRTIO_F_BAD_FEATURE)) { | |
456 | if (vdev->bad_features) | |
457 | val = vdev->bad_features(vdev); | |
458 | else | |
459 | val = 0; | |
460 | } | |
967f97fa AL |
461 | if (vdev->set_features) |
462 | vdev->set_features(vdev, val); | |
463 | vdev->features = val; | |
464 | break; | |
465 | case VIRTIO_PCI_QUEUE_PFN: | |
f46f15bc | 466 | pa = (ram_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
967f97fa AL |
467 | vdev->vq[vdev->queue_sel].pfn = val; |
468 | if (pa == 0) { | |
469 | virtio_reset(vdev); | |
470 | } else { | |
471 | virtqueue_init(&vdev->vq[vdev->queue_sel], pa); | |
472 | } | |
473 | break; | |
474 | case VIRTIO_PCI_QUEUE_SEL: | |
475 | if (val < VIRTIO_PCI_QUEUE_MAX) | |
476 | vdev->queue_sel = val; | |
477 | break; | |
478 | case VIRTIO_PCI_QUEUE_NOTIFY: | |
479 | if (val < VIRTIO_PCI_QUEUE_MAX && vdev->vq[val].vring.desc) | |
480 | vdev->vq[val].handle_output(vdev, &vdev->vq[val]); | |
481 | break; | |
482 | case VIRTIO_PCI_STATUS: | |
483 | vdev->status = val & 0xFF; | |
484 | if (vdev->status == 0) | |
485 | virtio_reset(vdev); | |
486 | break; | |
487 | } | |
488 | } | |
489 | ||
490 | static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) | |
491 | { | |
492 | VirtIODevice *vdev = to_virtio_device(opaque); | |
493 | uint32_t ret = 0xFFFFFFFF; | |
494 | ||
495 | addr -= vdev->addr; | |
496 | ||
497 | switch (addr) { | |
498 | case VIRTIO_PCI_HOST_FEATURES: | |
499 | ret = vdev->get_features(vdev); | |
8eca6b1b | 500 | ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); |
967f97fa AL |
501 | break; |
502 | case VIRTIO_PCI_GUEST_FEATURES: | |
503 | ret = vdev->features; | |
504 | break; | |
505 | case VIRTIO_PCI_QUEUE_PFN: | |
506 | ret = vdev->vq[vdev->queue_sel].pfn; | |
507 | break; | |
508 | case VIRTIO_PCI_QUEUE_NUM: | |
509 | ret = vdev->vq[vdev->queue_sel].vring.num; | |
510 | break; | |
511 | case VIRTIO_PCI_QUEUE_SEL: | |
512 | ret = vdev->queue_sel; | |
513 | break; | |
514 | case VIRTIO_PCI_STATUS: | |
515 | ret = vdev->status; | |
516 | break; | |
517 | case VIRTIO_PCI_ISR: | |
518 | /* reading from the ISR also clears it. */ | |
519 | ret = vdev->isr; | |
520 | vdev->isr = 0; | |
521 | virtio_update_irq(vdev); | |
522 | break; | |
523 | default: | |
524 | break; | |
525 | } | |
526 | ||
527 | return ret; | |
528 | } | |
529 | ||
530 | static uint32_t virtio_config_readb(void *opaque, uint32_t addr) | |
531 | { | |
532 | VirtIODevice *vdev = opaque; | |
533 | uint8_t val; | |
534 | ||
535 | vdev->get_config(vdev, vdev->config); | |
536 | ||
537 | addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
538 | if (addr > (vdev->config_len - sizeof(val))) | |
539 | return (uint32_t)-1; | |
540 | ||
541 | memcpy(&val, vdev->config + addr, sizeof(val)); | |
542 | return val; | |
543 | } | |
544 | ||
545 | static uint32_t virtio_config_readw(void *opaque, uint32_t addr) | |
546 | { | |
547 | VirtIODevice *vdev = opaque; | |
548 | uint16_t val; | |
549 | ||
550 | vdev->get_config(vdev, vdev->config); | |
551 | ||
552 | addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
553 | if (addr > (vdev->config_len - sizeof(val))) | |
554 | return (uint32_t)-1; | |
555 | ||
556 | memcpy(&val, vdev->config + addr, sizeof(val)); | |
557 | return val; | |
558 | } | |
559 | ||
560 | static uint32_t virtio_config_readl(void *opaque, uint32_t addr) | |
561 | { | |
562 | VirtIODevice *vdev = opaque; | |
563 | uint32_t val; | |
564 | ||
565 | vdev->get_config(vdev, vdev->config); | |
566 | ||
567 | addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
568 | if (addr > (vdev->config_len - sizeof(val))) | |
569 | return (uint32_t)-1; | |
570 | ||
571 | memcpy(&val, vdev->config + addr, sizeof(val)); | |
572 | return val; | |
573 | } | |
574 | ||
575 | static void virtio_config_writeb(void *opaque, uint32_t addr, uint32_t data) | |
576 | { | |
577 | VirtIODevice *vdev = opaque; | |
578 | uint8_t val = data; | |
579 | ||
580 | addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
581 | if (addr > (vdev->config_len - sizeof(val))) | |
582 | return; | |
583 | ||
584 | memcpy(vdev->config + addr, &val, sizeof(val)); | |
585 | ||
586 | if (vdev->set_config) | |
587 | vdev->set_config(vdev, vdev->config); | |
588 | } | |
589 | ||
590 | static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data) | |
591 | { | |
592 | VirtIODevice *vdev = opaque; | |
593 | uint16_t val = data; | |
594 | ||
595 | addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
596 | if (addr > (vdev->config_len - sizeof(val))) | |
597 | return; | |
598 | ||
599 | memcpy(vdev->config + addr, &val, sizeof(val)); | |
600 | ||
601 | if (vdev->set_config) | |
602 | vdev->set_config(vdev, vdev->config); | |
603 | } | |
604 | ||
605 | static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data) | |
606 | { | |
607 | VirtIODevice *vdev = opaque; | |
608 | uint32_t val = data; | |
609 | ||
610 | addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
611 | if (addr > (vdev->config_len - sizeof(val))) | |
612 | return; | |
613 | ||
614 | memcpy(vdev->config + addr, &val, sizeof(val)); | |
615 | ||
616 | if (vdev->set_config) | |
617 | vdev->set_config(vdev, vdev->config); | |
618 | } | |
619 | ||
620 | static void virtio_map(PCIDevice *pci_dev, int region_num, | |
621 | uint32_t addr, uint32_t size, int type) | |
622 | { | |
623 | VirtIODevice *vdev = to_virtio_device(pci_dev); | |
624 | int i; | |
625 | ||
626 | vdev->addr = addr; | |
627 | for (i = 0; i < 3; i++) { | |
628 | register_ioport_write(addr, 20, 1 << i, virtio_ioport_write, vdev); | |
629 | register_ioport_read(addr, 20, 1 << i, virtio_ioport_read, vdev); | |
630 | } | |
631 | ||
632 | if (vdev->config_len) { | |
633 | register_ioport_write(addr + 20, vdev->config_len, 1, | |
634 | virtio_config_writeb, vdev); | |
635 | register_ioport_write(addr + 20, vdev->config_len, 2, | |
636 | virtio_config_writew, vdev); | |
637 | register_ioport_write(addr + 20, vdev->config_len, 4, | |
638 | virtio_config_writel, vdev); | |
639 | register_ioport_read(addr + 20, vdev->config_len, 1, | |
640 | virtio_config_readb, vdev); | |
641 | register_ioport_read(addr + 20, vdev->config_len, 2, | |
642 | virtio_config_readw, vdev); | |
643 | register_ioport_read(addr + 20, vdev->config_len, 4, | |
644 | virtio_config_readl, vdev); | |
645 | ||
646 | vdev->get_config(vdev, vdev->config); | |
647 | } | |
648 | } | |
649 | ||
650 | VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, | |
651 | void (*handle_output)(VirtIODevice *, VirtQueue *)) | |
652 | { | |
653 | int i; | |
654 | ||
655 | for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { | |
656 | if (vdev->vq[i].vring.num == 0) | |
657 | break; | |
658 | } | |
659 | ||
660 | if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE) | |
661 | abort(); | |
662 | ||
663 | vdev->vq[i].vring.num = queue_size; | |
664 | vdev->vq[i].handle_output = handle_output; | |
665 | ||
666 | return &vdev->vq[i]; | |
667 | } | |
668 | ||
669 | void virtio_notify(VirtIODevice *vdev, VirtQueue *vq) | |
670 | { | |
97b83deb AL |
671 | /* Always notify when queue is empty (when feature acknowledge) */ |
672 | if ((vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT) && | |
673 | (!(vdev->features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) || | |
674 | (vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx))) | |
967f97fa AL |
675 | return; |
676 | ||
677 | vdev->isr |= 0x01; | |
678 | virtio_update_irq(vdev); | |
679 | } | |
680 | ||
681 | void virtio_notify_config(VirtIODevice *vdev) | |
682 | { | |
7625162c AL |
683 | if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) |
684 | return; | |
685 | ||
967f97fa AL |
686 | vdev->isr |= 0x03; |
687 | virtio_update_irq(vdev); | |
688 | } | |
689 | ||
690 | void virtio_save(VirtIODevice *vdev, QEMUFile *f) | |
691 | { | |
692 | int i; | |
693 | ||
694 | pci_device_save(&vdev->pci_dev, f); | |
695 | ||
696 | qemu_put_be32s(f, &vdev->addr); | |
697 | qemu_put_8s(f, &vdev->status); | |
698 | qemu_put_8s(f, &vdev->isr); | |
699 | qemu_put_be16s(f, &vdev->queue_sel); | |
700 | qemu_put_be32s(f, &vdev->features); | |
701 | qemu_put_be32(f, vdev->config_len); | |
702 | qemu_put_buffer(f, vdev->config, vdev->config_len); | |
703 | ||
704 | for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { | |
705 | if (vdev->vq[i].vring.num == 0) | |
706 | break; | |
707 | } | |
708 | ||
709 | qemu_put_be32(f, i); | |
710 | ||
711 | for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { | |
712 | if (vdev->vq[i].vring.num == 0) | |
713 | break; | |
714 | ||
715 | qemu_put_be32(f, vdev->vq[i].vring.num); | |
716 | qemu_put_be32s(f, &vdev->vq[i].pfn); | |
717 | qemu_put_be16s(f, &vdev->vq[i].last_avail_idx); | |
718 | } | |
719 | } | |
720 | ||
721 | void virtio_load(VirtIODevice *vdev, QEMUFile *f) | |
722 | { | |
723 | int num, i; | |
724 | ||
725 | pci_device_load(&vdev->pci_dev, f); | |
726 | ||
727 | qemu_get_be32s(f, &vdev->addr); | |
728 | qemu_get_8s(f, &vdev->status); | |
729 | qemu_get_8s(f, &vdev->isr); | |
730 | qemu_get_be16s(f, &vdev->queue_sel); | |
731 | qemu_get_be32s(f, &vdev->features); | |
732 | vdev->config_len = qemu_get_be32(f); | |
733 | qemu_get_buffer(f, vdev->config, vdev->config_len); | |
734 | ||
735 | num = qemu_get_be32(f); | |
736 | ||
737 | for (i = 0; i < num; i++) { | |
738 | vdev->vq[i].vring.num = qemu_get_be32(f); | |
739 | qemu_get_be32s(f, &vdev->vq[i].pfn); | |
740 | qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); | |
741 | ||
742 | if (vdev->vq[i].pfn) { | |
743 | target_phys_addr_t pa; | |
744 | ||
f46f15bc | 745 | pa = (ram_addr_t)vdev->vq[i].pfn << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
967f97fa AL |
746 | virtqueue_init(&vdev->vq[i], pa); |
747 | } | |
748 | } | |
749 | ||
750 | virtio_update_irq(vdev); | |
751 | } | |
752 | ||
b946a153 AL |
753 | void virtio_cleanup(VirtIODevice *vdev) |
754 | { | |
755 | if (vdev->config) | |
756 | qemu_free(vdev->config); | |
757 | qemu_free(vdev->vq); | |
758 | } | |
759 | ||
967f97fa AL |
760 | VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name, |
761 | uint16_t vendor, uint16_t device, | |
762 | uint16_t subvendor, uint16_t subdevice, | |
173a543b BS |
763 | uint16_t class_code, uint8_t pif, |
764 | size_t config_size, size_t struct_size) | |
967f97fa AL |
765 | { |
766 | VirtIODevice *vdev; | |
767 | PCIDevice *pci_dev; | |
768 | uint8_t *config; | |
769 | uint32_t size; | |
770 | ||
771 | pci_dev = pci_register_device(bus, name, struct_size, | |
772 | -1, NULL, NULL); | |
773 | if (!pci_dev) | |
774 | return NULL; | |
775 | ||
776 | vdev = to_virtio_device(pci_dev); | |
777 | ||
778 | vdev->status = 0; | |
779 | vdev->isr = 0; | |
780 | vdev->queue_sel = 0; | |
781 | vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX); | |
782 | ||
783 | config = pci_dev->config; | |
deb54399 AL |
784 | pci_config_set_vendor_id(config, vendor); |
785 | pci_config_set_device_id(config, device); | |
967f97fa AL |
786 | |
787 | config[0x08] = VIRTIO_PCI_ABI_VERSION; | |
788 | ||
789 | config[0x09] = pif; | |
173a543b | 790 | pci_config_set_class(config, class_code); |
6407f373 | 791 | config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; |
967f97fa AL |
792 | |
793 | config[0x2c] = subvendor & 0xFF; | |
794 | config[0x2d] = (subvendor >> 8) & 0xFF; | |
795 | config[0x2e] = subdevice & 0xFF; | |
796 | config[0x2f] = (subdevice >> 8) & 0xFF; | |
797 | ||
798 | config[0x3d] = 1; | |
799 | ||
800 | vdev->name = name; | |
801 | vdev->config_len = config_size; | |
802 | if (vdev->config_len) | |
803 | vdev->config = qemu_mallocz(config_size); | |
804 | else | |
805 | vdev->config = NULL; | |
806 | ||
807 | size = 20 + config_size; | |
808 | if (size & (size-1)) | |
ad46db9a | 809 | size = 1 << qemu_fls(size); |
967f97fa AL |
810 | |
811 | pci_register_io_region(pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, | |
812 | virtio_map); | |
813 | qemu_register_reset(virtio_reset, vdev); | |
814 | ||
815 | return vdev; | |
816 | } |