blob: 504b2ceccfb70284846c30bc1a73448026a35749 [file] [log] [blame]
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001/*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include <unistd.h>
25#include <fcntl.h>
26#include <signal.h>
27#include <time.h>
28#include <errno.h>
29#include <sys/time.h>
30#include <zlib.h>
31
David 'Digit' Turner2c538c82010-05-10 16:48:20 -070032/* Needed early for CONFIG_BSD etc. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070033#include "config-host.h"
34
35#ifndef _WIN32
36#include <sys/times.h>
37#include <sys/wait.h>
38#include <termios.h>
39#include <sys/mman.h>
40#include <sys/ioctl.h>
41#include <sys/resource.h>
42#include <sys/socket.h>
43#include <netinet/in.h>
44#include <net/if.h>
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070045#include <arpa/inet.h>
46#include <dirent.h>
47#include <netdb.h>
48#include <sys/select.h>
David 'Digit' Turner2c538c82010-05-10 16:48:20 -070049#ifdef CONFIG_BSD
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070050#include <sys/stat.h>
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +010051#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070052#include <libutil.h>
53#else
54#include <util.h>
55#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070056#ifdef __linux__
57#include <pty.h>
58#include <malloc.h>
59#include <linux/rtc.h>
60#endif
61#endif
62#endif
63
64#ifdef _WIN32
65#include <windows.h>
66#include <malloc.h>
67#include <sys/timeb.h>
68#include <mmsystem.h>
69#define getopt_long_only getopt_long
70#define memalign(align, size) malloc(size)
71#endif
72
73#include "qemu-common.h"
74#include "hw/hw.h"
David 'Digit' Turner6234c0b2014-03-14 17:05:26 +010075#include "hw/qdev.h"
David 'Digit' Turnercc330d42013-12-14 23:26:42 +010076#include "net/net.h"
David 'Digit' Turner6af67652013-12-14 23:49:32 +010077#include "monitor/monitor.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010078#include "sysemu/sysemu.h"
David 'Digit' Turnere7216d82013-12-15 00:51:13 +010079#include "sysemu/char.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010080#include "sysemu/blockdev.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010081#include "block/block.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070082#include "audio/audio.h"
David 'Digit' Turner28a09b62013-12-15 00:16:00 +010083#include "migration/migration.h"
David 'Digit' Turner28a09b62013-12-15 00:16:00 +010084#include "migration/qemu-file.h"
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +010085#include "migration/vmstate.h"
86#include "qemu/bitmap.h"
87#include "qemu/iov.h"
88#include "qemu/sockets.h"
89#include "qemu/timer.h"
90#include "qemu/queue.h"
Tim Baverstock622b8f42010-12-07 11:36:59 +000091#include "android/snapshot.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070092
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070093
94#define SELF_ANNOUNCE_ROUNDS 5
David 'Digit' Turner986acc92011-05-10 16:50:01 +020095
96#ifndef ETH_P_RARP
97#define ETH_P_RARP 0x8035
98#endif
99#define ARP_HTYPE_ETH 0x0001
100#define ARP_PTYPE_IP 0x0800
101#define ARP_OP_REQUEST_REV 0x3
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700102
David 'Digit' Turner5973c772011-05-10 07:06:00 +0200103static int announce_self_create(uint8_t *buf,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700104 uint8_t *mac_addr)
105{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200106 /* Ethernet header. */
107 memset(buf, 0xff, 6); /* destination MAC addr */
108 memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
109 *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700110
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200111 /* RARP header. */
112 *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
113 *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
114 *(buf + 18) = 6; /* hardware addr length (ethernet) */
115 *(buf + 19) = 4; /* protocol addr length (IPv4) */
116 *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
117 memcpy(buf + 22, mac_addr, 6); /* source hw addr */
118 memset(buf + 28, 0x00, 4); /* source protocol addr */
119 memcpy(buf + 32, mac_addr, 6); /* target hw addr */
120 memset(buf + 38, 0x00, 4); /* target protocol addr */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700121
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200122 /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
123 memset(buf + 42, 0x00, 18);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700124
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200125 return 60; /* len (FCS will be added by hardware) */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700126}
127
128static void qemu_announce_self_once(void *opaque)
129{
130 int i, len;
131 VLANState *vlan;
132 VLANClientState *vc;
133 uint8_t buf[256];
134 static int count = SELF_ANNOUNCE_ROUNDS;
135 QEMUTimer *timer = *(QEMUTimer **)opaque;
136
137 for (i = 0; i < MAX_NICS; i++) {
138 if (!nd_table[i].used)
139 continue;
140 len = announce_self_create(buf, nd_table[i].macaddr);
141 vlan = nd_table[i].vlan;
142 for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
143 vc->receive(vc, buf, len);
144 }
145 }
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200146 if (--count) {
147 /* delay 50ms, 150ms, 250ms, ... */
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100148 timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200149 50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700150 } else {
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100151 timer_del(timer);
152 timer_free(timer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700153 }
154}
155
156void qemu_announce_self(void)
157{
158 static QEMUTimer *timer;
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100159 timer = timer_new_ms(QEMU_CLOCK_REALTIME, qemu_announce_self_once, &timer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700160 qemu_announce_self_once(&timer);
161}
162
163/***********************************************************/
164/* savevm/loadvm support */
165
David 'Digit' Turner1365eb22014-02-16 22:23:26 +0100166void yield_until_fd_readable(int fd);
167
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700168#define IO_BUF_SIZE 32768
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100169#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700170
171struct QEMUFile {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100172 const QEMUFileOps *ops;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700173 void *opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700174
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100175 int64_t bytes_xfer;
176 int64_t xfer_limit;
177
178 int64_t pos; /* start of buffer when writing, end of buffer
179 when reading */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700180 int buf_index;
181 int buf_size; /* 0 when writing */
182 uint8_t buf[IO_BUF_SIZE];
183
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100184 struct iovec iov[MAX_IOV_SIZE];
185 unsigned int iovcnt;
186
187 int last_error;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700188};
189
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200190typedef struct QEMUFileStdio
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700191{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200192 FILE *stdio_file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700193 QEMUFile *file;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200194} QEMUFileStdio;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700195
196typedef struct QEMUFileSocket
197{
198 int fd;
199 QEMUFile *file;
200} QEMUFileSocket;
201
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100202static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
203 int64_t pos)
204{
205 QEMUFileSocket *s = opaque;
206 ssize_t len;
207 ssize_t size = iov_size(iov, iovcnt);
208
209 len = iov_send(s->fd, iov, iovcnt, 0, size);
210 if (len < size) {
211 len = -socket_error();
212 }
213 return len;
214}
215
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100216static int socket_get_fd(void *opaque)
217{
218 QEMUFileSocket *s = opaque;
219
220 return s->fd;
221}
222
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200223static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700224{
225 QEMUFileSocket *s = opaque;
226 ssize_t len;
227
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100228 for (;;) {
229 len = qemu_recv(s->fd, buf, size, 0);
230 if (len != -1) {
231 break;
232 }
233#ifndef CONFIG_ANDROID
234 if (socket_error() == EAGAIN) {
235 yield_until_fd_readable(s->fd);
236 } else if (socket_error() != EINTR) {
237 break;
238 }
239#else
240 if (socket_error() != EINTR)
241 break;
242#endif
243 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700244
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100245 if (len == -1) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700246 len = -socket_error();
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100247 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700248 return len;
249}
250
251static int file_socket_close(void *opaque)
252{
253 QEMUFileSocket *s = opaque;
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100254 if (s->fd >= 0)
255 socket_close(s->fd);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100256 g_free(s);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700257 return 0;
258}
259
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100260static int stdio_get_fd(void *opaque)
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100261{
262 QEMUFileStdio *s = opaque;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100263
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100264 return fileno(s->stdio_file);
265}
266
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200267static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700268{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200269 QEMUFileStdio *s = opaque;
270 return fwrite(buf, 1, size, s->stdio_file);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700271}
272
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200273static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700274{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200275 QEMUFileStdio *s = opaque;
276 FILE *fp = s->stdio_file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700277 int bytes;
278
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100279 for (;;) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700280 clearerr(fp);
281 bytes = fread(buf, 1, size, fp);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100282 if (bytes != 0 || !ferror(fp)) {
283 break;
284 }
285#ifndef CONFIG_ANDROID
286 if (errno == EAGAIN) {
287 yield_until_fd_readable(fileno(fp));
288 } else if (errno != EINTR) {
289 break;
290 }
291#else
292 if (errno != EINTR)
293 break;
294#endif
295 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700296 return bytes;
297}
298
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200299static int stdio_pclose(void *opaque)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700300{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200301 QEMUFileStdio *s = opaque;
302 int ret;
303 ret = pclose(s->stdio_file);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100304 if (ret == -1) {
305 ret = -errno;
306 } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
307 /* close succeeded, but non-zero exit code: */
308 ret = -EIO; /* fake errno value */
309 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100310 g_free(s);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200311 return ret;
312}
313
314static int stdio_fclose(void *opaque)
315{
316 QEMUFileStdio *s = opaque;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100317 int ret = 0;
318
319 if (s->file->ops->put_buffer || s->file->ops->writev_buffer) {
320 int fd = fileno(s->stdio_file);
321 struct stat st;
322
323 ret = fstat(fd, &st);
324 if (ret == 0 && S_ISREG(st.st_mode)) {
325 /*
326 * If the file handle is a regular file make sure the
327 * data is flushed to disk before signaling success.
328 */
329 ret = fsync(fd);
330 if (ret != 0) {
331 ret = -errno;
332 return ret;
333 }
334 }
335 }
336 if (fclose(s->stdio_file) == EOF) {
337 ret = -errno;
338 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100339 g_free(s);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100340 return ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700341}
342
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100343static const QEMUFileOps stdio_pipe_read_ops = {
344 .get_fd = stdio_get_fd,
345 .get_buffer = stdio_get_buffer,
346 .close = stdio_pclose
347};
348
349static const QEMUFileOps stdio_pipe_write_ops = {
350 .get_fd = stdio_get_fd,
351 .put_buffer = stdio_put_buffer,
352 .close = stdio_pclose
353};
354
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100355QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700356{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100357 FILE *stdio_file;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200358 QEMUFileStdio *s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700359
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100360 if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700361 fprintf(stderr, "qemu_popen: Argument validity check failed\n");
362 return NULL;
363 }
364
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100365 stdio_file = popen(command, mode);
366 if (stdio_file == NULL) {
367 return NULL;
368 }
369
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100370 s = g_malloc0(sizeof(QEMUFileStdio));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700371
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200372 s->stdio_file = stdio_file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700373
374 if(mode[0] == 'r') {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100375 s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700376 } else {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100377 s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700378 }
379 return s->file;
380}
381
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100382static const QEMUFileOps stdio_file_read_ops = {
383 .get_fd = stdio_get_fd,
384 .get_buffer = stdio_get_buffer,
385 .close = stdio_fclose
386};
387
388static const QEMUFileOps stdio_file_write_ops = {
389 .get_fd = stdio_get_fd,
390 .put_buffer = stdio_put_buffer,
391 .close = stdio_fclose
392};
393
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100394static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
395 int64_t pos)
396{
397 QEMUFileSocket *s = opaque;
398 ssize_t len, offset;
399 ssize_t size = iov_size(iov, iovcnt);
400 ssize_t total = 0;
401
402 assert(iovcnt > 0);
403 offset = 0;
404 while (size > 0) {
405 /* Find the next start position; skip all full-sized vector elements */
406 while (offset >= iov[0].iov_len) {
407 offset -= iov[0].iov_len;
408 iov++, iovcnt--;
409 }
410
411 /* skip `offset' bytes from the (now) first element, undo it on exit */
412 assert(iovcnt > 0);
413 iov[0].iov_base += offset;
414 iov[0].iov_len -= offset;
415
416 do {
417 len = writev(s->fd, iov, iovcnt);
418 } while (len == -1 && errno == EINTR);
419 if (len == -1) {
420 return -errno;
421 }
422
423 /* Undo the changes above */
424 iov[0].iov_base -= offset;
425 iov[0].iov_len += offset;
426
427 /* Prepare for the next iteration */
428 offset += len;
429 total += len;
430 size -= len;
431 }
432
433 return total;
434}
435
436static int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
437{
438 QEMUFileSocket *s = opaque;
439 ssize_t len;
440
441 for (;;) {
442 len = read(s->fd, buf, size);
443 if (len != -1) {
444 break;
445 }
446 if (errno == EAGAIN) {
447 yield_until_fd_readable(s->fd);
448 } else if (errno != EINTR) {
449 break;
450 }
451 }
452
453 if (len == -1) {
454 len = -errno;
455 }
456 return len;
457}
458
459static int unix_close(void *opaque)
460{
461 QEMUFileSocket *s = opaque;
462 close(s->fd);
463 g_free(s);
464 return 0;
465}
466
467static const QEMUFileOps unix_read_ops = {
468 .get_fd = socket_get_fd,
469 .get_buffer = unix_get_buffer,
470 .close = unix_close
471};
472
473static const QEMUFileOps unix_write_ops = {
474 .get_fd = socket_get_fd,
475 .writev_buffer = unix_writev_buffer,
476 .close = unix_close
477};
478
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200479QEMUFile *qemu_fdopen(int fd, const char *mode)
480{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100481 QEMUFileSocket *s;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200482
483 if (mode == NULL ||
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100484 (mode[0] != 'r' && mode[0] != 'w') ||
485 mode[1] != 'b' || mode[2] != 0) {
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200486 fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
487 return NULL;
488 }
489
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100490 s = g_malloc0(sizeof(QEMUFileSocket));
491 s->fd = fd;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200492
493 if(mode[0] == 'r') {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100494 s->file = qemu_fopen_ops(s, &unix_read_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200495 } else {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100496 s->file = qemu_fopen_ops(s, &unix_write_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200497 }
498 return s->file;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200499}
500
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100501static const QEMUFileOps socket_read_ops = {
502 .get_fd = socket_get_fd,
503 .get_buffer = socket_get_buffer,
504 .close = file_socket_close
505};
506
507static const QEMUFileOps socket_write_ops = {
508 .get_fd = socket_get_fd,
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100509 .writev_buffer = socket_writev_buffer,
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100510 .close = file_socket_close
511};
512
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100513bool qemu_file_mode_is_not_valid(const char *mode)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700514{
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100515 if (mode == NULL ||
516 (mode[0] != 'r' && mode[0] != 'w') ||
517 mode[1] != 'b' || mode[2] != 0) {
518 fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
519 return true;
520 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700521
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100522 return false;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700523}
524
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100525QEMUFile *qemu_fopen_socket(int fd, const char *mode)
526{
527 QEMUFileSocket *s;
528
529 if (qemu_file_mode_is_not_valid(mode)) {
530 return NULL;
531 }
532
533 s = g_malloc0(sizeof(QEMUFileSocket));
534 s->fd = fd;
535 if (mode[0] == 'w') {
536 qemu_set_block(s->fd);
537 s->file = qemu_fopen_ops(s, &socket_write_ops);
538 } else {
539 s->file = qemu_fopen_ops(s, &socket_read_ops);
540 }
541 return s->file;
542}
543
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700544QEMUFile *qemu_fopen(const char *filename, const char *mode)
545{
546 QEMUFileStdio *s;
547
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100548 if (qemu_file_mode_is_not_valid(mode)) {
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200549 return NULL;
550 }
551
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100552 s = g_malloc0(sizeof(QEMUFileStdio));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700553
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200554 s->stdio_file = fopen(filename, mode);
555 if (!s->stdio_file)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700556 goto fail;
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100557
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200558 if(mode[0] == 'w') {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100559 s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200560 } else {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100561 s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200562 }
563 return s->file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700564fail:
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100565 g_free(s);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700566 return NULL;
567}
568
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100569#ifndef CONFIG_ANDROID
570// TODO(digit): Once bdrv_writev_vmstate() is implemented.
571static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
572 int64_t pos)
573{
574 int ret;
575 QEMUIOVector qiov;
576
577 qemu_iovec_init_external(&qiov, iov, iovcnt);
578 ret = bdrv_writev_vmstate(opaque, &qiov, pos);
579 if (ret < 0) {
580 return ret;
581 }
582
583 return qiov.size;
584}
585#endif
586
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700587static int block_put_buffer(void *opaque, const uint8_t *buf,
588 int64_t pos, int size)
589{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200590 bdrv_save_vmstate(opaque, buf, pos, size);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700591 return size;
592}
593
594static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
595{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200596 return bdrv_load_vmstate(opaque, buf, pos, size);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700597}
598
599static int bdrv_fclose(void *opaque)
600{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100601 // TODO(digit): bdrv_flush() should return error code.
602 bdrv_flush(opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700603 return 0;
604}
605
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100606static const QEMUFileOps bdrv_read_ops = {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100607 .get_buffer = block_get_buffer,
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100608 .close = bdrv_fclose
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100609};
610
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100611static const QEMUFileOps bdrv_write_ops = {
612 .put_buffer = block_put_buffer,
613 //.writev_buffer = block_writev_buffer,
614 .close = bdrv_fclose
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100615};
616
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200617static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700618{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700619 if (is_writable)
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100620 return qemu_fopen_ops(bs, &bdrv_write_ops);
621 return qemu_fopen_ops(bs, &bdrv_read_ops);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700622}
623
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100624QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700625{
626 QEMUFile *f;
627
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100628 f = g_malloc0(sizeof(QEMUFile));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700629
630 f->opaque = opaque;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100631 f->ops = ops;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700632 return f;
633}
634
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100635/*
636 * Get last error for stream f
637 *
638 * Return negative error value if there has been an error on previous
639 * operations, return 0 if no error happened.
640 *
641 */
642int qemu_file_get_error(QEMUFile *f)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700643{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100644 return f->last_error;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700645}
646
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100647void qemu_file_set_error(QEMUFile *f, int ret)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700648{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100649 if (f->last_error == 0) {
650 f->last_error = ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700651 }
652}
653
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100654static inline bool qemu_file_is_writable(QEMUFile *f)
655{
656 return f->ops->writev_buffer || f->ops->put_buffer;
657}
658
659/**
660 * Flushes QEMUFile buffer
661 *
662 * If there is writev_buffer QEMUFileOps it uses it otherwise uses
663 * put_buffer ops.
664 */
665void qemu_fflush(QEMUFile *f)
666{
667 ssize_t ret = 0;
668
669 if (!qemu_file_is_writable(f)) {
670 return;
671 }
672
673 if (f->ops->writev_buffer) {
674 if (f->iovcnt > 0) {
675 ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
676 }
677 } else {
678 if (f->buf_index > 0) {
679 ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
680 }
681 }
682 if (ret >= 0) {
683 f->pos += ret;
684 }
685 f->buf_index = 0;
686 f->iovcnt = 0;
687 if (ret < 0) {
688 qemu_file_set_error(f, ret);
689 }
690}
691
692#ifndef CONFIG_ANDROID
693// TODO(digit).
694void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
695{
696 int ret = 0;
697
698 if (f->ops->before_ram_iterate) {
699 ret = f->ops->before_ram_iterate(f, f->opaque, flags);
700 if (ret < 0) {
701 qemu_file_set_error(f, ret);
702 }
703 }
704}
705
706void ram_control_after_iterate(QEMUFile *f, uint64_t flags)
707{
708 int ret = 0;
709
710 if (f->ops->after_ram_iterate) {
711 ret = f->ops->after_ram_iterate(f, f->opaque, flags);
712 if (ret < 0) {
713 qemu_file_set_error(f, ret);
714 }
715 }
716}
717
718void ram_control_load_hook(QEMUFile *f, uint64_t flags)
719{
720 int ret = -EINVAL;
721
722 if (f->ops->hook_ram_load) {
723 ret = f->ops->hook_ram_load(f, f->opaque, flags);
724 if (ret < 0) {
725 qemu_file_set_error(f, ret);
726 }
727 } else {
728 qemu_file_set_error(f, ret);
729 }
730}
731
732size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
733 ram_addr_t offset, size_t size, int *bytes_sent)
734{
735 if (f->ops->save_page) {
736 int ret = f->ops->save_page(f, f->opaque, block_offset,
737 offset, size, bytes_sent);
738
739 if (ret != RAM_SAVE_CONTROL_DELAYED) {
740 if (bytes_sent && *bytes_sent > 0) {
741 qemu_update_position(f, *bytes_sent);
742 } else if (ret < 0) {
743 qemu_file_set_error(f, ret);
744 }
745 }
746
747 return ret;
748 }
749
750 return RAM_SAVE_CONTROL_NOT_SUPP;
751}
752#endif // !CONFIG_ANDROID
753
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700754static void qemu_fill_buffer(QEMUFile *f)
755{
756 int len;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100757 int pending;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700758
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100759 assert(!qemu_file_is_writable(f));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700760
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100761 pending = f->buf_size - f->buf_index;
762 if (pending > 0) {
763 memmove(f->buf, f->buf + f->buf_index, pending);
764 }
765 f->buf_index = 0;
766 f->buf_size = pending;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700767
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100768 len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
769 IO_BUF_SIZE - pending);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700770 if (len > 0) {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100771 f->buf_size += len;
772 f->pos += len;
773 } else if (len == 0) {
774 qemu_file_set_error(f, -EIO);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700775 } else if (len != -EAGAIN)
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100776 qemu_file_set_error(f, len);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700777}
778
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100779int qemu_get_fd(QEMUFile *f)
780{
781 if (f->ops->get_fd) {
782 return f->ops->get_fd(f->opaque);
783 }
784 return -1;
785}
786
787void qemu_update_position(QEMUFile *f, size_t size)
788{
789 f->pos += size;
790}
791
792/** Closes the file
793 *
794 * Returns negative error value if any error happened on previous operations or
795 * while closing the file. Returns 0 or positive number on success.
796 *
797 * The meaning of return value on success depends on the specific backend
798 * being used.
799 */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700800int qemu_fclose(QEMUFile *f)
801{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100802 int ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700803 qemu_fflush(f);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100804 ret = qemu_file_get_error(f);
805
806 if (f->ops->close) {
807 int ret2 = f->ops->close(f->opaque);
808 if (ret >= 0) {
809 ret = ret2;
810 }
811 }
812 /* If any error was spotted before closing, we should report it
813 * instead of the close() return value.
814 */
815 if (f->last_error) {
816 ret = f->last_error;
817 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100818 g_free(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700819 return ret;
820}
821
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100822static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700823{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100824 /* check for adjacent buffer and coalesce them */
825 if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base +
826 f->iov[f->iovcnt - 1].iov_len) {
827 f->iov[f->iovcnt - 1].iov_len += size;
828 } else {
829 f->iov[f->iovcnt].iov_base = (uint8_t *)buf;
830 f->iov[f->iovcnt++].iov_len = size;
831 }
832
833 if (f->iovcnt >= MAX_IOV_SIZE) {
834 qemu_fflush(f);
835 }
836}
837
838void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size)
839{
840 if (!f->ops->writev_buffer) {
841 qemu_put_buffer(f, buf, size);
842 return;
843 }
844
845 if (f->last_error) {
846 return;
847 }
848
849 f->bytes_xfer += size;
850 add_to_iovec(f, buf, size);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700851}
852
853void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
854{
855 int l;
856
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100857 if (f->last_error) {
858 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700859 }
860
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100861 while (size > 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700862 l = IO_BUF_SIZE - f->buf_index;
863 if (l > size)
864 l = size;
865 memcpy(f->buf + f->buf_index, buf, l);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100866 f->bytes_xfer += l;
867 if (f->ops->writev_buffer) {
868 add_to_iovec(f, f->buf + f->buf_index, l);
869 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700870 f->buf_index += l;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100871 if (f->buf_index == IO_BUF_SIZE) {
872 qemu_fflush(f);
873 }
874 if (qemu_file_get_error(f)) {
875 break;
876 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700877 buf += l;
878 size -= l;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700879 }
880}
881
882void qemu_put_byte(QEMUFile *f, int v)
883{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100884 if (f->last_error) {
885 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700886 }
887
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100888 f->buf[f->buf_index] = v;
889 f->bytes_xfer++;
890 if (f->ops->writev_buffer) {
891 add_to_iovec(f, f->buf + f->buf_index, 1);
892 }
893 f->buf_index++;
894 if (f->buf_index == IO_BUF_SIZE) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700895 qemu_fflush(f);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100896 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700897}
898
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100899static void qemu_file_skip(QEMUFile *f, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700900{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100901 if (f->buf_index + size <= f->buf_size) {
902 f->buf_index += size;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700903 }
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100904}
905
906static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
907{
908 int pending;
909 int index;
910
911 assert(!qemu_file_is_writable(f));
912
913 index = f->buf_index + offset;
914 pending = f->buf_size - index;
915 if (pending < size) {
916 qemu_fill_buffer(f);
917 index = f->buf_index + offset;
918 pending = f->buf_size - index;
919 }
920
921 if (pending <= 0) {
922 return 0;
923 }
924 if (size > pending) {
925 size = pending;
926 }
927
928 memcpy(buf, f->buf + index, size);
929 return size;
930}
931
932int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
933{
934 int pending = size;
935 int done = 0;
936
937 while (pending > 0) {
938 int res;
939
940 res = qemu_peek_buffer(f, buf, pending, 0);
941 if (res == 0) {
942 return done;
943 }
944 qemu_file_skip(f, res);
945 buf += res;
946 pending -= res;
947 done += res;
948 }
949 return done;
950}
951
952static int qemu_peek_byte(QEMUFile *f, int offset)
953{
954 int index = f->buf_index + offset;
955
956 assert(!qemu_file_is_writable(f));
957
958 if (index >= f->buf_size) {
959 qemu_fill_buffer(f);
960 index = f->buf_index + offset;
961 if (index >= f->buf_size) {
962 return 0;
963 }
964 }
965 return f->buf[index];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700966}
967
968int qemu_get_byte(QEMUFile *f)
969{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100970 int result;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700971
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100972 result = qemu_peek_byte(f, 0);
973 qemu_file_skip(f, 1);
974 return result;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700975}
976
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200977#ifdef CONFIG_ANDROID
978void qemu_put_string(QEMUFile *f, const char* str)
979{
980 /* We will encode NULL and the empty string in the same way */
981 int slen;
982 if (str == NULL) {
983 str = "";
984 }
985 slen = strlen(str);
986 qemu_put_be32(f, slen);
987 qemu_put_buffer(f, (const uint8_t*)str, slen);
988}
989
990char* qemu_get_string(QEMUFile *f)
991{
992 int slen = qemu_get_be32(f);
993 char* str;
994 if (slen == 0)
995 return NULL;
996
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100997 str = g_malloc(slen+1);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200998 if (qemu_get_buffer(f, (uint8_t*)str, slen) != slen) {
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100999 g_free(str);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001000 return NULL;
1001 }
1002 str[slen] = '\0';
1003 return str;
1004}
1005#endif
1006
1007
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001008int64_t qemu_ftell(QEMUFile *f)
1009{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001010 qemu_fflush(f);
1011 return f->pos;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001012}
1013
1014int qemu_file_rate_limit(QEMUFile *f)
1015{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001016 if (qemu_file_get_error(f)) {
1017 return 1;
1018 }
1019 if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) {
1020 return 1;
1021 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001022 return 0;
1023}
1024
David 'Digit' Turner986acc92011-05-10 16:50:01 +02001025int64_t qemu_file_get_rate_limit(QEMUFile *f)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001026{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001027 return f->xfer_limit;
David 'Digit' Turner986acc92011-05-10 16:50:01 +02001028}
1029
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001030void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit)
David 'Digit' Turner986acc92011-05-10 16:50:01 +02001031{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001032 f->xfer_limit = limit;
1033}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001034
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001035void qemu_file_reset_rate_limit(QEMUFile *f)
1036{
1037 f->bytes_xfer = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001038}
1039
1040void qemu_put_be16(QEMUFile *f, unsigned int v)
1041{
1042 qemu_put_byte(f, v >> 8);
1043 qemu_put_byte(f, v);
1044}
1045
1046void qemu_put_be32(QEMUFile *f, unsigned int v)
1047{
1048 qemu_put_byte(f, v >> 24);
1049 qemu_put_byte(f, v >> 16);
1050 qemu_put_byte(f, v >> 8);
1051 qemu_put_byte(f, v);
1052}
1053
1054void qemu_put_be64(QEMUFile *f, uint64_t v)
1055{
1056 qemu_put_be32(f, v >> 32);
1057 qemu_put_be32(f, v);
1058}
1059
1060unsigned int qemu_get_be16(QEMUFile *f)
1061{
1062 unsigned int v;
1063 v = qemu_get_byte(f) << 8;
1064 v |= qemu_get_byte(f);
1065 return v;
1066}
1067
1068unsigned int qemu_get_be32(QEMUFile *f)
1069{
1070 unsigned int v;
1071 v = qemu_get_byte(f) << 24;
1072 v |= qemu_get_byte(f) << 16;
1073 v |= qemu_get_byte(f) << 8;
1074 v |= qemu_get_byte(f);
1075 return v;
1076}
1077
1078uint64_t qemu_get_be64(QEMUFile *f)
1079{
1080 uint64_t v;
1081 v = (uint64_t)qemu_get_be32(f) << 32;
1082 v |= qemu_get_be32(f);
1083 return v;
1084}
1085
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +01001086
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001087void qemu_put_struct(QEMUFile* f, const QField* fields, const void* s)
1088{
1089 const QField* qf = fields;
1090
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001091 /* Iterate over struct fields */
1092 while (qf->type != Q_FIELD_END) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001093 uint8_t* p = (uint8_t*)s + qf->offset;
1094
1095 switch (qf->type) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001096 case Q_FIELD_BYTE:
1097 qemu_put_byte(f, p[0]);
1098 break;
1099 case Q_FIELD_INT16:
1100 qemu_put_be16(f, ((uint16_t*)p)[0]);
1101 break;
1102 case Q_FIELD_INT32:
1103 qemu_put_be32(f, ((uint32_t*)p)[0]);
1104 break;
1105 case Q_FIELD_INT64:
1106 qemu_put_be64(f, ((uint64_t*)p)[0]);
1107 break;
1108 case Q_FIELD_BUFFER:
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001109 if (qf[1].type != Q_FIELD_BUFFER_SIZE ||
1110 qf[2].type != Q_FIELD_BUFFER_SIZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001111 {
1112 fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n",
1113 __FUNCTION__ );
1114 exit(1);
1115 }
1116 else
1117 {
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001118 uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001119
1120 qemu_put_buffer(f, p, size);
1121 qf += 2;
1122 }
1123 break;
1124 default:
1125 fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
1126 exit(1);
1127 }
1128 qf++;
1129 }
1130}
1131
1132int qemu_get_struct(QEMUFile* f, const QField* fields, void* s)
1133{
1134 const QField* qf = fields;
1135
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001136 /* Iterate over struct fields */
1137 while (qf->type != Q_FIELD_END) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001138 uint8_t* p = (uint8_t*)s + qf->offset;
1139
1140 switch (qf->type) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001141 case Q_FIELD_BYTE:
1142 p[0] = qemu_get_byte(f);
1143 break;
1144 case Q_FIELD_INT16:
1145 ((uint16_t*)p)[0] = qemu_get_be16(f);
1146 break;
1147 case Q_FIELD_INT32:
1148 ((uint32_t*)p)[0] = qemu_get_be32(f);
1149 break;
1150 case Q_FIELD_INT64:
1151 ((uint64_t*)p)[0] = qemu_get_be64(f);
1152 break;
1153 case Q_FIELD_BUFFER:
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001154 if (qf[1].type != Q_FIELD_BUFFER_SIZE ||
1155 qf[2].type != Q_FIELD_BUFFER_SIZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001156 {
1157 fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n",
1158 __FUNCTION__ );
1159 return -1;
1160 }
1161 else
1162 {
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001163 uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001164 int ret = qemu_get_buffer(f, p, size);
1165
1166 if (ret != size) {
1167 fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__);
1168 return -1;
1169 }
1170 qf += 2;
1171 }
1172 break;
1173 default:
1174 fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
1175 exit(1);
1176 }
1177 qf++;
1178 }
1179 return 0;
1180}
1181
Ot ten Thije871da2a2010-09-20 10:29:22 +01001182/* write a float to file */
1183void qemu_put_float(QEMUFile *f, float v)
1184{
1185 uint8_t *bytes = (uint8_t*) &v;
1186 qemu_put_buffer(f, bytes, sizeof(float));
1187}
1188
1189/* read a float from file */
1190float qemu_get_float(QEMUFile *f)
1191{
1192 uint8_t bytes[sizeof(float)];
1193 qemu_get_buffer(f, bytes, sizeof(float));
1194
1195 return *((float*) bytes);
1196}
1197
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001198/* timer */
1199
1200void timer_put(QEMUFile *f, QEMUTimer *ts)
1201{
1202 uint64_t expire_time;
1203
1204 expire_time = timer_expire_time_ns(ts);
1205 qemu_put_be64(f, expire_time);
1206}
1207
1208void timer_get(QEMUFile *f, QEMUTimer *ts)
1209{
1210 uint64_t expire_time;
1211
1212 expire_time = qemu_get_be64(f);
1213 if (expire_time != -1) {
1214 timer_mod_ns(ts, expire_time);
1215 } else {
1216 timer_del(ts);
1217 }
1218}
1219
1220
1221/* bool */
1222
1223static int get_bool(QEMUFile *f, void *pv, size_t size)
1224{
1225 bool *v = pv;
1226 *v = qemu_get_byte(f);
1227 return 0;
1228}
1229
1230static void put_bool(QEMUFile *f, void *pv, size_t size)
1231{
1232 bool *v = pv;
1233 qemu_put_byte(f, *v);
1234}
1235
1236const VMStateInfo vmstate_info_bool = {
1237 .name = "bool",
1238 .get = get_bool,
1239 .put = put_bool,
1240};
1241
1242/* 8 bit int */
1243
1244static int get_int8(QEMUFile *f, void *pv, size_t size)
1245{
1246 int8_t *v = pv;
1247 qemu_get_s8s(f, v);
1248 return 0;
1249}
1250
1251static void put_int8(QEMUFile *f, void *pv, size_t size)
1252{
1253 int8_t *v = pv;
1254 qemu_put_s8s(f, v);
1255}
1256
1257const VMStateInfo vmstate_info_int8 = {
1258 .name = "int8",
1259 .get = get_int8,
1260 .put = put_int8,
1261};
1262
1263/* 16 bit int */
1264
1265static int get_int16(QEMUFile *f, void *pv, size_t size)
1266{
1267 int16_t *v = pv;
1268 qemu_get_sbe16s(f, v);
1269 return 0;
1270}
1271
1272static void put_int16(QEMUFile *f, void *pv, size_t size)
1273{
1274 int16_t *v = pv;
1275 qemu_put_sbe16s(f, v);
1276}
1277
1278const VMStateInfo vmstate_info_int16 = {
1279 .name = "int16",
1280 .get = get_int16,
1281 .put = put_int16,
1282};
1283
1284/* 32 bit int */
1285
1286static int get_int32(QEMUFile *f, void *pv, size_t size)
1287{
1288 int32_t *v = pv;
1289 qemu_get_sbe32s(f, v);
1290 return 0;
1291}
1292
1293static void put_int32(QEMUFile *f, void *pv, size_t size)
1294{
1295 int32_t *v = pv;
1296 qemu_put_sbe32s(f, v);
1297}
1298
1299const VMStateInfo vmstate_info_int32 = {
1300 .name = "int32",
1301 .get = get_int32,
1302 .put = put_int32,
1303};
1304
1305/* 32 bit int. See that the received value is the same than the one
1306 in the field */
1307
1308static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
1309{
1310 int32_t *v = pv;
1311 int32_t v2;
1312 qemu_get_sbe32s(f, &v2);
1313
1314 if (*v == v2)
1315 return 0;
1316 return -EINVAL;
1317}
1318
1319const VMStateInfo vmstate_info_int32_equal = {
1320 .name = "int32 equal",
1321 .get = get_int32_equal,
1322 .put = put_int32,
1323};
1324
1325/* 32 bit int. See that the received value is the less or the same
1326 than the one in the field */
1327
1328static int get_int32_le(QEMUFile *f, void *pv, size_t size)
1329{
1330 int32_t *old = pv;
1331 int32_t new;
1332 qemu_get_sbe32s(f, &new);
1333
1334 if (*old <= new)
1335 return 0;
1336 return -EINVAL;
1337}
1338
1339const VMStateInfo vmstate_info_int32_le = {
1340 .name = "int32 equal",
1341 .get = get_int32_le,
1342 .put = put_int32,
1343};
1344
1345/* 64 bit int */
1346
1347static int get_int64(QEMUFile *f, void *pv, size_t size)
1348{
1349 int64_t *v = pv;
1350 qemu_get_sbe64s(f, v);
1351 return 0;
1352}
1353
1354static void put_int64(QEMUFile *f, void *pv, size_t size)
1355{
1356 int64_t *v = pv;
1357 qemu_put_sbe64s(f, v);
1358}
1359
1360const VMStateInfo vmstate_info_int64 = {
1361 .name = "int64",
1362 .get = get_int64,
1363 .put = put_int64,
1364};
1365
1366/* 8 bit unsigned int */
1367
1368static int get_uint8(QEMUFile *f, void *pv, size_t size)
1369{
1370 uint8_t *v = pv;
1371 qemu_get_8s(f, v);
1372 return 0;
1373}
1374
1375static void put_uint8(QEMUFile *f, void *pv, size_t size)
1376{
1377 uint8_t *v = pv;
1378 qemu_put_8s(f, v);
1379}
1380
1381const VMStateInfo vmstate_info_uint8 = {
1382 .name = "uint8",
1383 .get = get_uint8,
1384 .put = put_uint8,
1385};
1386
1387/* 16 bit unsigned int */
1388
1389static int get_uint16(QEMUFile *f, void *pv, size_t size)
1390{
1391 uint16_t *v = pv;
1392 qemu_get_be16s(f, v);
1393 return 0;
1394}
1395
1396static void put_uint16(QEMUFile *f, void *pv, size_t size)
1397{
1398 uint16_t *v = pv;
1399 qemu_put_be16s(f, v);
1400}
1401
1402const VMStateInfo vmstate_info_uint16 = {
1403 .name = "uint16",
1404 .get = get_uint16,
1405 .put = put_uint16,
1406};
1407
1408/* 32 bit unsigned int */
1409
1410static int get_uint32(QEMUFile *f, void *pv, size_t size)
1411{
1412 uint32_t *v = pv;
1413 qemu_get_be32s(f, v);
1414 return 0;
1415}
1416
1417static void put_uint32(QEMUFile *f, void *pv, size_t size)
1418{
1419 uint32_t *v = pv;
1420 qemu_put_be32s(f, v);
1421}
1422
1423const VMStateInfo vmstate_info_uint32 = {
1424 .name = "uint32",
1425 .get = get_uint32,
1426 .put = put_uint32,
1427};
1428
1429/* 32 bit uint. See that the received value is the same than the one
1430 in the field */
1431
1432static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
1433{
1434 uint32_t *v = pv;
1435 uint32_t v2;
1436 qemu_get_be32s(f, &v2);
1437
1438 if (*v == v2) {
1439 return 0;
1440 }
1441 return -EINVAL;
1442}
1443
1444const VMStateInfo vmstate_info_uint32_equal = {
1445 .name = "uint32 equal",
1446 .get = get_uint32_equal,
1447 .put = put_uint32,
1448};
1449
1450/* 64 bit unsigned int */
1451
1452static int get_uint64(QEMUFile *f, void *pv, size_t size)
1453{
1454 uint64_t *v = pv;
1455 qemu_get_be64s(f, v);
1456 return 0;
1457}
1458
1459static void put_uint64(QEMUFile *f, void *pv, size_t size)
1460{
1461 uint64_t *v = pv;
1462 qemu_put_be64s(f, v);
1463}
1464
1465const VMStateInfo vmstate_info_uint64 = {
1466 .name = "uint64",
1467 .get = get_uint64,
1468 .put = put_uint64,
1469};
1470
1471/* 64 bit unsigned int. See that the received value is the same than the one
1472 in the field */
1473
1474static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
1475{
1476 uint64_t *v = pv;
1477 uint64_t v2;
1478 qemu_get_be64s(f, &v2);
1479
1480 if (*v == v2) {
1481 return 0;
1482 }
1483 return -EINVAL;
1484}
1485
1486const VMStateInfo vmstate_info_uint64_equal = {
1487 .name = "int64 equal",
1488 .get = get_uint64_equal,
1489 .put = put_uint64,
1490};
1491
1492/* 8 bit int. See that the received value is the same than the one
1493 in the field */
1494
1495static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
1496{
1497 uint8_t *v = pv;
1498 uint8_t v2;
1499 qemu_get_8s(f, &v2);
1500
1501 if (*v == v2)
1502 return 0;
1503 return -EINVAL;
1504}
1505
1506const VMStateInfo vmstate_info_uint8_equal = {
1507 .name = "uint8 equal",
1508 .get = get_uint8_equal,
1509 .put = put_uint8,
1510};
1511
1512/* 16 bit unsigned int int. See that the received value is the same than the one
1513 in the field */
1514
1515static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
1516{
1517 uint16_t *v = pv;
1518 uint16_t v2;
1519 qemu_get_be16s(f, &v2);
1520
1521 if (*v == v2)
1522 return 0;
1523 return -EINVAL;
1524}
1525
1526const VMStateInfo vmstate_info_uint16_equal = {
1527 .name = "uint16 equal",
1528 .get = get_uint16_equal,
1529 .put = put_uint16,
1530};
1531
1532/* floating point */
1533
1534static int get_float64(QEMUFile *f, void *pv, size_t size)
1535{
1536 float64 *v = pv;
1537
1538 *v = make_float64(qemu_get_be64(f));
1539 return 0;
1540}
1541
1542static void put_float64(QEMUFile *f, void *pv, size_t size)
1543{
1544 uint64_t *v = pv;
1545
1546 qemu_put_be64(f, float64_val(*v));
1547}
1548
1549const VMStateInfo vmstate_info_float64 = {
1550 .name = "float64",
1551 .get = get_float64,
1552 .put = put_float64,
1553};
1554
1555/* timers */
1556
1557static int get_timer(QEMUFile *f, void *pv, size_t size)
1558{
1559 QEMUTimer *v = pv;
1560 timer_get(f, v);
1561 return 0;
1562}
1563
1564static void put_timer(QEMUFile *f, void *pv, size_t size)
1565{
1566 QEMUTimer *v = pv;
1567 timer_put(f, v);
1568}
1569
1570const VMStateInfo vmstate_info_timer = {
1571 .name = "timer",
1572 .get = get_timer,
1573 .put = put_timer,
1574};
1575
1576/* uint8_t buffers */
1577
1578static int get_buffer(QEMUFile *f, void *pv, size_t size)
1579{
1580 uint8_t *v = pv;
1581 qemu_get_buffer(f, v, size);
1582 return 0;
1583}
1584
1585static void put_buffer(QEMUFile *f, void *pv, size_t size)
1586{
1587 uint8_t *v = pv;
1588 qemu_put_buffer(f, v, size);
1589}
1590
1591const VMStateInfo vmstate_info_buffer = {
1592 .name = "buffer",
1593 .get = get_buffer,
1594 .put = put_buffer,
1595};
1596
1597/* unused buffers: space that was used for some fields that are
1598 not useful anymore */
1599
1600static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
1601{
1602 uint8_t buf[1024];
1603 int block_len;
1604
1605 while (size > 0) {
1606 block_len = MIN(sizeof(buf), size);
1607 size -= block_len;
1608 qemu_get_buffer(f, buf, block_len);
1609 }
1610 return 0;
1611}
1612
1613static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
1614{
1615 static const uint8_t buf[1024];
1616 int block_len;
1617
1618 while (size > 0) {
1619 block_len = MIN(sizeof(buf), size);
1620 size -= block_len;
1621 qemu_put_buffer(f, buf, block_len);
1622 }
1623}
1624
1625const VMStateInfo vmstate_info_unused_buffer = {
1626 .name = "unused_buffer",
1627 .get = get_unused_buffer,
1628 .put = put_unused_buffer,
1629};
1630
1631/* bitmaps (as defined by bitmap.h). Note that size here is the size
1632 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
1633 * bit words with the bits in big endian order. The in-memory format
1634 * is an array of 'unsigned long', which may be either 32 or 64 bits.
1635 */
1636/* This is the number of 64 bit words sent over the wire */
1637#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
1638static int get_bitmap(QEMUFile *f, void *pv, size_t size)
1639{
1640 unsigned long *bmp = pv;
1641 int i, idx = 0;
1642 for (i = 0; i < BITS_TO_U64S(size); i++) {
1643 uint64_t w = qemu_get_be64(f);
1644 bmp[idx++] = w;
1645 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
1646 bmp[idx++] = w >> 32;
1647 }
1648 }
1649 return 0;
1650}
1651
1652static void put_bitmap(QEMUFile *f, void *pv, size_t size)
1653{
1654 unsigned long *bmp = pv;
1655 int i, idx = 0;
1656 for (i = 0; i < BITS_TO_U64S(size); i++) {
1657 uint64_t w = bmp[idx++];
1658 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
1659 w |= ((uint64_t)bmp[idx++]) << 32;
1660 }
1661 qemu_put_be64(f, w);
1662 }
1663}
1664
1665const VMStateInfo vmstate_info_bitmap = {
1666 .name = "bitmap",
1667 .get = get_bitmap,
1668 .put = put_bitmap,
1669};
1670
1671typedef struct CompatEntry {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001672 char idstr[256];
1673 int instance_id;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001674} CompatEntry;
1675
1676typedef struct SaveStateEntry {
1677 QTAILQ_ENTRY(SaveStateEntry) entry;
1678 char idstr[256];
1679 int instance_id;
1680 int alias_id;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001681 int version_id;
1682 int section_id;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001683 SaveVMHandlers *ops;
1684 const VMStateDescription *vmsd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001685 void *opaque;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001686 CompatEntry *compat;
1687 int no_migrate;
1688 int is_ram;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001689} SaveStateEntry;
1690
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001691
1692static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
1693 QTAILQ_HEAD_INITIALIZER(savevm_handlers);
1694static int global_section_id;
1695
1696static int calculate_new_instance_id(const char *idstr)
1697{
1698 SaveStateEntry *se;
1699 int instance_id = 0;
1700
1701 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
1702 if (strcmp(idstr, se->idstr) == 0
1703 && instance_id <= se->instance_id) {
1704 instance_id = se->instance_id + 1;
1705 }
1706 }
1707 return instance_id;
1708}
1709
1710static int calculate_compat_instance_id(const char *idstr)
1711{
1712 SaveStateEntry *se;
1713 int instance_id = 0;
1714
1715 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
1716 if (!se->compat)
1717 continue;
1718
1719 if (strcmp(idstr, se->compat->idstr) == 0
1720 && instance_id <= se->compat->instance_id) {
1721 instance_id = se->compat->instance_id + 1;
1722 }
1723 }
1724 return instance_id;
1725}
1726
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001727/* TODO: Individual devices generally have very little idea about the rest
1728 of the system, so instance_id should be removed/replaced.
1729 Meanwhile pass -1 as instance_id if you do not already have a clearly
1730 distinguishing id for all instances of your device class. */
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001731int register_savevm_live(DeviceState *dev,
1732 const char *idstr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001733 int instance_id,
1734 int version_id,
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001735 SaveVMHandlers *ops,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001736 void *opaque)
1737{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001738 SaveStateEntry *se;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001739
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001740 se = g_malloc0(sizeof(SaveStateEntry));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001741 se->version_id = version_id;
1742 se->section_id = global_section_id++;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001743 se->ops = ops;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001744 se->opaque = opaque;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001745 se->vmsd = NULL;
1746 se->no_migrate = 0;
1747 /* if this is a live_savem then set is_ram */
1748 if (ops->save_live_state != NULL) {
1749 se->is_ram = 1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001750 }
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001751
1752 if (dev) {
1753 char *id = qdev_get_dev_path(dev);
1754 if (id) {
1755 pstrcpy(se->idstr, sizeof(se->idstr), id);
1756 pstrcat(se->idstr, sizeof(se->idstr), "/");
1757 g_free(id);
1758
1759 se->compat = g_malloc0(sizeof(CompatEntry));
1760 pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr);
1761 se->compat->instance_id = instance_id == -1 ?
1762 calculate_compat_instance_id(idstr) : instance_id;
1763 instance_id = -1;
1764 }
1765 }
1766 pstrcat(se->idstr, sizeof(se->idstr), idstr);
1767
1768 if (instance_id == -1) {
1769 se->instance_id = calculate_new_instance_id(se->idstr);
1770 } else {
1771 se->instance_id = instance_id;
1772 }
1773 assert(!se->compat || se->instance_id == 0);
1774 /* add at the end of list */
1775 QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001776 return 0;
1777}
1778
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001779int register_savevm(DeviceState *dev,
1780 const char *idstr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001781 int instance_id,
1782 int version_id,
1783 SaveStateHandler *save_state,
1784 LoadStateHandler *load_state,
1785 void *opaque)
1786{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001787 SaveVMHandlers *ops = g_malloc0(sizeof(SaveVMHandlers));
1788 ops->save_state = save_state;
1789 ops->load_state = load_state;
1790 return register_savevm_live(dev, idstr, instance_id, version_id,
1791 ops, opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001792}
1793
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001794void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001795{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001796 SaveStateEntry *se, *new_se;
1797 char id[256] = "";
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001798
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001799 if (dev) {
1800 char *path = qdev_get_dev_path(dev);
1801 if (path) {
1802 pstrcpy(id, sizeof(id), path);
1803 pstrcat(id, sizeof(id), "/");
1804 g_free(path);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001805 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001806 }
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001807 pstrcat(id, sizeof(id), idstr);
1808
1809 QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
1810 if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
1811 QTAILQ_REMOVE(&savevm_handlers, se, entry);
1812 if (se->compat) {
1813 g_free(se->compat);
1814 }
1815 g_free(se->ops);
1816 g_free(se);
1817 }
1818 }
1819}
1820
1821int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
1822 const VMStateDescription *vmsd,
1823 void *opaque, int alias_id,
1824 int required_for_version)
1825{
1826 SaveStateEntry *se;
1827
1828 /* If this triggers, alias support can be dropped for the vmsd. */
1829 assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
1830
1831 se = g_malloc0(sizeof(SaveStateEntry));
1832 se->version_id = vmsd->version_id;
1833 se->section_id = global_section_id++;
1834 se->opaque = opaque;
1835 se->vmsd = vmsd;
1836 se->alias_id = alias_id;
1837 se->no_migrate = vmsd->unmigratable;
1838
1839 if (dev) {
1840 char *id = qdev_get_dev_path(dev);
1841 if (id) {
1842 pstrcpy(se->idstr, sizeof(se->idstr), id);
1843 pstrcat(se->idstr, sizeof(se->idstr), "/");
1844 g_free(id);
1845
1846 se->compat = g_malloc0(sizeof(CompatEntry));
1847 pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
1848 se->compat->instance_id = instance_id == -1 ?
1849 calculate_compat_instance_id(vmsd->name) : instance_id;
1850 instance_id = -1;
1851 }
1852 }
1853 pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
1854
1855 if (instance_id == -1) {
1856 se->instance_id = calculate_new_instance_id(se->idstr);
1857 } else {
1858 se->instance_id = instance_id;
1859 }
1860 assert(!se->compat || se->instance_id == 0);
1861 /* add at the end of list */
1862 QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
1863 return 0;
1864}
1865
1866void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
1867 void *opaque)
1868{
1869 SaveStateEntry *se, *new_se;
1870
1871 QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
1872 if (se->vmsd == vmsd && se->opaque == opaque) {
1873 QTAILQ_REMOVE(&savevm_handlers, se, entry);
1874 if (se->compat) {
1875 g_free(se->compat);
1876 }
1877 g_free(se);
1878 }
1879 }
1880}
1881
1882static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
1883 void *opaque);
1884static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
1885 void *opaque);
1886
1887int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
1888 void *opaque, int version_id)
1889{
1890 VMStateField *field = vmsd->fields;
1891 int ret;
1892
1893 if (version_id > vmsd->version_id) {
1894 return -EINVAL;
1895 }
1896 if (version_id < vmsd->minimum_version_id_old) {
1897 return -EINVAL;
1898 }
1899 if (version_id < vmsd->minimum_version_id) {
1900 return vmsd->load_state_old(f, opaque, version_id);
1901 }
1902 if (vmsd->pre_load) {
1903 int ret = vmsd->pre_load(opaque);
1904 if (ret)
1905 return ret;
1906 }
1907 while(field->name) {
1908 if ((field->field_exists &&
1909 field->field_exists(opaque, version_id)) ||
1910 (!field->field_exists &&
1911 field->version_id <= version_id)) {
1912 void *base_addr = opaque + field->offset;
1913 int i, n_elems = 1;
1914 int size = field->size;
1915
1916 if (field->flags & VMS_VBUFFER) {
1917 size = *(int32_t *)(opaque+field->size_offset);
1918 if (field->flags & VMS_MULTIPLY) {
1919 size *= field->size;
1920 }
1921 }
1922 if (field->flags & VMS_ARRAY) {
1923 n_elems = field->num;
1924 } else if (field->flags & VMS_VARRAY_INT32) {
1925 n_elems = *(int32_t *)(opaque+field->num_offset);
1926 } else if (field->flags & VMS_VARRAY_UINT32) {
1927 n_elems = *(uint32_t *)(opaque+field->num_offset);
1928 } else if (field->flags & VMS_VARRAY_UINT16) {
1929 n_elems = *(uint16_t *)(opaque+field->num_offset);
1930 } else if (field->flags & VMS_VARRAY_UINT8) {
1931 n_elems = *(uint8_t *)(opaque+field->num_offset);
1932 }
1933 if (field->flags & VMS_POINTER) {
1934 base_addr = *(void **)base_addr + field->start;
1935 }
1936 for (i = 0; i < n_elems; i++) {
1937 void *addr = base_addr + size * i;
1938
1939 if (field->flags & VMS_ARRAY_OF_POINTER) {
1940 addr = *(void **)addr;
1941 }
1942 if (field->flags & VMS_STRUCT) {
1943 ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
1944 } else {
1945 ret = field->info->get(f, addr, size);
1946
1947 }
1948 if (ret < 0) {
1949 return ret;
1950 }
1951 }
1952 }
1953 field++;
1954 }
1955 ret = vmstate_subsection_load(f, vmsd, opaque);
1956 if (ret != 0) {
1957 return ret;
1958 }
1959 if (vmsd->post_load) {
1960 return vmsd->post_load(opaque, version_id);
1961 }
1962 return 0;
1963}
1964
1965void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
1966 void *opaque)
1967{
1968 VMStateField *field = vmsd->fields;
1969
1970 if (vmsd->pre_save) {
1971 vmsd->pre_save(opaque);
1972 }
1973 while(field->name) {
1974 if (!field->field_exists ||
1975 field->field_exists(opaque, vmsd->version_id)) {
1976 void *base_addr = opaque + field->offset;
1977 int i, n_elems = 1;
1978 int size = field->size;
1979
1980 if (field->flags & VMS_VBUFFER) {
1981 size = *(int32_t *)(opaque+field->size_offset);
1982 if (field->flags & VMS_MULTIPLY) {
1983 size *= field->size;
1984 }
1985 }
1986 if (field->flags & VMS_ARRAY) {
1987 n_elems = field->num;
1988 } else if (field->flags & VMS_VARRAY_INT32) {
1989 n_elems = *(int32_t *)(opaque+field->num_offset);
1990 } else if (field->flags & VMS_VARRAY_UINT32) {
1991 n_elems = *(uint32_t *)(opaque+field->num_offset);
1992 } else if (field->flags & VMS_VARRAY_UINT16) {
1993 n_elems = *(uint16_t *)(opaque+field->num_offset);
1994 } else if (field->flags & VMS_VARRAY_UINT8) {
1995 n_elems = *(uint8_t *)(opaque+field->num_offset);
1996 }
1997 if (field->flags & VMS_POINTER) {
1998 base_addr = *(void **)base_addr + field->start;
1999 }
2000 for (i = 0; i < n_elems; i++) {
2001 void *addr = base_addr + size * i;
2002
2003 if (field->flags & VMS_ARRAY_OF_POINTER) {
2004 addr = *(void **)addr;
2005 }
2006 if (field->flags & VMS_STRUCT) {
2007 vmstate_save_state(f, field->vmsd, addr);
2008 } else {
2009 field->info->put(f, addr, size);
2010 }
2011 }
2012 }
2013 field++;
2014 }
2015 vmstate_subsection_save(f, vmsd, opaque);
2016}
2017
2018static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
2019{
2020 if (!se->vmsd) { /* Old style */
2021 return se->ops->load_state(f, se->opaque, version_id);
2022 }
2023 return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
2024}
2025
2026static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
2027{
2028 if (!se->vmsd) { /* Old style */
2029 se->ops->save_state(f, se->opaque);
2030 return;
2031 }
2032 vmstate_save_state(f,se->vmsd, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002033}
2034
2035#define QEMU_VM_FILE_MAGIC 0x5145564d
2036#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002037#define QEMU_VM_FILE_VERSION 0x00000004
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002038
2039#define QEMU_VM_EOF 0x00
2040#define QEMU_VM_SECTION_START 0x01
2041#define QEMU_VM_SECTION_PART 0x02
2042#define QEMU_VM_SECTION_END 0x03
2043#define QEMU_VM_SECTION_FULL 0x04
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002044#define QEMU_VM_SUBSECTION 0x05
2045
2046bool qemu_savevm_state_blocked(Error **errp)
2047{
2048 SaveStateEntry *se;
2049
2050 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
2051 if (se->no_migrate) {
2052 error_set(errp, QERR_MIGRATION_NOT_SUPPORTED, se->idstr);
2053 return true;
2054 }
2055 }
2056 return false;
2057}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002058
2059int qemu_savevm_state_begin(QEMUFile *f)
2060{
2061 SaveStateEntry *se;
2062
2063 qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
2064 qemu_put_be32(f, QEMU_VM_FILE_VERSION);
2065
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002066 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002067 int len;
2068
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002069 if (!se->ops || !se->ops->save_live_state) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002070 continue;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002071 }
2072#if 0
2073 if (se->ops && se->ops->is_active) {
2074 if (!se->ops->is_active(se->opaque)) {
2075 continue;
2076 }
2077 }
2078#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002079 /* Section type */
2080 qemu_put_byte(f, QEMU_VM_SECTION_START);
2081 qemu_put_be32(f, se->section_id);
2082
2083 /* ID string */
2084 len = strlen(se->idstr);
2085 qemu_put_byte(f, len);
2086 qemu_put_buffer(f, (uint8_t *)se->idstr, len);
2087
2088 qemu_put_be32(f, se->instance_id);
2089 qemu_put_be32(f, se->version_id);
2090
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002091 se->ops->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002092 }
2093
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002094 return qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002095}
2096
2097int qemu_savevm_state_iterate(QEMUFile *f)
2098{
2099 SaveStateEntry *se;
2100 int ret = 1;
2101
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002102 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
2103 if (!se->ops || !se->ops->save_live_state) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002104 continue;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002105 }
2106#if 0
2107 if (se->ops && se->ops->is_active) {
2108 if (!se->ops->is_active(se->opaque)) {
2109 continue;
2110 }
2111 }
2112#endif
2113 if (qemu_file_rate_limit(f)) {
2114 return 0;
2115 }
2116 //trace_savevm_section_start();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002117 /* Section type */
2118 qemu_put_byte(f, QEMU_VM_SECTION_PART);
2119 qemu_put_be32(f, se->section_id);
2120
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002121 ret &= !!se->ops->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002122 }
2123
2124 if (ret)
2125 return 1;
2126
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002127 return qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002128}
2129
2130int qemu_savevm_state_complete(QEMUFile *f)
2131{
2132 SaveStateEntry *se;
2133
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002134 // cpu_synchronize_all_states();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002135
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002136 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
2137 if (!se->ops || se->ops->save_live_state == NULL) {
2138 continue;
2139 }
2140#if 0
2141 if (se->ops && se->ops->is_active) {
2142 if (!se->ops->is_active(se->opaque)) {
2143 continue;
2144 }
2145 }
2146#endif
2147 //trace_savevm_section_start();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002148 /* Section type */
2149 qemu_put_byte(f, QEMU_VM_SECTION_END);
2150 qemu_put_be32(f, se->section_id);
2151
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002152 se->ops->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002153 }
2154
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002155 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002156 int len;
2157
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002158 if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002159 continue;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002160 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002161
2162 /* Section type */
2163 qemu_put_byte(f, QEMU_VM_SECTION_FULL);
2164 qemu_put_be32(f, se->section_id);
2165
2166 /* ID string */
2167 len = strlen(se->idstr);
2168 qemu_put_byte(f, len);
2169 qemu_put_buffer(f, (uint8_t *)se->idstr, len);
2170
2171 qemu_put_be32(f, se->instance_id);
2172 qemu_put_be32(f, se->version_id);
2173
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002174 vmstate_save(f, se);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002175 }
2176
2177 qemu_put_byte(f, QEMU_VM_EOF);
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002178 qemu_fflush(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002179
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002180 return qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002181}
2182
2183int qemu_savevm_state(QEMUFile *f)
2184{
2185 int saved_vm_running;
2186 int ret;
2187
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002188 if (qemu_savevm_state_blocked(NULL)) {
2189 return -EINVAL;
2190 }
2191
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002192 saved_vm_running = vm_running;
2193 vm_stop(0);
2194
2195 bdrv_flush_all();
2196
2197 ret = qemu_savevm_state_begin(f);
2198 if (ret < 0)
2199 goto out;
2200
2201 do {
2202 ret = qemu_savevm_state_iterate(f);
2203 if (ret < 0)
2204 goto out;
2205 } while (ret == 0);
2206
2207 ret = qemu_savevm_state_complete(f);
2208
2209out:
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002210 ret = qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002211
2212 if (!ret && saved_vm_running)
2213 vm_start();
2214
2215 return ret;
2216}
2217
2218static SaveStateEntry *find_se(const char *idstr, int instance_id)
2219{
2220 SaveStateEntry *se;
2221
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002222 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002223 if (!strcmp(se->idstr, idstr) &&
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002224 (instance_id == se->instance_id ||
2225 instance_id == se->alias_id))
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002226 return se;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002227 /* Migrating from an older version? */
2228 if (strstr(se->idstr, idstr) && se->compat) {
2229 if (!strcmp(se->compat->idstr, idstr) &&
2230 (instance_id == se->compat->instance_id ||
2231 instance_id == se->alias_id))
2232 return se;
2233 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002234 }
2235 return NULL;
2236}
2237
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002238static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection *sub, char *idstr)
2239{
2240 while(sub && sub->needed) {
2241 if (strcmp(idstr, sub->vmsd->name) == 0) {
2242 return sub->vmsd;
2243 }
2244 sub++;
2245 }
2246 return NULL;
2247}
2248
2249static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
2250 void *opaque)
2251{
2252 while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
2253 char idstr[256];
2254 int ret;
2255 uint8_t version_id, len, size;
2256 const VMStateDescription *sub_vmsd;
2257
2258 len = qemu_peek_byte(f, 1);
2259 if (len < strlen(vmsd->name) + 1) {
2260 /* subsection name has be be "section_name/a" */
2261 return 0;
2262 }
2263 size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
2264 if (size != len) {
2265 return 0;
2266 }
2267 idstr[size] = 0;
2268
2269 if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
2270 /* it don't have a valid subsection name */
2271 return 0;
2272 }
2273 sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
2274 if (sub_vmsd == NULL) {
2275 return -ENOENT;
2276 }
2277 qemu_file_skip(f, 1); /* subsection */
2278 qemu_file_skip(f, 1); /* len */
2279 qemu_file_skip(f, len); /* idstr */
2280 version_id = qemu_get_be32(f);
2281
2282 ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
2283 if (ret) {
2284 return ret;
2285 }
2286 }
2287 return 0;
2288}
2289
2290static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
2291 void *opaque)
2292{
2293 const VMStateSubsection *sub = vmsd->subsections;
2294
2295 while (sub && sub->needed) {
2296 if (sub->needed(opaque)) {
2297 const VMStateDescription *vmsd = sub->vmsd;
2298 uint8_t len;
2299
2300 qemu_put_byte(f, QEMU_VM_SUBSECTION);
2301 len = strlen(vmsd->name);
2302 qemu_put_byte(f, len);
2303 qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
2304 qemu_put_be32(f, vmsd->version_id);
2305 vmstate_save_state(f, vmsd, opaque);
2306 }
2307 sub++;
2308 }
2309}
2310
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002311typedef struct LoadStateEntry {
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002312 QLIST_ENTRY(LoadStateEntry) entry;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002313 SaveStateEntry *se;
2314 int section_id;
2315 int version_id;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002316} LoadStateEntry;
2317
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002318int qemu_loadvm_state(QEMUFile *f)
2319{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002320 QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
2321 QLIST_HEAD_INITIALIZER(loadvm_handlers);
2322 LoadStateEntry *le, *new_le;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002323 uint8_t section_type;
2324 unsigned int v;
2325 int ret;
2326
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002327 if (qemu_savevm_state_blocked(NULL)) {
2328 return -EINVAL;
2329 }
2330
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002331 v = qemu_get_be32(f);
2332 if (v != QEMU_VM_FILE_MAGIC)
2333 return -EINVAL;
2334
2335 v = qemu_get_be32(f);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002336 if (v < QEMU_VM_FILE_VERSION) {
2337 fprintf(stderr, "Snapshot format %d is too old for this version of the emulator, please create a new one.\n", v);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002338 return -ENOTSUP;
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002339 } else if (v > QEMU_VM_FILE_VERSION) {
2340 fprintf(stderr, "Snapshot format %d is more recent than the emulator, please update your Android SDK Tools.\n", v);
2341 return -ENOTSUP;
2342 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002343
2344 while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
2345 uint32_t instance_id, version_id, section_id;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002346 SaveStateEntry *se;
2347 char idstr[257];
2348 int len;
2349
2350 switch (section_type) {
2351 case QEMU_VM_SECTION_START:
2352 case QEMU_VM_SECTION_FULL:
2353 /* Read section start */
2354 section_id = qemu_get_be32(f);
2355 len = qemu_get_byte(f);
2356 qemu_get_buffer(f, (uint8_t *)idstr, len);
2357 idstr[len] = 0;
2358 instance_id = qemu_get_be32(f);
2359 version_id = qemu_get_be32(f);
2360
2361 /* Find savevm section */
2362 se = find_se(idstr, instance_id);
2363 if (se == NULL) {
2364 fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
2365 ret = -EINVAL;
2366 goto out;
2367 }
2368
2369 /* Validate version */
2370 if (version_id > se->version_id) {
2371 fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
2372 version_id, idstr, se->version_id);
2373 ret = -EINVAL;
2374 goto out;
2375 }
2376
2377 /* Add entry */
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002378 le = g_malloc0(sizeof(*le));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002379
2380 le->se = se;
2381 le->section_id = section_id;
2382 le->version_id = version_id;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002383 QLIST_INSERT_HEAD(&loadvm_handlers, le, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002384
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002385 ret = vmstate_load(f, le->se, le->version_id);
2386 if (ret < 0) {
2387 fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
2388 instance_id, idstr);
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -07002389 goto out;
2390 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002391 break;
2392 case QEMU_VM_SECTION_PART:
2393 case QEMU_VM_SECTION_END:
2394 section_id = qemu_get_be32(f);
2395
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002396 QLIST_FOREACH(le, &loadvm_handlers, entry) {
2397 if (le->section_id == section_id) {
2398 break;
2399 }
2400 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002401 if (le == NULL) {
2402 fprintf(stderr, "Unknown savevm section %d\n", section_id);
2403 ret = -EINVAL;
2404 goto out;
2405 }
2406
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002407 ret = vmstate_load(f, le->se, le->version_id);
2408 if (ret < 0) {
2409 fprintf(stderr, "qemu: warning: error while loading state section id %d\n",
2410 section_id);
2411 goto out;
2412 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002413 break;
2414 default:
2415 fprintf(stderr, "Unknown savevm section type %d\n", section_type);
2416 ret = -EINVAL;
2417 goto out;
2418 }
2419 }
2420
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002421 //cpu_synchronize_all_post_init();
2422
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002423 ret = 0;
2424
2425out:
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002426 QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
2427 QLIST_REMOVE(le, entry);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002428 g_free(le);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002429 }
2430
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002431 if (ret == 0) {
2432 ret = qemu_file_get_error(f);
2433 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002434
2435 return ret;
2436}
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002437#if 0
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002438static BlockDriverState *get_bs_snapshots(void)
2439{
2440 BlockDriverState *bs;
2441 int i;
2442
2443 if (bs_snapshots)
2444 return bs_snapshots;
2445 for(i = 0; i <= nb_drives; i++) {
2446 bs = drives_table[i].bdrv;
2447 if (bdrv_can_snapshot(bs))
2448 goto ok;
2449 }
2450 return NULL;
2451 ok:
2452 bs_snapshots = bs;
2453 return bs;
2454}
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002455#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002456static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
2457 const char *name)
2458{
2459 QEMUSnapshotInfo *sn_tab, *sn;
2460 int nb_sns, i, ret;
2461
2462 ret = -ENOENT;
2463 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
2464 if (nb_sns < 0)
2465 return ret;
2466 for(i = 0; i < nb_sns; i++) {
2467 sn = &sn_tab[i];
2468 if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
2469 *sn_info = *sn;
2470 ret = 0;
2471 break;
2472 }
2473 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002474 g_free(sn_tab);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002475 return ret;
2476}
2477
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002478void do_savevm(Monitor *err, const char *name)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002479{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002480 BlockDriverState *bs, *bs1;
2481 QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002482 int must_delete, ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002483 BlockDriverInfo bdi1, *bdi = &bdi1;
2484 QEMUFile *f;
2485 int saved_vm_running;
2486 uint32_t vm_state_size;
2487#ifdef _WIN32
2488 struct _timeb tb;
2489#else
2490 struct timeval tv;
2491#endif
2492
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002493 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002494 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002495 monitor_printf(err, "No block device can accept snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002496 return;
2497 }
2498
2499 /* ??? Should this occur after vm_stop? */
2500 qemu_aio_flush();
2501
2502 saved_vm_running = vm_running;
2503 vm_stop(0);
2504
2505 must_delete = 0;
2506 if (name) {
2507 ret = bdrv_snapshot_find(bs, old_sn, name);
2508 if (ret >= 0) {
2509 must_delete = 1;
2510 }
2511 }
2512 memset(sn, 0, sizeof(*sn));
2513 if (must_delete) {
2514 pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
2515 pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
2516 } else {
2517 if (name)
2518 pstrcpy(sn->name, sizeof(sn->name), name);
2519 }
2520
2521 /* fill auxiliary fields */
2522#ifdef _WIN32
2523 _ftime(&tb);
2524 sn->date_sec = tb.time;
2525 sn->date_nsec = tb.millitm * 1000000;
2526#else
2527 gettimeofday(&tv, NULL);
2528 sn->date_sec = tv.tv_sec;
2529 sn->date_nsec = tv.tv_usec * 1000;
2530#endif
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +01002531 sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002532
2533 if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002534 monitor_printf(err, "Device %s does not support VM state snapshots\n",
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002535 bdrv_get_device_name(bs));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002536 goto the_end;
2537 }
2538
2539 /* save the VM state */
David 'Digit' Turner986acc92011-05-10 16:50:01 +02002540 f = qemu_fopen_bdrv(bs, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002541 if (!f) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002542 monitor_printf(err, "Could not open VM state file\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002543 goto the_end;
2544 }
2545 ret = qemu_savevm_state(f);
2546 vm_state_size = qemu_ftell(f);
2547 qemu_fclose(f);
2548 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002549 monitor_printf(err, "Error %d while writing VM\n", ret);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002550 goto the_end;
2551 }
2552
2553 /* create the snapshots */
2554
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002555 bs1 = NULL;
2556 while ((bs1 = bdrv_next(bs1))) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002557 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002558 if (must_delete) {
2559 ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
2560 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002561 monitor_printf(err,
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002562 "Error while deleting snapshot on '%s'\n",
2563 bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002564 }
2565 }
2566 /* Write VM state size only to the image that contains the state */
2567 sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
2568 ret = bdrv_snapshot_create(bs1, sn);
2569 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002570 monitor_printf(err, "Error while creating snapshot on '%s'\n",
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002571 bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002572 }
2573 }
2574 }
2575
2576 the_end:
2577 if (saved_vm_running)
2578 vm_start();
2579}
2580
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002581void do_loadvm(Monitor *err, const char *name)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002582{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002583 BlockDriverState *bs, *bs1;
2584 BlockDriverInfo bdi1, *bdi = &bdi1;
2585 QEMUSnapshotInfo sn;
2586 QEMUFile *f;
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002587 int ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002588 int saved_vm_running;
2589
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002590 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002591 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002592 monitor_printf(err, "No block device supports snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002593 return;
2594 }
2595
2596 /* Flush all IO requests so they don't interfere with the new state. */
2597 qemu_aio_flush();
2598
2599 saved_vm_running = vm_running;
2600 vm_stop(0);
2601
Vladimir Chtchetkine05e07482012-02-03 10:02:50 -08002602 bs1 = bs;
2603 do {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002604 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002605 ret = bdrv_snapshot_goto(bs1, name);
2606 if (ret < 0) {
2607 if (bs != bs1)
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002608 monitor_printf(err, "Warning: ");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002609 switch(ret) {
2610 case -ENOTSUP:
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002611 monitor_printf(err,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002612 "Snapshots not supported on device '%s'\n",
2613 bdrv_get_device_name(bs1));
2614 break;
2615 case -ENOENT:
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002616 monitor_printf(err, "Could not find snapshot '%s' on "
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002617 "device '%s'\n",
2618 name, bdrv_get_device_name(bs1));
2619 break;
2620 default:
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002621 monitor_printf(err, "Error %d while activating snapshot on"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002622 " '%s'\n", ret, bdrv_get_device_name(bs1));
2623 break;
2624 }
2625 /* fatal on snapshot block device */
2626 if (bs == bs1)
2627 goto the_end;
2628 }
2629 }
Vladimir Chtchetkine05e07482012-02-03 10:02:50 -08002630 } while ((bs1 = bdrv_next(bs)));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002631
2632 if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002633 monitor_printf(err, "Device %s does not support VM state snapshots\n",
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002634 bdrv_get_device_name(bs));
2635 return;
2636 }
2637
2638 /* Don't even try to load empty VM states */
2639 ret = bdrv_snapshot_find(bs, &sn, name);
2640 if ((ret >= 0) && (sn.vm_state_size == 0))
2641 goto the_end;
2642
2643 /* restore the VM state */
David 'Digit' Turner986acc92011-05-10 16:50:01 +02002644 f = qemu_fopen_bdrv(bs, 0);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002645 if (!f) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002646 monitor_printf(err, "Could not open VM state file\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002647 goto the_end;
2648 }
2649 ret = qemu_loadvm_state(f);
2650 qemu_fclose(f);
2651 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002652 monitor_printf(err, "Error %d while loading VM state\n", ret);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002653 }
2654 the_end:
2655 if (saved_vm_running)
2656 vm_start();
2657}
2658
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002659void do_delvm(Monitor *err, const char *name)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002660{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002661 BlockDriverState *bs, *bs1;
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002662 int ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002663
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002664 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002665 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002666 monitor_printf(err, "No block device supports snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002667 return;
2668 }
2669
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002670 bs1 = NULL;
2671 while ((bs1 = bdrv_next(bs1))) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002672 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002673 ret = bdrv_snapshot_delete(bs1, name);
2674 if (ret < 0) {
2675 if (ret == -ENOTSUP)
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002676 monitor_printf(err,
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002677 "Snapshots not supported on device '%s'\n",
2678 bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002679 else
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002680 monitor_printf(err, "Error %d while deleting snapshot on "
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002681 "'%s'\n", ret, bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002682 }
2683 }
2684 }
2685}
2686
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002687void do_info_snapshots(Monitor* out, Monitor* err)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002688{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002689 BlockDriverState *bs, *bs1;
2690 QEMUSnapshotInfo *sn_tab, *sn;
2691 int nb_sns, i;
2692 char buf[256];
2693
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002694 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002695 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002696 monitor_printf(err, "No available block device supports snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002697 return;
2698 }
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002699 monitor_printf(out, "Snapshot devices:");
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002700 bs1 = NULL;
2701 while ((bs1 = bdrv_next(bs1))) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002702 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002703 if (bs == bs1)
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002704 monitor_printf(out, " %s", bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002705 }
2706 }
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002707 monitor_printf(out, "\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002708
2709 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
2710 if (nb_sns < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002711 monitor_printf(err, "bdrv_snapshot_list: error %d\n", nb_sns);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002712 return;
2713 }
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002714 monitor_printf(out, "Snapshot list (from %s):\n",
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002715 bdrv_get_device_name(bs));
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002716 monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002717 for(i = 0; i < nb_sns; i++) {
2718 sn = &sn_tab[i];
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002719 monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002720 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002721 g_free(sn_tab);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002722}