root / hw / virtio-balloon.c @ 9b32d5a5
History | View | Annotate | Download (4.9 kB)
1 | bd322087 | aliguori | /*
|
---|---|---|---|
2 | bd322087 | aliguori | * Virtio Block Device
|
3 | bd322087 | aliguori | *
|
4 | bd322087 | aliguori | * Copyright IBM, Corp. 2008
|
5 | bd322087 | aliguori | *
|
6 | bd322087 | aliguori | * Authors:
|
7 | bd322087 | aliguori | * Anthony Liguori <aliguori@us.ibm.com>
|
8 | bd322087 | aliguori | *
|
9 | bd322087 | aliguori | * This work is licensed under the terms of the GNU GPL, version 2. See
|
10 | bd322087 | aliguori | * the COPYING file in the top-level directory.
|
11 | bd322087 | aliguori | *
|
12 | bd322087 | aliguori | */
|
13 | bd322087 | aliguori | |
14 | bd322087 | aliguori | #include "qemu-common.h" |
15 | bd322087 | aliguori | #include "virtio.h" |
16 | bd322087 | aliguori | #include "pc.h" |
17 | bd322087 | aliguori | #include "sysemu.h" |
18 | bd322087 | aliguori | #include "cpu.h" |
19 | bd322087 | aliguori | #include "balloon.h" |
20 | bd322087 | aliguori | #include "virtio-balloon.h" |
21 | bd322087 | aliguori | #include "kvm.h" |
22 | bd322087 | aliguori | |
23 | bd322087 | aliguori | #if defined(__linux__)
|
24 | bd322087 | aliguori | #include <sys/mman.h> |
25 | bd322087 | aliguori | #endif
|
26 | bd322087 | aliguori | |
27 | bd322087 | aliguori | typedef struct VirtIOBalloon |
28 | bd322087 | aliguori | { |
29 | bd322087 | aliguori | VirtIODevice vdev; |
30 | bd322087 | aliguori | VirtQueue *ivq, *dvq; |
31 | bd322087 | aliguori | uint32_t num_pages; |
32 | bd322087 | aliguori | uint32_t actual; |
33 | bd322087 | aliguori | } VirtIOBalloon; |
34 | bd322087 | aliguori | |
35 | bd322087 | aliguori | static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
|
36 | bd322087 | aliguori | { |
37 | bd322087 | aliguori | return (VirtIOBalloon *)vdev;
|
38 | bd322087 | aliguori | } |
39 | bd322087 | aliguori | |
40 | bd322087 | aliguori | static void balloon_page(void *addr, int deflate) |
41 | bd322087 | aliguori | { |
42 | bd322087 | aliguori | #if defined(__linux__)
|
43 | bd322087 | aliguori | if (!kvm_enabled() || kvm_has_sync_mmu())
|
44 | bd322087 | aliguori | madvise(addr, TARGET_PAGE_SIZE, |
45 | bd322087 | aliguori | deflate ? MADV_WILLNEED : MADV_DONTNEED); |
46 | bd322087 | aliguori | #endif
|
47 | bd322087 | aliguori | } |
48 | bd322087 | aliguori | |
49 | bd322087 | aliguori | /* FIXME: once we do a virtio refactoring, this will get subsumed into common
|
50 | bd322087 | aliguori | * code */
|
51 | bd322087 | aliguori | static size_t memcpy_from_iovector(void *data, size_t offset, size_t size, |
52 | bd322087 | aliguori | struct iovec *iov, int iovlen) |
53 | bd322087 | aliguori | { |
54 | bd322087 | aliguori | int i;
|
55 | bd322087 | aliguori | uint8_t *ptr = data; |
56 | bd322087 | aliguori | size_t iov_off = 0;
|
57 | bd322087 | aliguori | size_t data_off = 0;
|
58 | bd322087 | aliguori | |
59 | bd322087 | aliguori | for (i = 0; i < iovlen && size; i++) { |
60 | bd322087 | aliguori | if (offset < (iov_off + iov[i].iov_len)) {
|
61 | bd322087 | aliguori | size_t len = MIN((iov_off + iov[i].iov_len) - offset , size); |
62 | bd322087 | aliguori | |
63 | bd322087 | aliguori | memcpy(ptr + data_off, iov[i].iov_base + (offset - iov_off), len); |
64 | bd322087 | aliguori | |
65 | bd322087 | aliguori | data_off += len; |
66 | bd322087 | aliguori | offset += len; |
67 | bd322087 | aliguori | size -= len; |
68 | bd322087 | aliguori | } |
69 | bd322087 | aliguori | |
70 | bd322087 | aliguori | iov_off += iov[i].iov_len; |
71 | bd322087 | aliguori | } |
72 | bd322087 | aliguori | |
73 | bd322087 | aliguori | return data_off;
|
74 | bd322087 | aliguori | } |
75 | bd322087 | aliguori | |
76 | bd322087 | aliguori | static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) |
77 | bd322087 | aliguori | { |
78 | bd322087 | aliguori | VirtIOBalloon *s = to_virtio_balloon(vdev); |
79 | bd322087 | aliguori | VirtQueueElement elem; |
80 | bd322087 | aliguori | |
81 | bd322087 | aliguori | while (virtqueue_pop(vq, &elem)) {
|
82 | bd322087 | aliguori | size_t offset = 0;
|
83 | bd322087 | aliguori | uint32_t pfn; |
84 | bd322087 | aliguori | |
85 | bd322087 | aliguori | while (memcpy_from_iovector(&pfn, offset, 4, |
86 | bd322087 | aliguori | elem.out_sg, elem.out_num) == 4) {
|
87 | bd322087 | aliguori | ram_addr_t pa; |
88 | bd322087 | aliguori | ram_addr_t addr; |
89 | bd322087 | aliguori | |
90 | bd322087 | aliguori | pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT; |
91 | bd322087 | aliguori | offset += 4;
|
92 | bd322087 | aliguori | |
93 | bd322087 | aliguori | addr = cpu_get_physical_page_desc(pa); |
94 | bd322087 | aliguori | if ((addr & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
|
95 | bd322087 | aliguori | continue;
|
96 | bd322087 | aliguori | |
97 | bd322087 | aliguori | balloon_page(phys_ram_base + addr, !!(vq == s->dvq)); |
98 | bd322087 | aliguori | } |
99 | bd322087 | aliguori | |
100 | bd322087 | aliguori | virtqueue_push(vq, &elem, offset); |
101 | bd322087 | aliguori | virtio_notify(vdev, vq); |
102 | bd322087 | aliguori | } |
103 | bd322087 | aliguori | } |
104 | bd322087 | aliguori | |
105 | bd322087 | aliguori | static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) |
106 | bd322087 | aliguori | { |
107 | bd322087 | aliguori | VirtIOBalloon *dev = to_virtio_balloon(vdev); |
108 | bd322087 | aliguori | struct virtio_balloon_config config;
|
109 | bd322087 | aliguori | |
110 | bd322087 | aliguori | config.num_pages = cpu_to_le32(dev->num_pages); |
111 | bd322087 | aliguori | config.actual = cpu_to_le32(dev->actual); |
112 | bd322087 | aliguori | |
113 | bd322087 | aliguori | memcpy(config_data, &config, 8);
|
114 | bd322087 | aliguori | } |
115 | bd322087 | aliguori | |
116 | bd322087 | aliguori | static void virtio_balloon_set_config(VirtIODevice *vdev, |
117 | bd322087 | aliguori | const uint8_t *config_data)
|
118 | bd322087 | aliguori | { |
119 | bd322087 | aliguori | VirtIOBalloon *dev = to_virtio_balloon(vdev); |
120 | bd322087 | aliguori | struct virtio_balloon_config config;
|
121 | bd322087 | aliguori | memcpy(&config, config_data, 8);
|
122 | bd322087 | aliguori | dev->actual = config.actual; |
123 | bd322087 | aliguori | } |
124 | bd322087 | aliguori | |
125 | bd322087 | aliguori | static uint32_t virtio_balloon_get_features(VirtIODevice *vdev)
|
126 | bd322087 | aliguori | { |
127 | bd322087 | aliguori | return 0; |
128 | bd322087 | aliguori | } |
129 | bd322087 | aliguori | |
130 | bd322087 | aliguori | static ram_addr_t virtio_balloon_to_target(void *opaque, ram_addr_t target) |
131 | bd322087 | aliguori | { |
132 | bd322087 | aliguori | VirtIOBalloon *dev = opaque; |
133 | bd322087 | aliguori | |
134 | bd322087 | aliguori | if (target > ram_size)
|
135 | bd322087 | aliguori | target = ram_size; |
136 | bd322087 | aliguori | |
137 | bd322087 | aliguori | if (target) {
|
138 | bd322087 | aliguori | dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT; |
139 | bd322087 | aliguori | virtio_notify_config(&dev->vdev); |
140 | bd322087 | aliguori | } |
141 | bd322087 | aliguori | |
142 | bd322087 | aliguori | return ram_size - (dev->actual << VIRTIO_BALLOON_PFN_SHIFT);
|
143 | bd322087 | aliguori | } |
144 | bd322087 | aliguori | |
145 | bd322087 | aliguori | static void virtio_balloon_save(QEMUFile *f, void *opaque) |
146 | bd322087 | aliguori | { |
147 | bd322087 | aliguori | VirtIOBalloon *s = opaque; |
148 | bd322087 | aliguori | |
149 | bd322087 | aliguori | virtio_save(&s->vdev, f); |
150 | bd322087 | aliguori | |
151 | bd322087 | aliguori | qemu_put_be32(f, s->num_pages); |
152 | bd322087 | aliguori | qemu_put_be32(f, s->actual); |
153 | bd322087 | aliguori | } |
154 | bd322087 | aliguori | |
155 | bd322087 | aliguori | static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) |
156 | bd322087 | aliguori | { |
157 | bd322087 | aliguori | VirtIOBalloon *s = opaque; |
158 | bd322087 | aliguori | |
159 | bd322087 | aliguori | if (version_id != 1) |
160 | bd322087 | aliguori | return -EINVAL;
|
161 | bd322087 | aliguori | |
162 | bd322087 | aliguori | virtio_load(&s->vdev, f); |
163 | bd322087 | aliguori | |
164 | bd322087 | aliguori | s->num_pages = qemu_get_be32(f); |
165 | bd322087 | aliguori | s->actual = qemu_get_be32(f); |
166 | bd322087 | aliguori | |
167 | bd322087 | aliguori | return 0; |
168 | bd322087 | aliguori | } |
169 | bd322087 | aliguori | |
170 | bd322087 | aliguori | void *virtio_balloon_init(PCIBus *bus)
|
171 | bd322087 | aliguori | { |
172 | bd322087 | aliguori | VirtIOBalloon *s; |
173 | bd322087 | aliguori | |
174 | bd322087 | aliguori | s = (VirtIOBalloon *)virtio_init_pci(bus, "virtio-balloon",
|
175 | 9b32d5a5 | aliguori | PCI_VENDOR_ID_REDHAT_QUMRANET, |
176 | 9b32d5a5 | aliguori | PCI_DEVICE_ID_VIRTIO_BALLOON, |
177 | bd322087 | aliguori | 0, VIRTIO_ID_BALLOON,
|
178 | bd322087 | aliguori | 0x05, 0x00, 0x00, |
179 | bd322087 | aliguori | 8, sizeof(VirtIOBalloon)); |
180 | bd322087 | aliguori | if (s == NULL) |
181 | bd322087 | aliguori | return NULL; |
182 | bd322087 | aliguori | |
183 | bd322087 | aliguori | s->vdev.get_config = virtio_balloon_get_config; |
184 | bd322087 | aliguori | s->vdev.set_config = virtio_balloon_set_config; |
185 | bd322087 | aliguori | s->vdev.get_features = virtio_balloon_get_features; |
186 | bd322087 | aliguori | |
187 | bd322087 | aliguori | s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
|
188 | bd322087 | aliguori | s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
|
189 | bd322087 | aliguori | |
190 | bd322087 | aliguori | qemu_add_balloon_handler(virtio_balloon_to_target, s); |
191 | bd322087 | aliguori | |
192 | bd322087 | aliguori | register_savevm("virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); |
193 | bd322087 | aliguori | |
194 | bd322087 | aliguori | return &s->vdev;
|
195 | bd322087 | aliguori | } |