Revision 53c25cea
b/Makefile.target | ||
---|---|---|
489 | 489 |
gdbstub.o gdbstub-xml.o sysbus.o |
490 | 490 |
# virtio has to be here due to weird dependency between PCI and virtio-net. |
491 | 491 |
# need to fix this properly |
492 |
OBJS+=virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o |
|
492 |
OBJS+=virtio.o virtio-pci.o |
|
493 |
OBJS+=virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o |
|
493 | 494 |
OBJS+=fw_cfg.o |
494 | 495 |
ifdef CONFIG_KVM |
495 | 496 |
OBJS+=kvm.o kvm-all.o |
b/hw/pc.c | ||
---|---|---|
1137 | 1137 |
int unit_id = 0; |
1138 | 1138 |
|
1139 | 1139 |
while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { |
1140 |
pci_create_simple(pci_bus, -1, "virtio-blk"); |
|
1140 |
pci_create_simple(pci_bus, -1, "virtio-blk-pci");
|
|
1141 | 1141 |
unit_id++; |
1142 | 1142 |
} |
1143 | 1143 |
} |
1144 | 1144 |
|
1145 | 1145 |
/* Add virtio balloon device */ |
1146 | 1146 |
if (pci_enabled) { |
1147 |
pci_create_simple(pci_bus, -1, "virtio-balloon"); |
|
1147 |
pci_create_simple(pci_bus, -1, "virtio-balloon-pci");
|
|
1148 | 1148 |
} |
1149 | 1149 |
|
1150 | 1150 |
/* Add virtio console devices */ |
1151 | 1151 |
if (pci_enabled) { |
1152 | 1152 |
for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { |
1153 | 1153 |
if (virtcon_hds[i]) { |
1154 |
pci_create_simple(pci_bus, -1, "virtio-console"); |
|
1154 |
pci_create_simple(pci_bus, -1, "virtio-console-pci");
|
|
1155 | 1155 |
} |
1156 | 1156 |
} |
1157 | 1157 |
} |
b/hw/pci-hotplug.c | ||
---|---|---|
120 | 120 |
opaque = pci_create_simple(pci_bus, -1, "lsi53c895a"); |
121 | 121 |
break; |
122 | 122 |
case IF_VIRTIO: |
123 |
opaque = pci_create_simple(pci_bus, -1, "virtio-blk"); |
|
123 |
opaque = pci_create_simple(pci_bus, -1, "virtio-blk-pci");
|
|
124 | 124 |
qdev_init(opaque); |
125 | 125 |
break; |
126 | 126 |
} |
b/hw/pci.c | ||
---|---|---|
806 | 806 |
"rtl8139", |
807 | 807 |
"e1000", |
808 | 808 |
"pcnet", |
809 |
"virtio_net",
|
|
809 |
"virtio-net-pci",
|
|
810 | 810 |
NULL |
811 | 811 |
}; |
812 | 812 |
|
b/hw/ppc440_bamboo.c | ||
---|---|---|
111 | 111 |
|
112 | 112 |
/* Add virtio block devices. */ |
113 | 113 |
while ((i = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { |
114 |
pci_create_simple(pcibus, -1, "virtio-blk"); |
|
114 |
pci_create_simple(pcibus, -1, "virtio-blk-pci");
|
|
115 | 115 |
unit_id++; |
116 | 116 |
} |
117 | 117 |
|
118 | 118 |
/* Add virtio console devices */ |
119 | 119 |
for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { |
120 | 120 |
if (virtcon_hds[i]) { |
121 |
pci_create_simple(pcibus, -1, "virtio-console"); |
|
121 |
pci_create_simple(pcibus, -1, "virtio-console-pci");
|
|
122 | 122 |
} |
123 | 123 |
} |
124 | 124 |
|
b/hw/ppce500_mpc8544ds.c | ||
---|---|---|
220 | 220 |
|
221 | 221 |
/* Add virtio block devices. */ |
222 | 222 |
while ((i = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { |
223 |
pci_create_simple(pci_bus, -1, "virtio-blk"); |
|
223 |
pci_create_simple(pci_bus, -1, "virtio-blk-pci");
|
|
224 | 224 |
unit_id++; |
225 | 225 |
} |
226 | 226 |
|
b/hw/virtio-balloon.c | ||
---|---|---|
169 | 169 |
return 0; |
170 | 170 |
} |
171 | 171 |
|
172 |
static void virtio_balloon_init(PCIDevice *pci_dev)
|
|
172 |
VirtIODevice *virtio_balloon_init(DeviceState *dev)
|
|
173 | 173 |
{ |
174 | 174 |
VirtIOBalloon *s; |
175 | 175 |
|
176 |
s = (VirtIOBalloon *)virtio_init_pci(pci_dev, "virtio-balloon", |
|
177 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
178 |
PCI_DEVICE_ID_VIRTIO_BALLOON, |
|
179 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
180 |
VIRTIO_ID_BALLOON, |
|
181 |
PCI_CLASS_MEMORY_RAM, 0x00, |
|
182 |
8); |
|
176 |
s = (VirtIOBalloon *)virtio_common_init("virtio-balloon", |
|
177 |
VIRTIO_ID_BALLOON, |
|
178 |
8, sizeof(VirtIOBalloon)); |
|
183 | 179 |
|
184 | 180 |
s->vdev.get_config = virtio_balloon_get_config; |
185 | 181 |
s->vdev.set_config = virtio_balloon_set_config; |
... | ... | |
191 | 187 |
qemu_add_balloon_handler(virtio_balloon_to_target, s); |
192 | 188 |
|
193 | 189 |
register_savevm("virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); |
194 |
} |
|
195 | 190 |
|
196 |
static void virtio_balloon_register_devices(void) |
|
197 |
{ |
|
198 |
pci_qdev_register("virtio-balloon", sizeof(VirtIOBalloon), |
|
199 |
virtio_balloon_init); |
|
191 |
return &s->vdev; |
|
200 | 192 |
} |
201 |
|
|
202 |
device_init(virtio_balloon_register_devices) |
b/hw/virtio-blk.c | ||
---|---|---|
348 | 348 |
return 0; |
349 | 349 |
} |
350 | 350 |
|
351 |
static void virtio_blk_init(PCIDevice *pci_dev)
|
|
351 |
VirtIODevice *virtio_blk_init(DeviceState *dev)
|
|
352 | 352 |
{ |
353 | 353 |
VirtIOBlock *s; |
354 | 354 |
int cylinders, heads, secs; |
355 | 355 |
static int virtio_blk_id; |
356 | 356 |
BlockDriverState *bs; |
357 | 357 |
|
358 |
s = (VirtIOBlock *)virtio_init_pci(pci_dev, "virtio-blk", |
|
359 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
360 |
PCI_DEVICE_ID_VIRTIO_BLOCK, |
|
361 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
362 |
VIRTIO_ID_BLOCK, |
|
363 |
PCI_CLASS_STORAGE_OTHER, 0x00, |
|
364 |
sizeof(struct virtio_blk_config)); |
|
358 |
s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK, |
|
359 |
sizeof(struct virtio_blk_config), |
|
360 |
sizeof(VirtIOBlock)); |
|
365 | 361 |
|
366 |
bs = qdev_init_bdrv(&pci_dev->qdev, IF_VIRTIO);
|
|
362 |
bs = qdev_init_bdrv(dev, IF_VIRTIO); |
|
367 | 363 |
s->vdev.get_config = virtio_blk_update_config; |
368 | 364 |
s->vdev.get_features = virtio_blk_get_features; |
369 | 365 |
s->vdev.reset = virtio_blk_reset; |
370 | 366 |
s->bs = bs; |
371 | 367 |
s->rq = NULL; |
372 |
bs->private = &s->vdev.pci_dev;
|
|
368 |
bs->private = dev; |
|
373 | 369 |
bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); |
374 | 370 |
bdrv_set_geometry_hint(s->bs, cylinders, heads, secs); |
375 | 371 |
|
... | ... | |
378 | 374 |
qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); |
379 | 375 |
register_savevm("virtio-blk", virtio_blk_id++, 2, |
380 | 376 |
virtio_blk_save, virtio_blk_load, s); |
381 |
} |
|
382 | 377 |
|
383 |
static void virtio_blk_register_devices(void) |
|
384 |
{ |
|
385 |
pci_qdev_register("virtio-blk", sizeof(VirtIOBlock), virtio_blk_init); |
|
378 |
return &s->vdev; |
|
386 | 379 |
} |
387 |
|
|
388 |
device_init(virtio_blk_register_devices) |
b/hw/virtio-blk.h | ||
---|---|---|
16 | 16 |
|
17 | 17 |
#include "virtio.h" |
18 | 18 |
#include "block.h" |
19 |
#include "pci.h" |
|
20 | 19 |
|
21 | 20 |
/* from Linux's linux/virtio_blk.h */ |
22 | 21 |
|
b/hw/virtio-console.c | ||
---|---|---|
123 | 123 |
return 0; |
124 | 124 |
} |
125 | 125 |
|
126 |
static void virtio_console_init(PCIDevice *pci_dev)
|
|
126 |
VirtIODevice *virtio_console_init(DeviceState *dev)
|
|
127 | 127 |
{ |
128 | 128 |
VirtIOConsole *s; |
129 |
s = (VirtIOConsole *)virtio_init_pci(pci_dev, "virtio-console", |
|
130 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
131 |
PCI_DEVICE_ID_VIRTIO_CONSOLE, |
|
132 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
133 |
VIRTIO_ID_CONSOLE, |
|
134 |
PCI_CLASS_DISPLAY_OTHER, 0x00, |
|
135 |
0); |
|
129 |
s = (VirtIOConsole *)virtio_common_init("virtio-console", |
|
130 |
VIRTIO_ID_CONSOLE, |
|
131 |
0, sizeof(VirtIOConsole)); |
|
136 | 132 |
s->vdev.get_features = virtio_console_get_features; |
137 | 133 |
|
138 | 134 |
s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input); |
139 | 135 |
s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output); |
140 | 136 |
|
141 |
s->chr = qdev_init_chardev(&pci_dev->qdev);
|
|
137 |
s->chr = qdev_init_chardev(dev); |
|
142 | 138 |
qemu_chr_add_handlers(s->chr, vcon_can_read, vcon_read, vcon_event, s); |
143 | 139 |
|
144 | 140 |
register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s); |
145 |
} |
|
146 | 141 |
|
147 |
static void virtio_console_register_devices(void) |
|
148 |
{ |
|
149 |
pci_qdev_register("virtio-console", sizeof(VirtIOConsole), |
|
150 |
virtio_console_init); |
|
142 |
return &s->vdev; |
|
151 | 143 |
} |
152 |
|
|
153 |
device_init(virtio_console_register_devices) |
b/hw/virtio-net.c | ||
---|---|---|
585 | 585 |
virtio_cleanup(&n->vdev); |
586 | 586 |
} |
587 | 587 |
|
588 |
static void virtio_net_init(PCIDevice *pci_dev)
|
|
588 |
VirtIODevice *virtio_net_init(DeviceState *dev)
|
|
589 | 589 |
{ |
590 | 590 |
VirtIONet *n; |
591 | 591 |
static int virtio_net_id; |
592 | 592 |
|
593 |
n = (VirtIONet *)virtio_init_pci(pci_dev, "virtio-net", |
|
594 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
595 |
PCI_DEVICE_ID_VIRTIO_NET, |
|
596 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
597 |
VIRTIO_ID_NET, |
|
598 |
PCI_CLASS_NETWORK_ETHERNET, 0x00, |
|
599 |
sizeof(struct virtio_net_config)); |
|
593 |
n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET, |
|
594 |
sizeof(struct virtio_net_config), |
|
595 |
sizeof(VirtIONet)); |
|
600 | 596 |
|
601 | 597 |
n->vdev.get_config = virtio_net_get_config; |
602 | 598 |
n->vdev.set_config = virtio_net_set_config; |
... | ... | |
607 | 603 |
n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); |
608 | 604 |
n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx); |
609 | 605 |
n->ctrl_vq = virtio_add_queue(&n->vdev, 16, virtio_net_handle_ctrl); |
610 |
qdev_get_macaddr(&pci_dev->qdev, n->mac);
|
|
606 |
qdev_get_macaddr(dev, n->mac); |
|
611 | 607 |
n->status = VIRTIO_NET_S_LINK_UP; |
612 |
n->vc = qdev_get_vlan_client(&pci_dev->qdev,
|
|
608 |
n->vc = qdev_get_vlan_client(dev, |
|
613 | 609 |
virtio_net_receive, |
614 | 610 |
virtio_net_can_receive, |
615 | 611 |
virtio_net_cleanup, n); |
... | ... | |
628 | 624 |
|
629 | 625 |
register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION, |
630 | 626 |
virtio_net_save, virtio_net_load, n); |
631 |
} |
|
632 | 627 |
|
633 |
static void virtio_net_register_devices(void) |
|
634 |
{ |
|
635 |
pci_qdev_register("virtio_net", sizeof(VirtIONet), virtio_net_init); |
|
628 |
return &n->vdev; |
|
636 | 629 |
} |
637 |
|
|
638 |
device_init(virtio_net_register_devices) |
b/hw/virtio-pci.c | ||
---|---|---|
1 |
/* |
|
2 |
* Virtio PCI Bindings |
|
3 |
* |
|
4 |
* Copyright IBM, Corp. 2007 |
|
5 |
* Copyright (c) 2009 CodeSourcery |
|
6 |
* |
|
7 |
* Authors: |
|
8 |
* Anthony Liguori <aliguori@us.ibm.com> |
|
9 |
* Paul Brook <paul@codesourcery.com> |
|
10 |
* |
|
11 |
* This work is licensed under the terms of the GNU GPL, version 2. See |
|
12 |
* the COPYING file in the top-level directory. |
|
13 |
* |
|
14 |
*/ |
|
15 |
|
|
16 |
#include <inttypes.h> |
|
17 |
|
|
18 |
#include "virtio.h" |
|
19 |
#include "pci.h" |
|
20 |
#include "sysemu.h" |
|
21 |
|
|
22 |
/* from Linux's linux/virtio_pci.h */ |
|
23 |
|
|
24 |
/* A 32-bit r/o bitmask of the features supported by the host */ |
|
25 |
#define VIRTIO_PCI_HOST_FEATURES 0 |
|
26 |
|
|
27 |
/* A 32-bit r/w bitmask of features activated by the guest */ |
|
28 |
#define VIRTIO_PCI_GUEST_FEATURES 4 |
|
29 |
|
|
30 |
/* A 32-bit r/w PFN for the currently selected queue */ |
|
31 |
#define VIRTIO_PCI_QUEUE_PFN 8 |
|
32 |
|
|
33 |
/* A 16-bit r/o queue size for the currently selected queue */ |
|
34 |
#define VIRTIO_PCI_QUEUE_NUM 12 |
|
35 |
|
|
36 |
/* A 16-bit r/w queue selector */ |
|
37 |
#define VIRTIO_PCI_QUEUE_SEL 14 |
|
38 |
|
|
39 |
/* A 16-bit r/w queue notifier */ |
|
40 |
#define VIRTIO_PCI_QUEUE_NOTIFY 16 |
|
41 |
|
|
42 |
/* An 8-bit device status register. */ |
|
43 |
#define VIRTIO_PCI_STATUS 18 |
|
44 |
|
|
45 |
/* An 8-bit r/o interrupt status register. Reading the value will return the |
|
46 |
* current contents of the ISR and will also clear it. This is effectively |
|
47 |
* a read-and-acknowledge. */ |
|
48 |
#define VIRTIO_PCI_ISR 19 |
|
49 |
|
|
50 |
#define VIRTIO_PCI_CONFIG 20 |
|
51 |
|
|
52 |
/* Virtio ABI version, if we increment this, we break the guest driver. */ |
|
53 |
#define VIRTIO_PCI_ABI_VERSION 0 |
|
54 |
|
|
55 |
/* How many bits to shift physical queue address written to QUEUE_PFN. |
|
56 |
* 12 is historical, and due to x86 page size. */ |
|
57 |
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 |
|
58 |
|
|
59 |
/* QEMU doesn't strictly need write barriers since everything runs in |
|
60 |
* lock-step. We'll leave the calls to wmb() in though to make it obvious for |
|
61 |
* KVM or if kqemu gets SMP support. |
|
62 |
*/ |
|
63 |
#define wmb() do { } while (0) |
|
64 |
|
|
65 |
/* PCI bindings. */ |
|
66 |
|
|
67 |
typedef struct { |
|
68 |
PCIDevice pci_dev; |
|
69 |
VirtIODevice *vdev; |
|
70 |
uint32_t addr; |
|
71 |
|
|
72 |
uint16_t vendor; |
|
73 |
uint16_t device; |
|
74 |
uint16_t subvendor; |
|
75 |
uint16_t class_code; |
|
76 |
uint8_t pif; |
|
77 |
} VirtIOPCIProxy; |
|
78 |
|
|
79 |
/* virtio device */ |
|
80 |
|
|
81 |
static void virtio_pci_update_irq(void *opaque) |
|
82 |
{ |
|
83 |
VirtIOPCIProxy *proxy = opaque; |
|
84 |
|
|
85 |
qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1); |
|
86 |
} |
|
87 |
|
|
88 |
static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
|
89 |
{ |
|
90 |
VirtIOPCIProxy *proxy = opaque; |
|
91 |
VirtIODevice *vdev = proxy->vdev; |
|
92 |
target_phys_addr_t pa; |
|
93 |
|
|
94 |
addr -= proxy->addr; |
|
95 |
|
|
96 |
switch (addr) { |
|
97 |
case VIRTIO_PCI_GUEST_FEATURES: |
|
98 |
/* Guest does not negotiate properly? We have to assume nothing. */ |
|
99 |
if (val & (1 << VIRTIO_F_BAD_FEATURE)) { |
|
100 |
if (vdev->bad_features) |
|
101 |
val = vdev->bad_features(vdev); |
|
102 |
else |
|
103 |
val = 0; |
|
104 |
} |
|
105 |
if (vdev->set_features) |
|
106 |
vdev->set_features(vdev, val); |
|
107 |
vdev->features = val; |
|
108 |
break; |
|
109 |
case VIRTIO_PCI_QUEUE_PFN: |
|
110 |
pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
|
111 |
virtio_queue_set_addr(vdev, vdev->queue_sel, pa); |
|
112 |
break; |
|
113 |
case VIRTIO_PCI_QUEUE_SEL: |
|
114 |
if (val < VIRTIO_PCI_QUEUE_MAX) |
|
115 |
vdev->queue_sel = val; |
|
116 |
break; |
|
117 |
case VIRTIO_PCI_QUEUE_NOTIFY: |
|
118 |
virtio_queue_notify(vdev, val); |
|
119 |
break; |
|
120 |
case VIRTIO_PCI_STATUS: |
|
121 |
vdev->status = val & 0xFF; |
|
122 |
if (vdev->status == 0) |
|
123 |
virtio_reset(vdev); |
|
124 |
break; |
|
125 |
} |
|
126 |
} |
|
127 |
|
|
128 |
static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) |
|
129 |
{ |
|
130 |
VirtIOPCIProxy *proxy = opaque; |
|
131 |
VirtIODevice *vdev = proxy->vdev; |
|
132 |
uint32_t ret = 0xFFFFFFFF; |
|
133 |
|
|
134 |
addr -= proxy->addr; |
|
135 |
|
|
136 |
switch (addr) { |
|
137 |
case VIRTIO_PCI_HOST_FEATURES: |
|
138 |
ret = vdev->get_features(vdev); |
|
139 |
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); |
|
140 |
break; |
|
141 |
case VIRTIO_PCI_GUEST_FEATURES: |
|
142 |
ret = vdev->features; |
|
143 |
break; |
|
144 |
case VIRTIO_PCI_QUEUE_PFN: |
|
145 |
ret = virtio_queue_get_addr(vdev, vdev->queue_sel) |
|
146 |
>> VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
|
147 |
break; |
|
148 |
case VIRTIO_PCI_QUEUE_NUM: |
|
149 |
ret = virtio_queue_get_num(vdev, vdev->queue_sel); |
|
150 |
break; |
|
151 |
case VIRTIO_PCI_QUEUE_SEL: |
|
152 |
ret = vdev->queue_sel; |
|
153 |
break; |
|
154 |
case VIRTIO_PCI_STATUS: |
|
155 |
ret = vdev->status; |
|
156 |
break; |
|
157 |
case VIRTIO_PCI_ISR: |
|
158 |
/* reading from the ISR also clears it. */ |
|
159 |
ret = vdev->isr; |
|
160 |
vdev->isr = 0; |
|
161 |
virtio_update_irq(vdev); |
|
162 |
break; |
|
163 |
default: |
|
164 |
break; |
|
165 |
} |
|
166 |
|
|
167 |
return ret; |
|
168 |
} |
|
169 |
|
|
170 |
static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr) |
|
171 |
{ |
|
172 |
VirtIOPCIProxy *proxy = opaque; |
|
173 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
|
174 |
return virtio_config_readb(proxy->vdev, addr); |
|
175 |
} |
|
176 |
|
|
177 |
static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) |
|
178 |
{ |
|
179 |
VirtIOPCIProxy *proxy = opaque; |
|
180 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
|
181 |
return virtio_config_readw(proxy->vdev, addr); |
|
182 |
} |
|
183 |
|
|
184 |
static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) |
|
185 |
{ |
|
186 |
VirtIOPCIProxy *proxy = opaque; |
|
187 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
|
188 |
return virtio_config_readl(proxy->vdev, addr); |
|
189 |
} |
|
190 |
|
|
191 |
static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) |
|
192 |
{ |
|
193 |
VirtIOPCIProxy *proxy = opaque; |
|
194 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
|
195 |
virtio_config_writeb(proxy->vdev, addr, val); |
|
196 |
} |
|
197 |
|
|
198 |
static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) |
|
199 |
{ |
|
200 |
VirtIOPCIProxy *proxy = opaque; |
|
201 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
|
202 |
virtio_config_writew(proxy->vdev, addr, val); |
|
203 |
} |
|
204 |
|
|
205 |
static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) |
|
206 |
{ |
|
207 |
VirtIOPCIProxy *proxy = opaque; |
|
208 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
|
209 |
virtio_config_writel(proxy->vdev, addr, val); |
|
210 |
} |
|
211 |
|
|
212 |
static void virtio_map(PCIDevice *pci_dev, int region_num, |
|
213 |
uint32_t addr, uint32_t size, int type) |
|
214 |
{ |
|
215 |
VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev); |
|
216 |
VirtIODevice *vdev = proxy->vdev; |
|
217 |
int i; |
|
218 |
|
|
219 |
proxy->addr = addr; |
|
220 |
for (i = 0; i < 3; i++) { |
|
221 |
register_ioport_write(addr, VIRTIO_PCI_CONFIG, 1 << i, |
|
222 |
virtio_ioport_write, proxy); |
|
223 |
register_ioport_read(addr, VIRTIO_PCI_CONFIG, 1 << i, |
|
224 |
virtio_ioport_read, proxy); |
|
225 |
} |
|
226 |
|
|
227 |
if (vdev->config_len) { |
|
228 |
register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1, |
|
229 |
virtio_pci_config_writeb, proxy); |
|
230 |
register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2, |
|
231 |
virtio_pci_config_writew, proxy); |
|
232 |
register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4, |
|
233 |
virtio_pci_config_writel, proxy); |
|
234 |
register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1, |
|
235 |
virtio_pci_config_readb, proxy); |
|
236 |
register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2, |
|
237 |
virtio_pci_config_readw, proxy); |
|
238 |
register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4, |
|
239 |
virtio_pci_config_readl, proxy); |
|
240 |
|
|
241 |
vdev->get_config(vdev, vdev->config); |
|
242 |
} |
|
243 |
} |
|
244 |
|
|
245 |
static const VirtIOBindings virtio_pci_bindings = { |
|
246 |
.update_irq = virtio_pci_update_irq |
|
247 |
}; |
|
248 |
|
|
249 |
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, |
|
250 |
uint16_t vendor, uint16_t device, |
|
251 |
uint16_t class_code, uint8_t pif) |
|
252 |
{ |
|
253 |
uint8_t *config; |
|
254 |
uint32_t size; |
|
255 |
|
|
256 |
proxy->vdev = vdev; |
|
257 |
|
|
258 |
config = proxy->pci_dev.config; |
|
259 |
pci_config_set_vendor_id(config, vendor); |
|
260 |
pci_config_set_device_id(config, device); |
|
261 |
|
|
262 |
config[0x08] = VIRTIO_PCI_ABI_VERSION; |
|
263 |
|
|
264 |
config[0x09] = pif; |
|
265 |
pci_config_set_class(config, class_code); |
|
266 |
config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; |
|
267 |
|
|
268 |
config[0x2c] = vendor & 0xFF; |
|
269 |
config[0x2d] = (vendor >> 8) & 0xFF; |
|
270 |
config[0x2e] = vdev->device_id & 0xFF; |
|
271 |
config[0x2f] = (vdev->device_id >> 8) & 0xFF; |
|
272 |
|
|
273 |
config[0x3d] = 1; |
|
274 |
|
|
275 |
size = 20 + vdev->config_len; |
|
276 |
if (size & (size-1)) |
|
277 |
size = 1 << qemu_fls(size); |
|
278 |
|
|
279 |
pci_register_io_region(&proxy->pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, |
|
280 |
virtio_map); |
|
281 |
|
|
282 |
virtio_bind_device(vdev, &virtio_pci_bindings, proxy); |
|
283 |
} |
|
284 |
|
|
285 |
static void virtio_blk_init_pci(PCIDevice *pci_dev) |
|
286 |
{ |
|
287 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
|
288 |
VirtIODevice *vdev; |
|
289 |
|
|
290 |
vdev = virtio_blk_init(&pci_dev->qdev); |
|
291 |
virtio_init_pci(proxy, vdev, |
|
292 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
293 |
PCI_DEVICE_ID_VIRTIO_BLOCK, |
|
294 |
PCI_CLASS_STORAGE_OTHER, |
|
295 |
0x00); |
|
296 |
} |
|
297 |
|
|
298 |
static void virtio_console_init_pci(PCIDevice *pci_dev) |
|
299 |
{ |
|
300 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
|
301 |
VirtIODevice *vdev; |
|
302 |
|
|
303 |
vdev = virtio_console_init(&pci_dev->qdev); |
|
304 |
virtio_init_pci(proxy, vdev, |
|
305 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
306 |
PCI_DEVICE_ID_VIRTIO_CONSOLE, |
|
307 |
PCI_CLASS_DISPLAY_OTHER, |
|
308 |
0x00); |
|
309 |
} |
|
310 |
|
|
311 |
static void virtio_net_init_pci(PCIDevice *pci_dev) |
|
312 |
{ |
|
313 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
|
314 |
VirtIODevice *vdev; |
|
315 |
|
|
316 |
vdev = virtio_net_init(&pci_dev->qdev); |
|
317 |
virtio_init_pci(proxy, vdev, |
|
318 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
319 |
PCI_DEVICE_ID_VIRTIO_NET, |
|
320 |
PCI_CLASS_NETWORK_ETHERNET, |
|
321 |
0x00); |
|
322 |
} |
|
323 |
|
|
324 |
static void virtio_balloon_init_pci(PCIDevice *pci_dev) |
|
325 |
{ |
|
326 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
|
327 |
VirtIODevice *vdev; |
|
328 |
|
|
329 |
vdev = virtio_balloon_init(&pci_dev->qdev); |
|
330 |
virtio_init_pci(proxy, vdev, |
|
331 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
|
332 |
PCI_DEVICE_ID_VIRTIO_BALLOON, |
|
333 |
PCI_CLASS_MEMORY_RAM, |
|
334 |
0x00); |
|
335 |
} |
|
336 |
|
|
337 |
static void virtio_pci_register_devices(void) |
|
338 |
{ |
|
339 |
pci_qdev_register("virtio-blk-pci", sizeof(VirtIOPCIProxy), |
|
340 |
virtio_blk_init_pci); |
|
341 |
pci_qdev_register("virtio-net-pci", sizeof(VirtIOPCIProxy), |
|
342 |
virtio_net_init_pci); |
|
343 |
pci_qdev_register("virtio-console-pci", sizeof(VirtIOPCIProxy), |
|
344 |
virtio_console_init_pci); |
|
345 |
pci_qdev_register("virtio-balloon-pci", sizeof(VirtIOPCIProxy), |
|
346 |
virtio_balloon_init_pci); |
|
347 |
} |
|
348 |
|
|
349 |
device_init(virtio_pci_register_devices) |
b/hw/virtio.c | ||
---|---|---|
16 | 16 |
#include "virtio.h" |
17 | 17 |
#include "sysemu.h" |
18 | 18 |
|
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 |
|
|
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 | 19 |
/* The alignment to use between consumer and producer parts of vring. |
57 | 20 |
* x86 pagesize again. */ |
58 | 21 |
#define VIRTIO_PCI_VRING_ALIGN 4096 |
... | ... | |
102 | 65 |
struct VirtQueue |
103 | 66 |
{ |
104 | 67 |
VRing vring; |
105 |
uint32_t pfn;
|
|
68 |
target_phys_addr_t pa;
|
|
106 | 69 |
uint16_t last_avail_idx; |
107 | 70 |
int inuse; |
108 | 71 |
void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq); |
... | ... | |
111 | 74 |
#define VIRTIO_PCI_QUEUE_MAX 16 |
112 | 75 |
|
113 | 76 |
/* virt queue functions */ |
114 |
static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa)
|
|
77 |
static void virtqueue_init(VirtQueue *vq) |
|
115 | 78 |
{ |
79 |
target_phys_addr_t pa = vq->pa; |
|
80 |
|
|
116 | 81 |
vq->vring.desc = pa; |
117 | 82 |
vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc); |
118 | 83 |
vq->vring.used = vring_align(vq->vring.avail + |
... | ... | |
409 | 374 |
|
410 | 375 |
/* virtio device */ |
411 | 376 |
|
412 |
static VirtIODevice *to_virtio_device(PCIDevice *pci_dev)
|
|
377 |
void virtio_update_irq(VirtIODevice *vdev)
|
|
413 | 378 |
{ |
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); |
|
379 |
if (vdev->binding->update_irq) { |
|
380 |
vdev->binding->update_irq(vdev->binding_opaque); |
|
381 |
} |
|
420 | 382 |
} |
421 | 383 |
|
422 |
static void virtio_reset(void *opaque)
|
|
384 |
void virtio_reset(void *opaque) |
|
423 | 385 |
{ |
424 | 386 |
VirtIODevice *vdev = opaque; |
425 | 387 |
int i; |
... | ... | |
438 | 400 |
vdev->vq[i].vring.avail = 0; |
439 | 401 |
vdev->vq[i].vring.used = 0; |
440 | 402 |
vdev->vq[i].last_avail_idx = 0; |
441 |
vdev->vq[i].pfn = 0;
|
|
403 |
vdev->vq[i].pa = 0;
|
|
442 | 404 |
} |
443 | 405 |
} |
444 | 406 |
|
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: |
|
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 |
} |
|
461 |
if (vdev->set_features) |
|
462 |
vdev->set_features(vdev, val); |
|
463 |
vdev->features = val; |
|
464 |
break; |
|
465 |
case VIRTIO_PCI_QUEUE_PFN: |
|
466 |
pa = (ram_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
|
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); |
|
500 |
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); |
|
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) |
|
407 |
uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr) |
|
531 | 408 |
{ |
532 |
VirtIODevice *vdev = opaque; |
|
533 | 409 |
uint8_t val; |
534 | 410 |
|
535 | 411 |
vdev->get_config(vdev, vdev->config); |
536 | 412 |
|
537 |
addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
538 | 413 |
if (addr > (vdev->config_len - sizeof(val))) |
539 | 414 |
return (uint32_t)-1; |
540 | 415 |
|
... | ... | |
542 | 417 |
return val; |
543 | 418 |
} |
544 | 419 |
|
545 |
static uint32_t virtio_config_readw(void *opaque, uint32_t addr)
|
|
420 |
uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
|
|
546 | 421 |
{ |
547 |
VirtIODevice *vdev = opaque; |
|
548 | 422 |
uint16_t val; |
549 | 423 |
|
550 | 424 |
vdev->get_config(vdev, vdev->config); |
551 | 425 |
|
552 |
addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
553 | 426 |
if (addr > (vdev->config_len - sizeof(val))) |
554 | 427 |
return (uint32_t)-1; |
555 | 428 |
|
... | ... | |
557 | 430 |
return val; |
558 | 431 |
} |
559 | 432 |
|
560 |
static uint32_t virtio_config_readl(void *opaque, uint32_t addr)
|
|
433 |
uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
|
|
561 | 434 |
{ |
562 |
VirtIODevice *vdev = opaque; |
|
563 | 435 |
uint32_t val; |
564 | 436 |
|
565 | 437 |
vdev->get_config(vdev, vdev->config); |
566 | 438 |
|
567 |
addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
568 | 439 |
if (addr > (vdev->config_len - sizeof(val))) |
569 | 440 |
return (uint32_t)-1; |
570 | 441 |
|
... | ... | |
572 | 443 |
return val; |
573 | 444 |
} |
574 | 445 |
|
575 |
static void virtio_config_writeb(void *opaque, uint32_t addr, uint32_t data)
|
|
446 |
void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
|
|
576 | 447 |
{ |
577 |
VirtIODevice *vdev = opaque; |
|
578 | 448 |
uint8_t val = data; |
579 | 449 |
|
580 |
addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
581 | 450 |
if (addr > (vdev->config_len - sizeof(val))) |
582 | 451 |
return; |
583 | 452 |
|
... | ... | |
587 | 456 |
vdev->set_config(vdev, vdev->config); |
588 | 457 |
} |
589 | 458 |
|
590 |
static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data)
|
|
459 |
void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
|
|
591 | 460 |
{ |
592 |
VirtIODevice *vdev = opaque; |
|
593 | 461 |
uint16_t val = data; |
594 | 462 |
|
595 |
addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
596 | 463 |
if (addr > (vdev->config_len - sizeof(val))) |
597 | 464 |
return; |
598 | 465 |
|
... | ... | |
602 | 469 |
vdev->set_config(vdev, vdev->config); |
603 | 470 |
} |
604 | 471 |
|
605 |
static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data)
|
|
472 |
void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
|
|
606 | 473 |
{ |
607 |
VirtIODevice *vdev = opaque; |
|
608 | 474 |
uint32_t val = data; |
609 | 475 |
|
610 |
addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
611 | 476 |
if (addr > (vdev->config_len - sizeof(val))) |
612 | 477 |
return; |
613 | 478 |
|
... | ... | |
617 | 482 |
vdev->set_config(vdev, vdev->config); |
618 | 483 |
} |
619 | 484 |
|
620 |
static void virtio_map(PCIDevice *pci_dev, int region_num, |
|
621 |
uint32_t addr, uint32_t size, int type) |
|
485 |
void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr) |
|
622 | 486 |
{ |
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); |
|
487 |
if (addr == 0) { |
|
488 |
virtio_reset(vdev); |
|
489 |
} else { |
|
490 |
vdev->vq[n].pa = addr; |
|
491 |
virtqueue_init(&vdev->vq[n]); |
|
630 | 492 |
} |
493 |
} |
|
494 |
|
|
495 |
target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n) |
|
496 |
{ |
|
497 |
return vdev->vq[n].pa; |
|
498 |
} |
|
499 |
|
|
500 |
int virtio_queue_get_num(VirtIODevice *vdev, int n) |
|
501 |
{ |
|
502 |
return vdev->vq[n].vring.num; |
|
503 |
} |
|
631 | 504 |
|
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); |
|
505 |
void virtio_queue_notify(VirtIODevice *vdev, int n) |
|
506 |
{ |
|
507 |
if (n < VIRTIO_PCI_QUEUE_MAX && vdev->vq[n].vring.desc) { |
|
508 |
vdev->vq[n].handle_output(vdev, &vdev->vq[n]); |
|
647 | 509 |
} |
648 | 510 |
} |
649 | 511 |
|
... | ... | |
691 | 553 |
{ |
692 | 554 |
int i; |
693 | 555 |
|
694 |
pci_device_save(&vdev->pci_dev, f); |
|
556 |
/* FIXME: load/save binding. */ |
|
557 |
//pci_device_save(&vdev->pci_dev, f); |
|
695 | 558 |
|
696 |
qemu_put_be32s(f, &vdev->addr); |
|
697 | 559 |
qemu_put_8s(f, &vdev->status); |
698 | 560 |
qemu_put_8s(f, &vdev->isr); |
699 | 561 |
qemu_put_be16s(f, &vdev->queue_sel); |
... | ... | |
713 | 575 |
break; |
714 | 576 |
|
715 | 577 |
qemu_put_be32(f, vdev->vq[i].vring.num); |
716 |
qemu_put_be32s(f, &vdev->vq[i].pfn);
|
|
578 |
qemu_put_be64(f, vdev->vq[i].pa);
|
|
717 | 579 |
qemu_put_be16s(f, &vdev->vq[i].last_avail_idx); |
718 | 580 |
} |
719 | 581 |
} |
... | ... | |
722 | 584 |
{ |
723 | 585 |
int num, i; |
724 | 586 |
|
725 |
pci_device_load(&vdev->pci_dev, f); |
|
587 |
/* FIXME: load/save binding. */ |
|
588 |
//pci_device_load(&vdev->pci_dev, f); |
|
726 | 589 |
|
727 |
qemu_get_be32s(f, &vdev->addr); |
|
728 | 590 |
qemu_get_8s(f, &vdev->status); |
729 | 591 |
qemu_get_8s(f, &vdev->isr); |
730 | 592 |
qemu_get_be16s(f, &vdev->queue_sel); |
... | ... | |
736 | 598 |
|
737 | 599 |
for (i = 0; i < num; i++) { |
738 | 600 |
vdev->vq[i].vring.num = qemu_get_be32(f); |
739 |
qemu_get_be32s(f, &vdev->vq[i].pfn);
|
|
601 |
vdev->vq[i].pa = qemu_get_be64(f);
|
|
740 | 602 |
qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); |
741 | 603 |
|
742 |
if (vdev->vq[i].pfn) { |
|
743 |
target_phys_addr_t pa; |
|
744 |
|
|
745 |
pa = (ram_addr_t)vdev->vq[i].pfn << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
|
746 |
virtqueue_init(&vdev->vq[i], pa); |
|
604 |
if (vdev->vq[i].pa) { |
|
605 |
virtqueue_init(&vdev->vq[i]); |
|
747 | 606 |
} |
748 | 607 |
} |
749 | 608 |
|
... | ... | |
757 | 616 |
qemu_free(vdev->vq); |
758 | 617 |
} |
759 | 618 |
|
760 |
VirtIODevice *virtio_init_pci(PCIDevice *pci_dev, const char *name, |
|
761 |
uint16_t vendor, uint16_t device, |
|
762 |
uint16_t subvendor, uint16_t subdevice, |
|
763 |
uint16_t class_code, uint8_t pif, |
|
764 |
size_t config_size) |
|
619 |
VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, |
|
620 |
size_t config_size, size_t struct_size) |
|
765 | 621 |
{ |
766 | 622 |
VirtIODevice *vdev; |
767 |
uint8_t *config; |
|
768 |
uint32_t size; |
|
769 | 623 |
|
770 |
vdev = to_virtio_device(pci_dev);
|
|
624 |
vdev = qemu_mallocz(struct_size);
|
|
771 | 625 |
|
626 |
vdev->device_id = device_id; |
|
772 | 627 |
vdev->status = 0; |
773 | 628 |
vdev->isr = 0; |
774 | 629 |
vdev->queue_sel = 0; |
775 | 630 |
vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX); |
776 | 631 |
|
777 |
config = pci_dev->config; |
|
778 |
pci_config_set_vendor_id(config, vendor); |
|
779 |
pci_config_set_device_id(config, device); |
|
780 |
|
|
781 |
config[0x08] = VIRTIO_PCI_ABI_VERSION; |
|
782 |
|
|
783 |
config[0x09] = pif; |
|
784 |
pci_config_set_class(config, class_code); |
|
785 |
config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; |
|
786 |
|
|
787 |
config[0x2c] = subvendor & 0xFF; |
|
788 |
config[0x2d] = (subvendor >> 8) & 0xFF; |
|
789 |
config[0x2e] = subdevice & 0xFF; |
|
790 |
config[0x2f] = (subdevice >> 8) & 0xFF; |
|
791 |
|
|
792 |
config[0x3d] = 1; |
|
793 |
|
|
794 | 632 |
vdev->name = name; |
795 | 633 |
vdev->config_len = config_size; |
796 | 634 |
if (vdev->config_len) |
... | ... | |
798 | 636 |
else |
799 | 637 |
vdev->config = NULL; |
800 | 638 |
|
801 |
size = 20 + config_size; |
|
802 |
if (size & (size-1)) |
|
803 |
size = 1 << qemu_fls(size); |
|
804 |
|
|
805 |
pci_register_io_region(pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, |
|
806 |
virtio_map); |
|
807 | 639 |
qemu_register_reset(virtio_reset, vdev); |
808 |
|
|
809 | 640 |
return vdev; |
810 | 641 |
} |
642 |
|
|
643 |
void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, |
|
644 |
void *opaque) |
|
645 |
{ |
|
646 |
vdev->binding = binding; |
|
647 |
vdev->binding_opaque = opaque; |
|
648 |
} |
b/hw/virtio.h | ||
---|---|---|
15 | 15 |
#define _QEMU_VIRTIO_H |
16 | 16 |
|
17 | 17 |
#include "hw.h" |
18 |
#include "pci.h"
|
|
18 |
#include "qdev.h"
|
|
19 | 19 |
|
20 | 20 |
/* from Linux's linux/virtio_config.h */ |
21 | 21 |
|
... | ... | |
70 | 70 |
struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; |
71 | 71 |
} VirtQueueElement; |
72 | 72 |
|
73 |
typedef struct { |
|
74 |
void (*update_irq)(void * opaque); |
|
75 |
} VirtIOBindings; |
|
76 |
|
|
73 | 77 |
#define VIRTIO_PCI_QUEUE_MAX 16 |
74 | 78 |
|
75 | 79 |
struct VirtIODevice |
76 | 80 |
{ |
77 |
PCIDevice pci_dev; |
|
78 | 81 |
const char *name; |
79 |
uint32_t addr; |
|
80 | 82 |
uint8_t status; |
81 | 83 |
uint8_t isr; |
82 | 84 |
uint16_t queue_sel; |
... | ... | |
90 | 92 |
void (*set_config)(VirtIODevice *vdev, const uint8_t *config); |
91 | 93 |
void (*reset)(VirtIODevice *vdev); |
92 | 94 |
VirtQueue *vq; |
95 |
const VirtIOBindings *binding; |
|
96 |
void *binding_opaque; |
|
97 |
uint16_t device_id; |
|
93 | 98 |
}; |
94 | 99 |
|
95 |
VirtIODevice *virtio_init_pci(PCIDevice *pci_dev, const char *name, |
|
96 |
uint16_t vendor, uint16_t device, |
|
97 |
uint16_t subvendor, uint16_t subdevice, |
|
98 |
uint16_t class_code, uint8_t pif, |
|
99 |
size_t config_size); |
|
100 |
|
|
101 | 100 |
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, |
102 | 101 |
void (*handle_output)(VirtIODevice *, |
103 | 102 |
VirtQueue *)); |
... | ... | |
127 | 126 |
|
128 | 127 |
int virtio_queue_empty(VirtQueue *vq); |
129 | 128 |
|
129 |
/* Host binding interface. */ |
|
130 |
|
|
131 |
VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, |
|
132 |
size_t config_size, size_t struct_size); |
|
133 |
uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr); |
|
134 |
uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr); |
|
135 |
uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr); |
|
136 |
void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data); |
|
137 |
void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data); |
|
138 |
void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data); |
|
139 |
void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr); |
|
140 |
target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n); |
|
141 |
int virtio_queue_get_num(VirtIODevice *vdev, int n); |
|
142 |
void virtio_queue_notify(VirtIODevice *vdev, int n); |
|
143 |
void virtio_reset(void *opaque); |
|
144 |
void virtio_update_irq(VirtIODevice *vdev); |
|
145 |
|
|
146 |
void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, |
|
147 |
void *opaque); |
|
148 |
|
|
149 |
/* Base devices. */ |
|
150 |
VirtIODevice *virtio_blk_init(DeviceState *dev); |
|
151 |
VirtIODevice *virtio_net_init(DeviceState *dev); |
|
152 |
VirtIODevice *virtio_console_init(DeviceState *dev); |
|
153 |
VirtIODevice *virtio_balloon_init(DeviceState *dev); |
|
154 |
|
|
130 | 155 |
#endif |
Also available in: Unified diff