root / hw / virtio-balloon.c @ bc578fe0
History | View | Annotate | Download (4.8 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 | c227f099 | Anthony Liguori | ram_addr_t pa; |
88 | c227f099 | Anthony Liguori | ram_addr_t addr; |
89 | bd322087 | aliguori | |
90 | c227f099 | Anthony Liguori | 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 | 5c130f65 | pbrook | /* Using qemu_get_ram_ptr is bending the rules a bit, but
|
98 | 5c130f65 | pbrook | should be OK because we only want a single page. */
|
99 | 5c130f65 | pbrook | balloon_page(qemu_get_ram_ptr(addr), !!(vq == s->dvq)); |
100 | bd322087 | aliguori | } |
101 | bd322087 | aliguori | |
102 | bd322087 | aliguori | virtqueue_push(vq, &elem, offset); |
103 | bd322087 | aliguori | virtio_notify(vdev, vq); |
104 | bd322087 | aliguori | } |
105 | bd322087 | aliguori | } |
106 | bd322087 | aliguori | |
107 | bd322087 | aliguori | static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) |
108 | bd322087 | aliguori | { |
109 | bd322087 | aliguori | VirtIOBalloon *dev = to_virtio_balloon(vdev); |
110 | bd322087 | aliguori | struct virtio_balloon_config config;
|
111 | bd322087 | aliguori | |
112 | bd322087 | aliguori | config.num_pages = cpu_to_le32(dev->num_pages); |
113 | bd322087 | aliguori | config.actual = cpu_to_le32(dev->actual); |
114 | bd322087 | aliguori | |
115 | bd322087 | aliguori | memcpy(config_data, &config, 8);
|
116 | bd322087 | aliguori | } |
117 | bd322087 | aliguori | |
118 | bd322087 | aliguori | static void virtio_balloon_set_config(VirtIODevice *vdev, |
119 | bd322087 | aliguori | const uint8_t *config_data)
|
120 | bd322087 | aliguori | { |
121 | bd322087 | aliguori | VirtIOBalloon *dev = to_virtio_balloon(vdev); |
122 | bd322087 | aliguori | struct virtio_balloon_config config;
|
123 | bd322087 | aliguori | memcpy(&config, config_data, 8);
|
124 | bd322087 | aliguori | dev->actual = config.actual; |
125 | bd322087 | aliguori | } |
126 | bd322087 | aliguori | |
127 | bd322087 | aliguori | static uint32_t virtio_balloon_get_features(VirtIODevice *vdev)
|
128 | bd322087 | aliguori | { |
129 | bd322087 | aliguori | return 0; |
130 | bd322087 | aliguori | } |
131 | bd322087 | aliguori | |
132 | c227f099 | Anthony Liguori | static ram_addr_t virtio_balloon_to_target(void *opaque, ram_addr_t target) |
133 | bd322087 | aliguori | { |
134 | bd322087 | aliguori | VirtIOBalloon *dev = opaque; |
135 | bd322087 | aliguori | |
136 | bd322087 | aliguori | if (target > ram_size)
|
137 | bd322087 | aliguori | target = ram_size; |
138 | bd322087 | aliguori | |
139 | bd322087 | aliguori | if (target) {
|
140 | bd322087 | aliguori | dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT; |
141 | bd322087 | aliguori | virtio_notify_config(&dev->vdev); |
142 | bd322087 | aliguori | } |
143 | bd322087 | aliguori | |
144 | bd322087 | aliguori | return ram_size - (dev->actual << VIRTIO_BALLOON_PFN_SHIFT);
|
145 | bd322087 | aliguori | } |
146 | bd322087 | aliguori | |
147 | bd322087 | aliguori | static void virtio_balloon_save(QEMUFile *f, void *opaque) |
148 | bd322087 | aliguori | { |
149 | bd322087 | aliguori | VirtIOBalloon *s = opaque; |
150 | bd322087 | aliguori | |
151 | bd322087 | aliguori | virtio_save(&s->vdev, f); |
152 | bd322087 | aliguori | |
153 | bd322087 | aliguori | qemu_put_be32(f, s->num_pages); |
154 | bd322087 | aliguori | qemu_put_be32(f, s->actual); |
155 | bd322087 | aliguori | } |
156 | bd322087 | aliguori | |
157 | bd322087 | aliguori | static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) |
158 | bd322087 | aliguori | { |
159 | bd322087 | aliguori | VirtIOBalloon *s = opaque; |
160 | bd322087 | aliguori | |
161 | bd322087 | aliguori | if (version_id != 1) |
162 | bd322087 | aliguori | return -EINVAL;
|
163 | bd322087 | aliguori | |
164 | bd322087 | aliguori | virtio_load(&s->vdev, f); |
165 | bd322087 | aliguori | |
166 | bd322087 | aliguori | s->num_pages = qemu_get_be32(f); |
167 | bd322087 | aliguori | s->actual = qemu_get_be32(f); |
168 | bd322087 | aliguori | |
169 | bd322087 | aliguori | return 0; |
170 | bd322087 | aliguori | } |
171 | bd322087 | aliguori | |
172 | 53c25cea | Paul Brook | VirtIODevice *virtio_balloon_init(DeviceState *dev) |
173 | bd322087 | aliguori | { |
174 | bd322087 | aliguori | VirtIOBalloon *s; |
175 | bd322087 | aliguori | |
176 | 53c25cea | Paul Brook | s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
|
177 | 53c25cea | Paul Brook | VIRTIO_ID_BALLOON, |
178 | 53c25cea | Paul Brook | 8, sizeof(VirtIOBalloon)); |
179 | bd322087 | aliguori | |
180 | bd322087 | aliguori | s->vdev.get_config = virtio_balloon_get_config; |
181 | bd322087 | aliguori | s->vdev.set_config = virtio_balloon_set_config; |
182 | bd322087 | aliguori | s->vdev.get_features = virtio_balloon_get_features; |
183 | bd322087 | aliguori | |
184 | bd322087 | aliguori | s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
|
185 | bd322087 | aliguori | s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
|
186 | bd322087 | aliguori | |
187 | bd322087 | aliguori | qemu_add_balloon_handler(virtio_balloon_to_target, s); |
188 | bd322087 | aliguori | |
189 | bd322087 | aliguori | register_savevm("virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); |
190 | bd322087 | aliguori | |
191 | 53c25cea | Paul Brook | return &s->vdev;
|
192 | bd322087 | aliguori | } |