blob: b5a41671296b996d512db0c482dc854e93b65f56 [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' Turnercc330d42013-12-14 23:26:42 +010075#include "net/net.h"
David 'Digit' Turner6af67652013-12-14 23:49:32 +010076#include "monitor/monitor.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010077#include "sysemu/sysemu.h"
David 'Digit' Turnere7216d82013-12-15 00:51:13 +010078#include "sysemu/char.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010079#include "sysemu/blockdev.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010080#include "block/block.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070081#include "audio/audio.h"
David 'Digit' Turner28a09b62013-12-15 00:16:00 +010082#include "migration/migration.h"
David 'Digit' Turner28a09b62013-12-15 00:16:00 +010083#include "migration/qemu-file.h"
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +010084#include "migration/vmstate.h"
85#include "qemu/bitmap.h"
86#include "qemu/iov.h"
87#include "qemu/sockets.h"
88#include "qemu/timer.h"
89#include "qemu/queue.h"
Tim Baverstock622b8f42010-12-07 11:36:59 +000090#include "android/snapshot.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070091
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070092
93#define SELF_ANNOUNCE_ROUNDS 5
David 'Digit' Turner986acc92011-05-10 16:50:01 +020094
95#ifndef ETH_P_RARP
96#define ETH_P_RARP 0x8035
97#endif
98#define ARP_HTYPE_ETH 0x0001
99#define ARP_PTYPE_IP 0x0800
100#define ARP_OP_REQUEST_REV 0x3
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700101
David 'Digit' Turner5973c772011-05-10 07:06:00 +0200102static int announce_self_create(uint8_t *buf,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700103 uint8_t *mac_addr)
104{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200105 /* Ethernet header. */
106 memset(buf, 0xff, 6); /* destination MAC addr */
107 memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
108 *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700109
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200110 /* RARP header. */
111 *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
112 *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
113 *(buf + 18) = 6; /* hardware addr length (ethernet) */
114 *(buf + 19) = 4; /* protocol addr length (IPv4) */
115 *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
116 memcpy(buf + 22, mac_addr, 6); /* source hw addr */
117 memset(buf + 28, 0x00, 4); /* source protocol addr */
118 memcpy(buf + 32, mac_addr, 6); /* target hw addr */
119 memset(buf + 38, 0x00, 4); /* target protocol addr */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700120
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200121 /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
122 memset(buf + 42, 0x00, 18);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700123
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200124 return 60; /* len (FCS will be added by hardware) */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700125}
126
127static void qemu_announce_self_once(void *opaque)
128{
129 int i, len;
130 VLANState *vlan;
131 VLANClientState *vc;
132 uint8_t buf[256];
133 static int count = SELF_ANNOUNCE_ROUNDS;
134 QEMUTimer *timer = *(QEMUTimer **)opaque;
135
136 for (i = 0; i < MAX_NICS; i++) {
137 if (!nd_table[i].used)
138 continue;
139 len = announce_self_create(buf, nd_table[i].macaddr);
140 vlan = nd_table[i].vlan;
141 for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
142 vc->receive(vc, buf, len);
143 }
144 }
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200145 if (--count) {
146 /* delay 50ms, 150ms, 250ms, ... */
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100147 timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200148 50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700149 } else {
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100150 timer_del(timer);
151 timer_free(timer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700152 }
153}
154
155void qemu_announce_self(void)
156{
157 static QEMUTimer *timer;
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100158 timer = timer_new_ms(QEMU_CLOCK_REALTIME, qemu_announce_self_once, &timer);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700159 qemu_announce_self_once(&timer);
160}
161
162/***********************************************************/
163/* savevm/loadvm support */
164
David 'Digit' Turner1365eb22014-02-16 22:23:26 +0100165void yield_until_fd_readable(int fd);
166
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700167#define IO_BUF_SIZE 32768
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100168#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700169
170struct QEMUFile {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100171 const QEMUFileOps *ops;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700172 void *opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700173
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100174 int64_t bytes_xfer;
175 int64_t xfer_limit;
176
177 int64_t pos; /* start of buffer when writing, end of buffer
178 when reading */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700179 int buf_index;
180 int buf_size; /* 0 when writing */
181 uint8_t buf[IO_BUF_SIZE];
182
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100183 struct iovec iov[MAX_IOV_SIZE];
184 unsigned int iovcnt;
185
186 int last_error;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700187};
188
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200189typedef struct QEMUFileStdio
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700190{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200191 FILE *stdio_file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700192 QEMUFile *file;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200193} QEMUFileStdio;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700194
195typedef struct QEMUFileSocket
196{
197 int fd;
198 QEMUFile *file;
199} QEMUFileSocket;
200
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100201static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
202 int64_t pos)
203{
204 QEMUFileSocket *s = opaque;
205 ssize_t len;
206 ssize_t size = iov_size(iov, iovcnt);
207
208 len = iov_send(s->fd, iov, iovcnt, 0, size);
209 if (len < size) {
210 len = -socket_error();
211 }
212 return len;
213}
214
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100215static int socket_get_fd(void *opaque)
216{
217 QEMUFileSocket *s = opaque;
218
219 return s->fd;
220}
221
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200222static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700223{
224 QEMUFileSocket *s = opaque;
225 ssize_t len;
226
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100227 for (;;) {
228 len = qemu_recv(s->fd, buf, size, 0);
229 if (len != -1) {
230 break;
231 }
232#ifndef CONFIG_ANDROID
233 if (socket_error() == EAGAIN) {
234 yield_until_fd_readable(s->fd);
235 } else if (socket_error() != EINTR) {
236 break;
237 }
238#else
239 if (socket_error() != EINTR)
240 break;
241#endif
242 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700243
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100244 if (len == -1) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700245 len = -socket_error();
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100246 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700247 return len;
248}
249
250static int file_socket_close(void *opaque)
251{
252 QEMUFileSocket *s = opaque;
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100253 if (s->fd >= 0)
254 socket_close(s->fd);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100255 g_free(s);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700256 return 0;
257}
258
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100259static int stdio_get_fd(void *opaque)
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100260{
261 QEMUFileStdio *s = opaque;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100262
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100263 return fileno(s->stdio_file);
264}
265
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200266static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700267{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200268 QEMUFileStdio *s = opaque;
269 return fwrite(buf, 1, size, s->stdio_file);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700270}
271
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200272static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700273{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200274 QEMUFileStdio *s = opaque;
275 FILE *fp = s->stdio_file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700276 int bytes;
277
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100278 for (;;) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700279 clearerr(fp);
280 bytes = fread(buf, 1, size, fp);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100281 if (bytes != 0 || !ferror(fp)) {
282 break;
283 }
284#ifndef CONFIG_ANDROID
285 if (errno == EAGAIN) {
286 yield_until_fd_readable(fileno(fp));
287 } else if (errno != EINTR) {
288 break;
289 }
290#else
291 if (errno != EINTR)
292 break;
293#endif
294 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700295 return bytes;
296}
297
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200298static int stdio_pclose(void *opaque)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700299{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200300 QEMUFileStdio *s = opaque;
301 int ret;
302 ret = pclose(s->stdio_file);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100303 if (ret == -1) {
304 ret = -errno;
305 } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
306 /* close succeeded, but non-zero exit code: */
307 ret = -EIO; /* fake errno value */
308 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100309 g_free(s);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200310 return ret;
311}
312
313static int stdio_fclose(void *opaque)
314{
315 QEMUFileStdio *s = opaque;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100316 int ret = 0;
317
318 if (s->file->ops->put_buffer || s->file->ops->writev_buffer) {
319 int fd = fileno(s->stdio_file);
320 struct stat st;
321
322 ret = fstat(fd, &st);
323 if (ret == 0 && S_ISREG(st.st_mode)) {
324 /*
325 * If the file handle is a regular file make sure the
326 * data is flushed to disk before signaling success.
327 */
328 ret = fsync(fd);
329 if (ret != 0) {
330 ret = -errno;
331 return ret;
332 }
333 }
334 }
335 if (fclose(s->stdio_file) == EOF) {
336 ret = -errno;
337 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100338 g_free(s);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100339 return ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700340}
341
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100342static const QEMUFileOps stdio_pipe_read_ops = {
343 .get_fd = stdio_get_fd,
344 .get_buffer = stdio_get_buffer,
345 .close = stdio_pclose
346};
347
348static const QEMUFileOps stdio_pipe_write_ops = {
349 .get_fd = stdio_get_fd,
350 .put_buffer = stdio_put_buffer,
351 .close = stdio_pclose
352};
353
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100354QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700355{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100356 FILE *stdio_file;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200357 QEMUFileStdio *s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700358
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100359 if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700360 fprintf(stderr, "qemu_popen: Argument validity check failed\n");
361 return NULL;
362 }
363
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100364 stdio_file = popen(command, mode);
365 if (stdio_file == NULL) {
366 return NULL;
367 }
368
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100369 s = g_malloc0(sizeof(QEMUFileStdio));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700370
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200371 s->stdio_file = stdio_file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700372
373 if(mode[0] == 'r') {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100374 s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700375 } else {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100376 s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700377 }
378 return s->file;
379}
380
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100381static const QEMUFileOps stdio_file_read_ops = {
382 .get_fd = stdio_get_fd,
383 .get_buffer = stdio_get_buffer,
384 .close = stdio_fclose
385};
386
387static const QEMUFileOps stdio_file_write_ops = {
388 .get_fd = stdio_get_fd,
389 .put_buffer = stdio_put_buffer,
390 .close = stdio_fclose
391};
392
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100393static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
394 int64_t pos)
395{
396 QEMUFileSocket *s = opaque;
397 ssize_t len, offset;
398 ssize_t size = iov_size(iov, iovcnt);
399 ssize_t total = 0;
400
401 assert(iovcnt > 0);
402 offset = 0;
403 while (size > 0) {
404 /* Find the next start position; skip all full-sized vector elements */
405 while (offset >= iov[0].iov_len) {
406 offset -= iov[0].iov_len;
407 iov++, iovcnt--;
408 }
409
410 /* skip `offset' bytes from the (now) first element, undo it on exit */
411 assert(iovcnt > 0);
412 iov[0].iov_base += offset;
413 iov[0].iov_len -= offset;
414
415 do {
416 len = writev(s->fd, iov, iovcnt);
417 } while (len == -1 && errno == EINTR);
418 if (len == -1) {
419 return -errno;
420 }
421
422 /* Undo the changes above */
423 iov[0].iov_base -= offset;
424 iov[0].iov_len += offset;
425
426 /* Prepare for the next iteration */
427 offset += len;
428 total += len;
429 size -= len;
430 }
431
432 return total;
433}
434
435static int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
436{
437 QEMUFileSocket *s = opaque;
438 ssize_t len;
439
440 for (;;) {
441 len = read(s->fd, buf, size);
442 if (len != -1) {
443 break;
444 }
445 if (errno == EAGAIN) {
446 yield_until_fd_readable(s->fd);
447 } else if (errno != EINTR) {
448 break;
449 }
450 }
451
452 if (len == -1) {
453 len = -errno;
454 }
455 return len;
456}
457
458static int unix_close(void *opaque)
459{
460 QEMUFileSocket *s = opaque;
461 close(s->fd);
462 g_free(s);
463 return 0;
464}
465
466static const QEMUFileOps unix_read_ops = {
467 .get_fd = socket_get_fd,
468 .get_buffer = unix_get_buffer,
469 .close = unix_close
470};
471
472static const QEMUFileOps unix_write_ops = {
473 .get_fd = socket_get_fd,
474 .writev_buffer = unix_writev_buffer,
475 .close = unix_close
476};
477
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200478QEMUFile *qemu_fdopen(int fd, const char *mode)
479{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100480 QEMUFileSocket *s;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200481
482 if (mode == NULL ||
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100483 (mode[0] != 'r' && mode[0] != 'w') ||
484 mode[1] != 'b' || mode[2] != 0) {
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200485 fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
486 return NULL;
487 }
488
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100489 s = g_malloc0(sizeof(QEMUFileSocket));
490 s->fd = fd;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200491
492 if(mode[0] == 'r') {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100493 s->file = qemu_fopen_ops(s, &unix_read_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200494 } else {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100495 s->file = qemu_fopen_ops(s, &unix_write_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200496 }
497 return s->file;
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200498}
499
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100500static const QEMUFileOps socket_read_ops = {
501 .get_fd = socket_get_fd,
502 .get_buffer = socket_get_buffer,
503 .close = file_socket_close
504};
505
506static const QEMUFileOps socket_write_ops = {
507 .get_fd = socket_get_fd,
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100508 .writev_buffer = socket_writev_buffer,
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100509 .close = file_socket_close
510};
511
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100512bool qemu_file_mode_is_not_valid(const char *mode)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700513{
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100514 if (mode == NULL ||
515 (mode[0] != 'r' && mode[0] != 'w') ||
516 mode[1] != 'b' || mode[2] != 0) {
517 fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
518 return true;
519 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700520
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100521 return false;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700522}
523
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100524QEMUFile *qemu_fopen_socket(int fd, const char *mode)
525{
526 QEMUFileSocket *s;
527
528 if (qemu_file_mode_is_not_valid(mode)) {
529 return NULL;
530 }
531
532 s = g_malloc0(sizeof(QEMUFileSocket));
533 s->fd = fd;
534 if (mode[0] == 'w') {
535 qemu_set_block(s->fd);
536 s->file = qemu_fopen_ops(s, &socket_write_ops);
537 } else {
538 s->file = qemu_fopen_ops(s, &socket_read_ops);
539 }
540 return s->file;
541}
542
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700543QEMUFile *qemu_fopen(const char *filename, const char *mode)
544{
545 QEMUFileStdio *s;
546
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100547 if (qemu_file_mode_is_not_valid(mode)) {
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200548 return NULL;
549 }
550
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100551 s = g_malloc0(sizeof(QEMUFileStdio));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700552
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200553 s->stdio_file = fopen(filename, mode);
554 if (!s->stdio_file)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700555 goto fail;
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100556
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200557 if(mode[0] == 'w') {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100558 s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200559 } else {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100560 s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200561 }
562 return s->file;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700563fail:
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100564 g_free(s);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700565 return NULL;
566}
567
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100568#ifndef CONFIG_ANDROID
569// TODO(digit): Once bdrv_writev_vmstate() is implemented.
570static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
571 int64_t pos)
572{
573 int ret;
574 QEMUIOVector qiov;
575
576 qemu_iovec_init_external(&qiov, iov, iovcnt);
577 ret = bdrv_writev_vmstate(opaque, &qiov, pos);
578 if (ret < 0) {
579 return ret;
580 }
581
582 return qiov.size;
583}
584#endif
585
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700586static int block_put_buffer(void *opaque, const uint8_t *buf,
587 int64_t pos, int size)
588{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200589 bdrv_save_vmstate(opaque, buf, pos, size);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700590 return size;
591}
592
593static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
594{
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200595 return bdrv_load_vmstate(opaque, buf, pos, size);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700596}
597
598static int bdrv_fclose(void *opaque)
599{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100600 // TODO(digit): bdrv_flush() should return error code.
601 bdrv_flush(opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700602 return 0;
603}
604
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100605static const QEMUFileOps bdrv_read_ops = {
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100606 .get_buffer = block_get_buffer,
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100607 .close = bdrv_fclose
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100608};
609
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100610static const QEMUFileOps bdrv_write_ops = {
611 .put_buffer = block_put_buffer,
612 //.writev_buffer = block_writev_buffer,
613 .close = bdrv_fclose
David 'Digit' Turner0e051542014-01-23 02:41:42 +0100614};
615
David 'Digit' Turner986acc92011-05-10 16:50:01 +0200616static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700617{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700618 if (is_writable)
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100619 return qemu_fopen_ops(bs, &bdrv_write_ops);
620 return qemu_fopen_ops(bs, &bdrv_read_ops);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700621}
622
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100623QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700624{
625 QEMUFile *f;
626
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100627 f = g_malloc0(sizeof(QEMUFile));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700628
629 f->opaque = opaque;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100630 f->ops = ops;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700631 return f;
632}
633
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100634/*
635 * Get last error for stream f
636 *
637 * Return negative error value if there has been an error on previous
638 * operations, return 0 if no error happened.
639 *
640 */
641int qemu_file_get_error(QEMUFile *f)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700642{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100643 return f->last_error;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700644}
645
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100646void qemu_file_set_error(QEMUFile *f, int ret)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700647{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100648 if (f->last_error == 0) {
649 f->last_error = ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700650 }
651}
652
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100653static inline bool qemu_file_is_writable(QEMUFile *f)
654{
655 return f->ops->writev_buffer || f->ops->put_buffer;
656}
657
658/**
659 * Flushes QEMUFile buffer
660 *
661 * If there is writev_buffer QEMUFileOps it uses it otherwise uses
662 * put_buffer ops.
663 */
664void qemu_fflush(QEMUFile *f)
665{
666 ssize_t ret = 0;
667
668 if (!qemu_file_is_writable(f)) {
669 return;
670 }
671
672 if (f->ops->writev_buffer) {
673 if (f->iovcnt > 0) {
674 ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
675 }
676 } else {
677 if (f->buf_index > 0) {
678 ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
679 }
680 }
681 if (ret >= 0) {
682 f->pos += ret;
683 }
684 f->buf_index = 0;
685 f->iovcnt = 0;
686 if (ret < 0) {
687 qemu_file_set_error(f, ret);
688 }
689}
690
691#ifndef CONFIG_ANDROID
692// TODO(digit).
693void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
694{
695 int ret = 0;
696
697 if (f->ops->before_ram_iterate) {
698 ret = f->ops->before_ram_iterate(f, f->opaque, flags);
699 if (ret < 0) {
700 qemu_file_set_error(f, ret);
701 }
702 }
703}
704
705void ram_control_after_iterate(QEMUFile *f, uint64_t flags)
706{
707 int ret = 0;
708
709 if (f->ops->after_ram_iterate) {
710 ret = f->ops->after_ram_iterate(f, f->opaque, flags);
711 if (ret < 0) {
712 qemu_file_set_error(f, ret);
713 }
714 }
715}
716
717void ram_control_load_hook(QEMUFile *f, uint64_t flags)
718{
719 int ret = -EINVAL;
720
721 if (f->ops->hook_ram_load) {
722 ret = f->ops->hook_ram_load(f, f->opaque, flags);
723 if (ret < 0) {
724 qemu_file_set_error(f, ret);
725 }
726 } else {
727 qemu_file_set_error(f, ret);
728 }
729}
730
731size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
732 ram_addr_t offset, size_t size, int *bytes_sent)
733{
734 if (f->ops->save_page) {
735 int ret = f->ops->save_page(f, f->opaque, block_offset,
736 offset, size, bytes_sent);
737
738 if (ret != RAM_SAVE_CONTROL_DELAYED) {
739 if (bytes_sent && *bytes_sent > 0) {
740 qemu_update_position(f, *bytes_sent);
741 } else if (ret < 0) {
742 qemu_file_set_error(f, ret);
743 }
744 }
745
746 return ret;
747 }
748
749 return RAM_SAVE_CONTROL_NOT_SUPP;
750}
751#endif // !CONFIG_ANDROID
752
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700753static void qemu_fill_buffer(QEMUFile *f)
754{
755 int len;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100756 int pending;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700757
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100758 assert(!qemu_file_is_writable(f));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700759
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100760 pending = f->buf_size - f->buf_index;
761 if (pending > 0) {
762 memmove(f->buf, f->buf + f->buf_index, pending);
763 }
764 f->buf_index = 0;
765 f->buf_size = pending;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700766
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100767 len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
768 IO_BUF_SIZE - pending);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700769 if (len > 0) {
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100770 f->buf_size += len;
771 f->pos += len;
772 } else if (len == 0) {
773 qemu_file_set_error(f, -EIO);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700774 } else if (len != -EAGAIN)
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100775 qemu_file_set_error(f, len);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700776}
777
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100778int qemu_get_fd(QEMUFile *f)
779{
780 if (f->ops->get_fd) {
781 return f->ops->get_fd(f->opaque);
782 }
783 return -1;
784}
785
786void qemu_update_position(QEMUFile *f, size_t size)
787{
788 f->pos += size;
789}
790
791/** Closes the file
792 *
793 * Returns negative error value if any error happened on previous operations or
794 * while closing the file. Returns 0 or positive number on success.
795 *
796 * The meaning of return value on success depends on the specific backend
797 * being used.
798 */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700799int qemu_fclose(QEMUFile *f)
800{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100801 int ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700802 qemu_fflush(f);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100803 ret = qemu_file_get_error(f);
804
805 if (f->ops->close) {
806 int ret2 = f->ops->close(f->opaque);
807 if (ret >= 0) {
808 ret = ret2;
809 }
810 }
811 /* If any error was spotted before closing, we should report it
812 * instead of the close() return value.
813 */
814 if (f->last_error) {
815 ret = f->last_error;
816 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100817 g_free(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700818 return ret;
819}
820
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100821static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700822{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100823 /* check for adjacent buffer and coalesce them */
824 if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base +
825 f->iov[f->iovcnt - 1].iov_len) {
826 f->iov[f->iovcnt - 1].iov_len += size;
827 } else {
828 f->iov[f->iovcnt].iov_base = (uint8_t *)buf;
829 f->iov[f->iovcnt++].iov_len = size;
830 }
831
832 if (f->iovcnt >= MAX_IOV_SIZE) {
833 qemu_fflush(f);
834 }
835}
836
837void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size)
838{
839 if (!f->ops->writev_buffer) {
840 qemu_put_buffer(f, buf, size);
841 return;
842 }
843
844 if (f->last_error) {
845 return;
846 }
847
848 f->bytes_xfer += size;
849 add_to_iovec(f, buf, size);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700850}
851
852void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
853{
854 int l;
855
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100856 if (f->last_error) {
857 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700858 }
859
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100860 while (size > 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700861 l = IO_BUF_SIZE - f->buf_index;
862 if (l > size)
863 l = size;
864 memcpy(f->buf + f->buf_index, buf, l);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100865 f->bytes_xfer += l;
866 if (f->ops->writev_buffer) {
867 add_to_iovec(f, f->buf + f->buf_index, l);
868 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700869 f->buf_index += l;
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100870 if (f->buf_index == IO_BUF_SIZE) {
871 qemu_fflush(f);
872 }
873 if (qemu_file_get_error(f)) {
874 break;
875 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700876 buf += l;
877 size -= l;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700878 }
879}
880
881void qemu_put_byte(QEMUFile *f, int v)
882{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100883 if (f->last_error) {
884 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700885 }
886
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100887 f->buf[f->buf_index] = v;
888 f->bytes_xfer++;
889 if (f->ops->writev_buffer) {
890 add_to_iovec(f, f->buf + f->buf_index, 1);
891 }
892 f->buf_index++;
893 if (f->buf_index == IO_BUF_SIZE) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700894 qemu_fflush(f);
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100895 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700896}
897
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100898static void qemu_file_skip(QEMUFile *f, int size)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700899{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100900 if (f->buf_index + size <= f->buf_size) {
901 f->buf_index += size;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700902 }
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100903}
904
905static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
906{
907 int pending;
908 int index;
909
910 assert(!qemu_file_is_writable(f));
911
912 index = f->buf_index + offset;
913 pending = f->buf_size - index;
914 if (pending < size) {
915 qemu_fill_buffer(f);
916 index = f->buf_index + offset;
917 pending = f->buf_size - index;
918 }
919
920 if (pending <= 0) {
921 return 0;
922 }
923 if (size > pending) {
924 size = pending;
925 }
926
927 memcpy(buf, f->buf + index, size);
928 return size;
929}
930
931int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
932{
933 int pending = size;
934 int done = 0;
935
936 while (pending > 0) {
937 int res;
938
939 res = qemu_peek_buffer(f, buf, pending, 0);
940 if (res == 0) {
941 return done;
942 }
943 qemu_file_skip(f, res);
944 buf += res;
945 pending -= res;
946 done += res;
947 }
948 return done;
949}
950
951static int qemu_peek_byte(QEMUFile *f, int offset)
952{
953 int index = f->buf_index + offset;
954
955 assert(!qemu_file_is_writable(f));
956
957 if (index >= f->buf_size) {
958 qemu_fill_buffer(f);
959 index = f->buf_index + offset;
960 if (index >= f->buf_size) {
961 return 0;
962 }
963 }
964 return f->buf[index];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700965}
966
967int qemu_get_byte(QEMUFile *f)
968{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100969 int result;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700970
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +0100971 result = qemu_peek_byte(f, 0);
972 qemu_file_skip(f, 1);
973 return result;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700974}
975
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200976#ifdef CONFIG_ANDROID
977void qemu_put_string(QEMUFile *f, const char* str)
978{
979 /* We will encode NULL and the empty string in the same way */
980 int slen;
981 if (str == NULL) {
982 str = "";
983 }
984 slen = strlen(str);
985 qemu_put_be32(f, slen);
986 qemu_put_buffer(f, (const uint8_t*)str, slen);
987}
988
989char* qemu_get_string(QEMUFile *f)
990{
991 int slen = qemu_get_be32(f);
992 char* str;
993 if (slen == 0)
994 return NULL;
995
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100996 str = g_malloc(slen+1);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200997 if (qemu_get_buffer(f, (uint8_t*)str, slen) != slen) {
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100998 g_free(str);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200999 return NULL;
1000 }
1001 str[slen] = '\0';
1002 return str;
1003}
1004#endif
1005
1006
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001007int64_t qemu_ftell(QEMUFile *f)
1008{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001009 qemu_fflush(f);
1010 return f->pos;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001011}
1012
1013int qemu_file_rate_limit(QEMUFile *f)
1014{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001015 if (qemu_file_get_error(f)) {
1016 return 1;
1017 }
1018 if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) {
1019 return 1;
1020 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001021 return 0;
1022}
1023
David 'Digit' Turner986acc92011-05-10 16:50:01 +02001024int64_t qemu_file_get_rate_limit(QEMUFile *f)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001025{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001026 return f->xfer_limit;
David 'Digit' Turner986acc92011-05-10 16:50:01 +02001027}
1028
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001029void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit)
David 'Digit' Turner986acc92011-05-10 16:50:01 +02001030{
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001031 f->xfer_limit = limit;
1032}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001033
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01001034void qemu_file_reset_rate_limit(QEMUFile *f)
1035{
1036 f->bytes_xfer = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001037}
1038
1039void qemu_put_be16(QEMUFile *f, unsigned int v)
1040{
1041 qemu_put_byte(f, v >> 8);
1042 qemu_put_byte(f, v);
1043}
1044
1045void qemu_put_be32(QEMUFile *f, unsigned int v)
1046{
1047 qemu_put_byte(f, v >> 24);
1048 qemu_put_byte(f, v >> 16);
1049 qemu_put_byte(f, v >> 8);
1050 qemu_put_byte(f, v);
1051}
1052
1053void qemu_put_be64(QEMUFile *f, uint64_t v)
1054{
1055 qemu_put_be32(f, v >> 32);
1056 qemu_put_be32(f, v);
1057}
1058
1059unsigned int qemu_get_be16(QEMUFile *f)
1060{
1061 unsigned int v;
1062 v = qemu_get_byte(f) << 8;
1063 v |= qemu_get_byte(f);
1064 return v;
1065}
1066
1067unsigned int qemu_get_be32(QEMUFile *f)
1068{
1069 unsigned int v;
1070 v = qemu_get_byte(f) << 24;
1071 v |= qemu_get_byte(f) << 16;
1072 v |= qemu_get_byte(f) << 8;
1073 v |= qemu_get_byte(f);
1074 return v;
1075}
1076
1077uint64_t qemu_get_be64(QEMUFile *f)
1078{
1079 uint64_t v;
1080 v = (uint64_t)qemu_get_be32(f) << 32;
1081 v |= qemu_get_be32(f);
1082 return v;
1083}
1084
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +01001085
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001086void qemu_put_struct(QEMUFile* f, const QField* fields, const void* s)
1087{
1088 const QField* qf = fields;
1089
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001090 /* Iterate over struct fields */
1091 while (qf->type != Q_FIELD_END) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001092 uint8_t* p = (uint8_t*)s + qf->offset;
1093
1094 switch (qf->type) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001095 case Q_FIELD_BYTE:
1096 qemu_put_byte(f, p[0]);
1097 break;
1098 case Q_FIELD_INT16:
1099 qemu_put_be16(f, ((uint16_t*)p)[0]);
1100 break;
1101 case Q_FIELD_INT32:
1102 qemu_put_be32(f, ((uint32_t*)p)[0]);
1103 break;
1104 case Q_FIELD_INT64:
1105 qemu_put_be64(f, ((uint64_t*)p)[0]);
1106 break;
1107 case Q_FIELD_BUFFER:
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001108 if (qf[1].type != Q_FIELD_BUFFER_SIZE ||
1109 qf[2].type != Q_FIELD_BUFFER_SIZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001110 {
1111 fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n",
1112 __FUNCTION__ );
1113 exit(1);
1114 }
1115 else
1116 {
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001117 uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001118
1119 qemu_put_buffer(f, p, size);
1120 qf += 2;
1121 }
1122 break;
1123 default:
1124 fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
1125 exit(1);
1126 }
1127 qf++;
1128 }
1129}
1130
1131int qemu_get_struct(QEMUFile* f, const QField* fields, void* s)
1132{
1133 const QField* qf = fields;
1134
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001135 /* Iterate over struct fields */
1136 while (qf->type != Q_FIELD_END) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001137 uint8_t* p = (uint8_t*)s + qf->offset;
1138
1139 switch (qf->type) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001140 case Q_FIELD_BYTE:
1141 p[0] = qemu_get_byte(f);
1142 break;
1143 case Q_FIELD_INT16:
1144 ((uint16_t*)p)[0] = qemu_get_be16(f);
1145 break;
1146 case Q_FIELD_INT32:
1147 ((uint32_t*)p)[0] = qemu_get_be32(f);
1148 break;
1149 case Q_FIELD_INT64:
1150 ((uint64_t*)p)[0] = qemu_get_be64(f);
1151 break;
1152 case Q_FIELD_BUFFER:
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001153 if (qf[1].type != Q_FIELD_BUFFER_SIZE ||
1154 qf[2].type != Q_FIELD_BUFFER_SIZE)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001155 {
1156 fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n",
1157 __FUNCTION__ );
1158 return -1;
1159 }
1160 else
1161 {
Ot ten Thije7fd67eb2010-07-29 10:26:01 +01001162 uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001163 int ret = qemu_get_buffer(f, p, size);
1164
1165 if (ret != size) {
1166 fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__);
1167 return -1;
1168 }
1169 qf += 2;
1170 }
1171 break;
1172 default:
1173 fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
1174 exit(1);
1175 }
1176 qf++;
1177 }
1178 return 0;
1179}
1180
Ot ten Thije871da2a2010-09-20 10:29:22 +01001181/* write a float to file */
1182void qemu_put_float(QEMUFile *f, float v)
1183{
1184 uint8_t *bytes = (uint8_t*) &v;
1185 qemu_put_buffer(f, bytes, sizeof(float));
1186}
1187
1188/* read a float from file */
1189float qemu_get_float(QEMUFile *f)
1190{
1191 uint8_t bytes[sizeof(float)];
1192 qemu_get_buffer(f, bytes, sizeof(float));
1193
1194 return *((float*) bytes);
1195}
1196
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001197/* timer */
1198
1199void timer_put(QEMUFile *f, QEMUTimer *ts)
1200{
1201 uint64_t expire_time;
1202
1203 expire_time = timer_expire_time_ns(ts);
1204 qemu_put_be64(f, expire_time);
1205}
1206
1207void timer_get(QEMUFile *f, QEMUTimer *ts)
1208{
1209 uint64_t expire_time;
1210
1211 expire_time = qemu_get_be64(f);
1212 if (expire_time != -1) {
1213 timer_mod_ns(ts, expire_time);
1214 } else {
1215 timer_del(ts);
1216 }
1217}
1218
1219
1220/* bool */
1221
1222static int get_bool(QEMUFile *f, void *pv, size_t size)
1223{
1224 bool *v = pv;
1225 *v = qemu_get_byte(f);
1226 return 0;
1227}
1228
1229static void put_bool(QEMUFile *f, void *pv, size_t size)
1230{
1231 bool *v = pv;
1232 qemu_put_byte(f, *v);
1233}
1234
1235const VMStateInfo vmstate_info_bool = {
1236 .name = "bool",
1237 .get = get_bool,
1238 .put = put_bool,
1239};
1240
1241/* 8 bit int */
1242
1243static int get_int8(QEMUFile *f, void *pv, size_t size)
1244{
1245 int8_t *v = pv;
1246 qemu_get_s8s(f, v);
1247 return 0;
1248}
1249
1250static void put_int8(QEMUFile *f, void *pv, size_t size)
1251{
1252 int8_t *v = pv;
1253 qemu_put_s8s(f, v);
1254}
1255
1256const VMStateInfo vmstate_info_int8 = {
1257 .name = "int8",
1258 .get = get_int8,
1259 .put = put_int8,
1260};
1261
1262/* 16 bit int */
1263
1264static int get_int16(QEMUFile *f, void *pv, size_t size)
1265{
1266 int16_t *v = pv;
1267 qemu_get_sbe16s(f, v);
1268 return 0;
1269}
1270
1271static void put_int16(QEMUFile *f, void *pv, size_t size)
1272{
1273 int16_t *v = pv;
1274 qemu_put_sbe16s(f, v);
1275}
1276
1277const VMStateInfo vmstate_info_int16 = {
1278 .name = "int16",
1279 .get = get_int16,
1280 .put = put_int16,
1281};
1282
1283/* 32 bit int */
1284
1285static int get_int32(QEMUFile *f, void *pv, size_t size)
1286{
1287 int32_t *v = pv;
1288 qemu_get_sbe32s(f, v);
1289 return 0;
1290}
1291
1292static void put_int32(QEMUFile *f, void *pv, size_t size)
1293{
1294 int32_t *v = pv;
1295 qemu_put_sbe32s(f, v);
1296}
1297
1298const VMStateInfo vmstate_info_int32 = {
1299 .name = "int32",
1300 .get = get_int32,
1301 .put = put_int32,
1302};
1303
1304/* 32 bit int. See that the received value is the same than the one
1305 in the field */
1306
1307static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
1308{
1309 int32_t *v = pv;
1310 int32_t v2;
1311 qemu_get_sbe32s(f, &v2);
1312
1313 if (*v == v2)
1314 return 0;
1315 return -EINVAL;
1316}
1317
1318const VMStateInfo vmstate_info_int32_equal = {
1319 .name = "int32 equal",
1320 .get = get_int32_equal,
1321 .put = put_int32,
1322};
1323
1324/* 32 bit int. See that the received value is the less or the same
1325 than the one in the field */
1326
1327static int get_int32_le(QEMUFile *f, void *pv, size_t size)
1328{
1329 int32_t *old = pv;
1330 int32_t new;
1331 qemu_get_sbe32s(f, &new);
1332
1333 if (*old <= new)
1334 return 0;
1335 return -EINVAL;
1336}
1337
1338const VMStateInfo vmstate_info_int32_le = {
1339 .name = "int32 equal",
1340 .get = get_int32_le,
1341 .put = put_int32,
1342};
1343
1344/* 64 bit int */
1345
1346static int get_int64(QEMUFile *f, void *pv, size_t size)
1347{
1348 int64_t *v = pv;
1349 qemu_get_sbe64s(f, v);
1350 return 0;
1351}
1352
1353static void put_int64(QEMUFile *f, void *pv, size_t size)
1354{
1355 int64_t *v = pv;
1356 qemu_put_sbe64s(f, v);
1357}
1358
1359const VMStateInfo vmstate_info_int64 = {
1360 .name = "int64",
1361 .get = get_int64,
1362 .put = put_int64,
1363};
1364
1365/* 8 bit unsigned int */
1366
1367static int get_uint8(QEMUFile *f, void *pv, size_t size)
1368{
1369 uint8_t *v = pv;
1370 qemu_get_8s(f, v);
1371 return 0;
1372}
1373
1374static void put_uint8(QEMUFile *f, void *pv, size_t size)
1375{
1376 uint8_t *v = pv;
1377 qemu_put_8s(f, v);
1378}
1379
1380const VMStateInfo vmstate_info_uint8 = {
1381 .name = "uint8",
1382 .get = get_uint8,
1383 .put = put_uint8,
1384};
1385
1386/* 16 bit unsigned int */
1387
1388static int get_uint16(QEMUFile *f, void *pv, size_t size)
1389{
1390 uint16_t *v = pv;
1391 qemu_get_be16s(f, v);
1392 return 0;
1393}
1394
1395static void put_uint16(QEMUFile *f, void *pv, size_t size)
1396{
1397 uint16_t *v = pv;
1398 qemu_put_be16s(f, v);
1399}
1400
1401const VMStateInfo vmstate_info_uint16 = {
1402 .name = "uint16",
1403 .get = get_uint16,
1404 .put = put_uint16,
1405};
1406
1407/* 32 bit unsigned int */
1408
1409static int get_uint32(QEMUFile *f, void *pv, size_t size)
1410{
1411 uint32_t *v = pv;
1412 qemu_get_be32s(f, v);
1413 return 0;
1414}
1415
1416static void put_uint32(QEMUFile *f, void *pv, size_t size)
1417{
1418 uint32_t *v = pv;
1419 qemu_put_be32s(f, v);
1420}
1421
1422const VMStateInfo vmstate_info_uint32 = {
1423 .name = "uint32",
1424 .get = get_uint32,
1425 .put = put_uint32,
1426};
1427
1428/* 32 bit uint. See that the received value is the same than the one
1429 in the field */
1430
1431static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
1432{
1433 uint32_t *v = pv;
1434 uint32_t v2;
1435 qemu_get_be32s(f, &v2);
1436
1437 if (*v == v2) {
1438 return 0;
1439 }
1440 return -EINVAL;
1441}
1442
1443const VMStateInfo vmstate_info_uint32_equal = {
1444 .name = "uint32 equal",
1445 .get = get_uint32_equal,
1446 .put = put_uint32,
1447};
1448
1449/* 64 bit unsigned int */
1450
1451static int get_uint64(QEMUFile *f, void *pv, size_t size)
1452{
1453 uint64_t *v = pv;
1454 qemu_get_be64s(f, v);
1455 return 0;
1456}
1457
1458static void put_uint64(QEMUFile *f, void *pv, size_t size)
1459{
1460 uint64_t *v = pv;
1461 qemu_put_be64s(f, v);
1462}
1463
1464const VMStateInfo vmstate_info_uint64 = {
1465 .name = "uint64",
1466 .get = get_uint64,
1467 .put = put_uint64,
1468};
1469
1470/* 64 bit unsigned int. See that the received value is the same than the one
1471 in the field */
1472
1473static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
1474{
1475 uint64_t *v = pv;
1476 uint64_t v2;
1477 qemu_get_be64s(f, &v2);
1478
1479 if (*v == v2) {
1480 return 0;
1481 }
1482 return -EINVAL;
1483}
1484
1485const VMStateInfo vmstate_info_uint64_equal = {
1486 .name = "int64 equal",
1487 .get = get_uint64_equal,
1488 .put = put_uint64,
1489};
1490
1491/* 8 bit int. See that the received value is the same than the one
1492 in the field */
1493
1494static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
1495{
1496 uint8_t *v = pv;
1497 uint8_t v2;
1498 qemu_get_8s(f, &v2);
1499
1500 if (*v == v2)
1501 return 0;
1502 return -EINVAL;
1503}
1504
1505const VMStateInfo vmstate_info_uint8_equal = {
1506 .name = "uint8 equal",
1507 .get = get_uint8_equal,
1508 .put = put_uint8,
1509};
1510
1511/* 16 bit unsigned int int. See that the received value is the same than the one
1512 in the field */
1513
1514static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
1515{
1516 uint16_t *v = pv;
1517 uint16_t v2;
1518 qemu_get_be16s(f, &v2);
1519
1520 if (*v == v2)
1521 return 0;
1522 return -EINVAL;
1523}
1524
1525const VMStateInfo vmstate_info_uint16_equal = {
1526 .name = "uint16 equal",
1527 .get = get_uint16_equal,
1528 .put = put_uint16,
1529};
1530
1531/* floating point */
1532
1533static int get_float64(QEMUFile *f, void *pv, size_t size)
1534{
1535 float64 *v = pv;
1536
1537 *v = make_float64(qemu_get_be64(f));
1538 return 0;
1539}
1540
1541static void put_float64(QEMUFile *f, void *pv, size_t size)
1542{
1543 uint64_t *v = pv;
1544
1545 qemu_put_be64(f, float64_val(*v));
1546}
1547
1548const VMStateInfo vmstate_info_float64 = {
1549 .name = "float64",
1550 .get = get_float64,
1551 .put = put_float64,
1552};
1553
1554/* timers */
1555
1556static int get_timer(QEMUFile *f, void *pv, size_t size)
1557{
1558 QEMUTimer *v = pv;
1559 timer_get(f, v);
1560 return 0;
1561}
1562
1563static void put_timer(QEMUFile *f, void *pv, size_t size)
1564{
1565 QEMUTimer *v = pv;
1566 timer_put(f, v);
1567}
1568
1569const VMStateInfo vmstate_info_timer = {
1570 .name = "timer",
1571 .get = get_timer,
1572 .put = put_timer,
1573};
1574
1575/* uint8_t buffers */
1576
1577static int get_buffer(QEMUFile *f, void *pv, size_t size)
1578{
1579 uint8_t *v = pv;
1580 qemu_get_buffer(f, v, size);
1581 return 0;
1582}
1583
1584static void put_buffer(QEMUFile *f, void *pv, size_t size)
1585{
1586 uint8_t *v = pv;
1587 qemu_put_buffer(f, v, size);
1588}
1589
1590const VMStateInfo vmstate_info_buffer = {
1591 .name = "buffer",
1592 .get = get_buffer,
1593 .put = put_buffer,
1594};
1595
1596/* unused buffers: space that was used for some fields that are
1597 not useful anymore */
1598
1599static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
1600{
1601 uint8_t buf[1024];
1602 int block_len;
1603
1604 while (size > 0) {
1605 block_len = MIN(sizeof(buf), size);
1606 size -= block_len;
1607 qemu_get_buffer(f, buf, block_len);
1608 }
1609 return 0;
1610}
1611
1612static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
1613{
1614 static const uint8_t buf[1024];
1615 int block_len;
1616
1617 while (size > 0) {
1618 block_len = MIN(sizeof(buf), size);
1619 size -= block_len;
1620 qemu_put_buffer(f, buf, block_len);
1621 }
1622}
1623
1624const VMStateInfo vmstate_info_unused_buffer = {
1625 .name = "unused_buffer",
1626 .get = get_unused_buffer,
1627 .put = put_unused_buffer,
1628};
1629
1630/* bitmaps (as defined by bitmap.h). Note that size here is the size
1631 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
1632 * bit words with the bits in big endian order. The in-memory format
1633 * is an array of 'unsigned long', which may be either 32 or 64 bits.
1634 */
1635/* This is the number of 64 bit words sent over the wire */
1636#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
1637static int get_bitmap(QEMUFile *f, void *pv, size_t size)
1638{
1639 unsigned long *bmp = pv;
1640 int i, idx = 0;
1641 for (i = 0; i < BITS_TO_U64S(size); i++) {
1642 uint64_t w = qemu_get_be64(f);
1643 bmp[idx++] = w;
1644 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
1645 bmp[idx++] = w >> 32;
1646 }
1647 }
1648 return 0;
1649}
1650
1651static void put_bitmap(QEMUFile *f, void *pv, size_t size)
1652{
1653 unsigned long *bmp = pv;
1654 int i, idx = 0;
1655 for (i = 0; i < BITS_TO_U64S(size); i++) {
1656 uint64_t w = bmp[idx++];
1657 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
1658 w |= ((uint64_t)bmp[idx++]) << 32;
1659 }
1660 qemu_put_be64(f, w);
1661 }
1662}
1663
1664const VMStateInfo vmstate_info_bitmap = {
1665 .name = "bitmap",
1666 .get = get_bitmap,
1667 .put = put_bitmap,
1668};
1669
1670typedef struct CompatEntry {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001671 char idstr[256];
1672 int instance_id;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001673} CompatEntry;
1674
1675typedef struct SaveStateEntry {
1676 QTAILQ_ENTRY(SaveStateEntry) entry;
1677 char idstr[256];
1678 int instance_id;
1679 int alias_id;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001680 int version_id;
1681 int section_id;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001682 SaveVMHandlers *ops;
1683 const VMStateDescription *vmsd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001684 void *opaque;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001685 CompatEntry *compat;
1686 int no_migrate;
1687 int is_ram;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001688} SaveStateEntry;
1689
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001690
1691static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
1692 QTAILQ_HEAD_INITIALIZER(savevm_handlers);
1693static int global_section_id;
1694
1695static int calculate_new_instance_id(const char *idstr)
1696{
1697 SaveStateEntry *se;
1698 int instance_id = 0;
1699
1700 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
1701 if (strcmp(idstr, se->idstr) == 0
1702 && instance_id <= se->instance_id) {
1703 instance_id = se->instance_id + 1;
1704 }
1705 }
1706 return instance_id;
1707}
1708
1709static int calculate_compat_instance_id(const char *idstr)
1710{
1711 SaveStateEntry *se;
1712 int instance_id = 0;
1713
1714 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
1715 if (!se->compat)
1716 continue;
1717
1718 if (strcmp(idstr, se->compat->idstr) == 0
1719 && instance_id <= se->compat->instance_id) {
1720 instance_id = se->compat->instance_id + 1;
1721 }
1722 }
1723 return instance_id;
1724}
1725
1726#ifdef CONFIG_ANDROID
1727// TODO(digit): Implement this properly once we switch all devices to
1728// be DeviceState instances.
1729char* qdev_get_dev_path(DeviceState* dev) {
1730 return NULL;
1731}
1732#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001733
1734/* TODO: Individual devices generally have very little idea about the rest
1735 of the system, so instance_id should be removed/replaced.
1736 Meanwhile pass -1 as instance_id if you do not already have a clearly
1737 distinguishing id for all instances of your device class. */
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001738int register_savevm_live(DeviceState *dev,
1739 const char *idstr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001740 int instance_id,
1741 int version_id,
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001742 SaveVMHandlers *ops,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001743 void *opaque)
1744{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001745 SaveStateEntry *se;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001746
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001747 se = g_malloc0(sizeof(SaveStateEntry));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001748 se->version_id = version_id;
1749 se->section_id = global_section_id++;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001750 se->ops = ops;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001751 se->opaque = opaque;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001752 se->vmsd = NULL;
1753 se->no_migrate = 0;
1754 /* if this is a live_savem then set is_ram */
1755 if (ops->save_live_state != NULL) {
1756 se->is_ram = 1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001757 }
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001758
1759 if (dev) {
1760 char *id = qdev_get_dev_path(dev);
1761 if (id) {
1762 pstrcpy(se->idstr, sizeof(se->idstr), id);
1763 pstrcat(se->idstr, sizeof(se->idstr), "/");
1764 g_free(id);
1765
1766 se->compat = g_malloc0(sizeof(CompatEntry));
1767 pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr);
1768 se->compat->instance_id = instance_id == -1 ?
1769 calculate_compat_instance_id(idstr) : instance_id;
1770 instance_id = -1;
1771 }
1772 }
1773 pstrcat(se->idstr, sizeof(se->idstr), idstr);
1774
1775 if (instance_id == -1) {
1776 se->instance_id = calculate_new_instance_id(se->idstr);
1777 } else {
1778 se->instance_id = instance_id;
1779 }
1780 assert(!se->compat || se->instance_id == 0);
1781 /* add at the end of list */
1782 QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001783 return 0;
1784}
1785
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001786int register_savevm(DeviceState *dev,
1787 const char *idstr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001788 int instance_id,
1789 int version_id,
1790 SaveStateHandler *save_state,
1791 LoadStateHandler *load_state,
1792 void *opaque)
1793{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001794 SaveVMHandlers *ops = g_malloc0(sizeof(SaveVMHandlers));
1795 ops->save_state = save_state;
1796 ops->load_state = load_state;
1797 return register_savevm_live(dev, idstr, instance_id, version_id,
1798 ops, opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001799}
1800
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001801void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001802{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001803 SaveStateEntry *se, *new_se;
1804 char id[256] = "";
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001805
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001806 if (dev) {
1807 char *path = qdev_get_dev_path(dev);
1808 if (path) {
1809 pstrcpy(id, sizeof(id), path);
1810 pstrcat(id, sizeof(id), "/");
1811 g_free(path);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001812 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001813 }
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01001814 pstrcat(id, sizeof(id), idstr);
1815
1816 QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
1817 if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
1818 QTAILQ_REMOVE(&savevm_handlers, se, entry);
1819 if (se->compat) {
1820 g_free(se->compat);
1821 }
1822 g_free(se->ops);
1823 g_free(se);
1824 }
1825 }
1826}
1827
1828int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
1829 const VMStateDescription *vmsd,
1830 void *opaque, int alias_id,
1831 int required_for_version)
1832{
1833 SaveStateEntry *se;
1834
1835 /* If this triggers, alias support can be dropped for the vmsd. */
1836 assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
1837
1838 se = g_malloc0(sizeof(SaveStateEntry));
1839 se->version_id = vmsd->version_id;
1840 se->section_id = global_section_id++;
1841 se->opaque = opaque;
1842 se->vmsd = vmsd;
1843 se->alias_id = alias_id;
1844 se->no_migrate = vmsd->unmigratable;
1845
1846 if (dev) {
1847 char *id = qdev_get_dev_path(dev);
1848 if (id) {
1849 pstrcpy(se->idstr, sizeof(se->idstr), id);
1850 pstrcat(se->idstr, sizeof(se->idstr), "/");
1851 g_free(id);
1852
1853 se->compat = g_malloc0(sizeof(CompatEntry));
1854 pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
1855 se->compat->instance_id = instance_id == -1 ?
1856 calculate_compat_instance_id(vmsd->name) : instance_id;
1857 instance_id = -1;
1858 }
1859 }
1860 pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
1861
1862 if (instance_id == -1) {
1863 se->instance_id = calculate_new_instance_id(se->idstr);
1864 } else {
1865 se->instance_id = instance_id;
1866 }
1867 assert(!se->compat || se->instance_id == 0);
1868 /* add at the end of list */
1869 QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
1870 return 0;
1871}
1872
1873void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
1874 void *opaque)
1875{
1876 SaveStateEntry *se, *new_se;
1877
1878 QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
1879 if (se->vmsd == vmsd && se->opaque == opaque) {
1880 QTAILQ_REMOVE(&savevm_handlers, se, entry);
1881 if (se->compat) {
1882 g_free(se->compat);
1883 }
1884 g_free(se);
1885 }
1886 }
1887}
1888
1889static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
1890 void *opaque);
1891static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
1892 void *opaque);
1893
1894int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
1895 void *opaque, int version_id)
1896{
1897 VMStateField *field = vmsd->fields;
1898 int ret;
1899
1900 if (version_id > vmsd->version_id) {
1901 return -EINVAL;
1902 }
1903 if (version_id < vmsd->minimum_version_id_old) {
1904 return -EINVAL;
1905 }
1906 if (version_id < vmsd->minimum_version_id) {
1907 return vmsd->load_state_old(f, opaque, version_id);
1908 }
1909 if (vmsd->pre_load) {
1910 int ret = vmsd->pre_load(opaque);
1911 if (ret)
1912 return ret;
1913 }
1914 while(field->name) {
1915 if ((field->field_exists &&
1916 field->field_exists(opaque, version_id)) ||
1917 (!field->field_exists &&
1918 field->version_id <= version_id)) {
1919 void *base_addr = opaque + field->offset;
1920 int i, n_elems = 1;
1921 int size = field->size;
1922
1923 if (field->flags & VMS_VBUFFER) {
1924 size = *(int32_t *)(opaque+field->size_offset);
1925 if (field->flags & VMS_MULTIPLY) {
1926 size *= field->size;
1927 }
1928 }
1929 if (field->flags & VMS_ARRAY) {
1930 n_elems = field->num;
1931 } else if (field->flags & VMS_VARRAY_INT32) {
1932 n_elems = *(int32_t *)(opaque+field->num_offset);
1933 } else if (field->flags & VMS_VARRAY_UINT32) {
1934 n_elems = *(uint32_t *)(opaque+field->num_offset);
1935 } else if (field->flags & VMS_VARRAY_UINT16) {
1936 n_elems = *(uint16_t *)(opaque+field->num_offset);
1937 } else if (field->flags & VMS_VARRAY_UINT8) {
1938 n_elems = *(uint8_t *)(opaque+field->num_offset);
1939 }
1940 if (field->flags & VMS_POINTER) {
1941 base_addr = *(void **)base_addr + field->start;
1942 }
1943 for (i = 0; i < n_elems; i++) {
1944 void *addr = base_addr + size * i;
1945
1946 if (field->flags & VMS_ARRAY_OF_POINTER) {
1947 addr = *(void **)addr;
1948 }
1949 if (field->flags & VMS_STRUCT) {
1950 ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
1951 } else {
1952 ret = field->info->get(f, addr, size);
1953
1954 }
1955 if (ret < 0) {
1956 return ret;
1957 }
1958 }
1959 }
1960 field++;
1961 }
1962 ret = vmstate_subsection_load(f, vmsd, opaque);
1963 if (ret != 0) {
1964 return ret;
1965 }
1966 if (vmsd->post_load) {
1967 return vmsd->post_load(opaque, version_id);
1968 }
1969 return 0;
1970}
1971
1972void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
1973 void *opaque)
1974{
1975 VMStateField *field = vmsd->fields;
1976
1977 if (vmsd->pre_save) {
1978 vmsd->pre_save(opaque);
1979 }
1980 while(field->name) {
1981 if (!field->field_exists ||
1982 field->field_exists(opaque, vmsd->version_id)) {
1983 void *base_addr = opaque + field->offset;
1984 int i, n_elems = 1;
1985 int size = field->size;
1986
1987 if (field->flags & VMS_VBUFFER) {
1988 size = *(int32_t *)(opaque+field->size_offset);
1989 if (field->flags & VMS_MULTIPLY) {
1990 size *= field->size;
1991 }
1992 }
1993 if (field->flags & VMS_ARRAY) {
1994 n_elems = field->num;
1995 } else if (field->flags & VMS_VARRAY_INT32) {
1996 n_elems = *(int32_t *)(opaque+field->num_offset);
1997 } else if (field->flags & VMS_VARRAY_UINT32) {
1998 n_elems = *(uint32_t *)(opaque+field->num_offset);
1999 } else if (field->flags & VMS_VARRAY_UINT16) {
2000 n_elems = *(uint16_t *)(opaque+field->num_offset);
2001 } else if (field->flags & VMS_VARRAY_UINT8) {
2002 n_elems = *(uint8_t *)(opaque+field->num_offset);
2003 }
2004 if (field->flags & VMS_POINTER) {
2005 base_addr = *(void **)base_addr + field->start;
2006 }
2007 for (i = 0; i < n_elems; i++) {
2008 void *addr = base_addr + size * i;
2009
2010 if (field->flags & VMS_ARRAY_OF_POINTER) {
2011 addr = *(void **)addr;
2012 }
2013 if (field->flags & VMS_STRUCT) {
2014 vmstate_save_state(f, field->vmsd, addr);
2015 } else {
2016 field->info->put(f, addr, size);
2017 }
2018 }
2019 }
2020 field++;
2021 }
2022 vmstate_subsection_save(f, vmsd, opaque);
2023}
2024
2025static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
2026{
2027 if (!se->vmsd) { /* Old style */
2028 return se->ops->load_state(f, se->opaque, version_id);
2029 }
2030 return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
2031}
2032
2033static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
2034{
2035 if (!se->vmsd) { /* Old style */
2036 se->ops->save_state(f, se->opaque);
2037 return;
2038 }
2039 vmstate_save_state(f,se->vmsd, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002040}
2041
2042#define QEMU_VM_FILE_MAGIC 0x5145564d
2043#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002044#define QEMU_VM_FILE_VERSION 0x00000004
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002045
2046#define QEMU_VM_EOF 0x00
2047#define QEMU_VM_SECTION_START 0x01
2048#define QEMU_VM_SECTION_PART 0x02
2049#define QEMU_VM_SECTION_END 0x03
2050#define QEMU_VM_SECTION_FULL 0x04
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002051#define QEMU_VM_SUBSECTION 0x05
2052
2053bool qemu_savevm_state_blocked(Error **errp)
2054{
2055 SaveStateEntry *se;
2056
2057 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
2058 if (se->no_migrate) {
2059 error_set(errp, QERR_MIGRATION_NOT_SUPPORTED, se->idstr);
2060 return true;
2061 }
2062 }
2063 return false;
2064}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002065
2066int qemu_savevm_state_begin(QEMUFile *f)
2067{
2068 SaveStateEntry *se;
2069
2070 qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
2071 qemu_put_be32(f, QEMU_VM_FILE_VERSION);
2072
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002073 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002074 int len;
2075
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002076 if (!se->ops || !se->ops->save_live_state) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002077 continue;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002078 }
2079#if 0
2080 if (se->ops && se->ops->is_active) {
2081 if (!se->ops->is_active(se->opaque)) {
2082 continue;
2083 }
2084 }
2085#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002086 /* Section type */
2087 qemu_put_byte(f, QEMU_VM_SECTION_START);
2088 qemu_put_be32(f, se->section_id);
2089
2090 /* ID string */
2091 len = strlen(se->idstr);
2092 qemu_put_byte(f, len);
2093 qemu_put_buffer(f, (uint8_t *)se->idstr, len);
2094
2095 qemu_put_be32(f, se->instance_id);
2096 qemu_put_be32(f, se->version_id);
2097
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002098 se->ops->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002099 }
2100
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002101 return qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002102}
2103
2104int qemu_savevm_state_iterate(QEMUFile *f)
2105{
2106 SaveStateEntry *se;
2107 int ret = 1;
2108
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002109 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
2110 if (!se->ops || !se->ops->save_live_state) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002111 continue;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002112 }
2113#if 0
2114 if (se->ops && se->ops->is_active) {
2115 if (!se->ops->is_active(se->opaque)) {
2116 continue;
2117 }
2118 }
2119#endif
2120 if (qemu_file_rate_limit(f)) {
2121 return 0;
2122 }
2123 //trace_savevm_section_start();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002124 /* Section type */
2125 qemu_put_byte(f, QEMU_VM_SECTION_PART);
2126 qemu_put_be32(f, se->section_id);
2127
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002128 ret &= !!se->ops->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002129 }
2130
2131 if (ret)
2132 return 1;
2133
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002134 return qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002135}
2136
2137int qemu_savevm_state_complete(QEMUFile *f)
2138{
2139 SaveStateEntry *se;
2140
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002141 // cpu_synchronize_all_states();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002142
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002143 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
2144 if (!se->ops || se->ops->save_live_state == NULL) {
2145 continue;
2146 }
2147#if 0
2148 if (se->ops && se->ops->is_active) {
2149 if (!se->ops->is_active(se->opaque)) {
2150 continue;
2151 }
2152 }
2153#endif
2154 //trace_savevm_section_start();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002155 /* Section type */
2156 qemu_put_byte(f, QEMU_VM_SECTION_END);
2157 qemu_put_be32(f, se->section_id);
2158
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002159 se->ops->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002160 }
2161
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002162 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002163 int len;
2164
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002165 if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002166 continue;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002167 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002168
2169 /* Section type */
2170 qemu_put_byte(f, QEMU_VM_SECTION_FULL);
2171 qemu_put_be32(f, se->section_id);
2172
2173 /* ID string */
2174 len = strlen(se->idstr);
2175 qemu_put_byte(f, len);
2176 qemu_put_buffer(f, (uint8_t *)se->idstr, len);
2177
2178 qemu_put_be32(f, se->instance_id);
2179 qemu_put_be32(f, se->version_id);
2180
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002181 vmstate_save(f, se);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002182 }
2183
2184 qemu_put_byte(f, QEMU_VM_EOF);
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002185 qemu_fflush(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002186
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002187 return qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002188}
2189
2190int qemu_savevm_state(QEMUFile *f)
2191{
2192 int saved_vm_running;
2193 int ret;
2194
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002195 if (qemu_savevm_state_blocked(NULL)) {
2196 return -EINVAL;
2197 }
2198
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002199 saved_vm_running = vm_running;
2200 vm_stop(0);
2201
2202 bdrv_flush_all();
2203
2204 ret = qemu_savevm_state_begin(f);
2205 if (ret < 0)
2206 goto out;
2207
2208 do {
2209 ret = qemu_savevm_state_iterate(f);
2210 if (ret < 0)
2211 goto out;
2212 } while (ret == 0);
2213
2214 ret = qemu_savevm_state_complete(f);
2215
2216out:
David 'Digit' Turnerc79de3c2014-01-23 04:17:24 +01002217 ret = qemu_file_get_error(f);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002218
2219 if (!ret && saved_vm_running)
2220 vm_start();
2221
2222 return ret;
2223}
2224
2225static SaveStateEntry *find_se(const char *idstr, int instance_id)
2226{
2227 SaveStateEntry *se;
2228
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002229 QTAILQ_FOREACH(se, &savevm_handlers, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002230 if (!strcmp(se->idstr, idstr) &&
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002231 (instance_id == se->instance_id ||
2232 instance_id == se->alias_id))
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002233 return se;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002234 /* Migrating from an older version? */
2235 if (strstr(se->idstr, idstr) && se->compat) {
2236 if (!strcmp(se->compat->idstr, idstr) &&
2237 (instance_id == se->compat->instance_id ||
2238 instance_id == se->alias_id))
2239 return se;
2240 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002241 }
2242 return NULL;
2243}
2244
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002245static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection *sub, char *idstr)
2246{
2247 while(sub && sub->needed) {
2248 if (strcmp(idstr, sub->vmsd->name) == 0) {
2249 return sub->vmsd;
2250 }
2251 sub++;
2252 }
2253 return NULL;
2254}
2255
2256static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
2257 void *opaque)
2258{
2259 while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
2260 char idstr[256];
2261 int ret;
2262 uint8_t version_id, len, size;
2263 const VMStateDescription *sub_vmsd;
2264
2265 len = qemu_peek_byte(f, 1);
2266 if (len < strlen(vmsd->name) + 1) {
2267 /* subsection name has be be "section_name/a" */
2268 return 0;
2269 }
2270 size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
2271 if (size != len) {
2272 return 0;
2273 }
2274 idstr[size] = 0;
2275
2276 if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
2277 /* it don't have a valid subsection name */
2278 return 0;
2279 }
2280 sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
2281 if (sub_vmsd == NULL) {
2282 return -ENOENT;
2283 }
2284 qemu_file_skip(f, 1); /* subsection */
2285 qemu_file_skip(f, 1); /* len */
2286 qemu_file_skip(f, len); /* idstr */
2287 version_id = qemu_get_be32(f);
2288
2289 ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
2290 if (ret) {
2291 return ret;
2292 }
2293 }
2294 return 0;
2295}
2296
2297static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
2298 void *opaque)
2299{
2300 const VMStateSubsection *sub = vmsd->subsections;
2301
2302 while (sub && sub->needed) {
2303 if (sub->needed(opaque)) {
2304 const VMStateDescription *vmsd = sub->vmsd;
2305 uint8_t len;
2306
2307 qemu_put_byte(f, QEMU_VM_SUBSECTION);
2308 len = strlen(vmsd->name);
2309 qemu_put_byte(f, len);
2310 qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
2311 qemu_put_be32(f, vmsd->version_id);
2312 vmstate_save_state(f, vmsd, opaque);
2313 }
2314 sub++;
2315 }
2316}
2317
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002318typedef struct LoadStateEntry {
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002319 QLIST_ENTRY(LoadStateEntry) entry;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002320 SaveStateEntry *se;
2321 int section_id;
2322 int version_id;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002323} LoadStateEntry;
2324
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002325int qemu_loadvm_state(QEMUFile *f)
2326{
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002327 QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
2328 QLIST_HEAD_INITIALIZER(loadvm_handlers);
2329 LoadStateEntry *le, *new_le;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002330 uint8_t section_type;
2331 unsigned int v;
2332 int ret;
2333
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002334 if (qemu_savevm_state_blocked(NULL)) {
2335 return -EINVAL;
2336 }
2337
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002338 v = qemu_get_be32(f);
2339 if (v != QEMU_VM_FILE_MAGIC)
2340 return -EINVAL;
2341
2342 v = qemu_get_be32(f);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002343 if (v < QEMU_VM_FILE_VERSION) {
2344 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 -07002345 return -ENOTSUP;
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002346 } else if (v > QEMU_VM_FILE_VERSION) {
2347 fprintf(stderr, "Snapshot format %d is more recent than the emulator, please update your Android SDK Tools.\n", v);
2348 return -ENOTSUP;
2349 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002350
2351 while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
2352 uint32_t instance_id, version_id, section_id;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002353 SaveStateEntry *se;
2354 char idstr[257];
2355 int len;
2356
2357 switch (section_type) {
2358 case QEMU_VM_SECTION_START:
2359 case QEMU_VM_SECTION_FULL:
2360 /* Read section start */
2361 section_id = qemu_get_be32(f);
2362 len = qemu_get_byte(f);
2363 qemu_get_buffer(f, (uint8_t *)idstr, len);
2364 idstr[len] = 0;
2365 instance_id = qemu_get_be32(f);
2366 version_id = qemu_get_be32(f);
2367
2368 /* Find savevm section */
2369 se = find_se(idstr, instance_id);
2370 if (se == NULL) {
2371 fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
2372 ret = -EINVAL;
2373 goto out;
2374 }
2375
2376 /* Validate version */
2377 if (version_id > se->version_id) {
2378 fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
2379 version_id, idstr, se->version_id);
2380 ret = -EINVAL;
2381 goto out;
2382 }
2383
2384 /* Add entry */
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002385 le = g_malloc0(sizeof(*le));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002386
2387 le->se = se;
2388 le->section_id = section_id;
2389 le->version_id = version_id;
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002390 QLIST_INSERT_HEAD(&loadvm_handlers, le, entry);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002391
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002392 ret = vmstate_load(f, le->se, le->version_id);
2393 if (ret < 0) {
2394 fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
2395 instance_id, idstr);
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -07002396 goto out;
2397 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002398 break;
2399 case QEMU_VM_SECTION_PART:
2400 case QEMU_VM_SECTION_END:
2401 section_id = qemu_get_be32(f);
2402
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002403 QLIST_FOREACH(le, &loadvm_handlers, entry) {
2404 if (le->section_id == section_id) {
2405 break;
2406 }
2407 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002408 if (le == NULL) {
2409 fprintf(stderr, "Unknown savevm section %d\n", section_id);
2410 ret = -EINVAL;
2411 goto out;
2412 }
2413
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002414 ret = vmstate_load(f, le->se, le->version_id);
2415 if (ret < 0) {
2416 fprintf(stderr, "qemu: warning: error while loading state section id %d\n",
2417 section_id);
2418 goto out;
2419 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002420 break;
2421 default:
2422 fprintf(stderr, "Unknown savevm section type %d\n", section_type);
2423 ret = -EINVAL;
2424 goto out;
2425 }
2426 }
2427
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002428 //cpu_synchronize_all_post_init();
2429
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002430 ret = 0;
2431
2432out:
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002433 QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
2434 QLIST_REMOVE(le, entry);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002435 g_free(le);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002436 }
2437
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002438 if (ret == 0) {
2439 ret = qemu_file_get_error(f);
2440 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002441
2442 return ret;
2443}
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002444#if 0
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002445static BlockDriverState *get_bs_snapshots(void)
2446{
2447 BlockDriverState *bs;
2448 int i;
2449
2450 if (bs_snapshots)
2451 return bs_snapshots;
2452 for(i = 0; i <= nb_drives; i++) {
2453 bs = drives_table[i].bdrv;
2454 if (bdrv_can_snapshot(bs))
2455 goto ok;
2456 }
2457 return NULL;
2458 ok:
2459 bs_snapshots = bs;
2460 return bs;
2461}
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002462#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002463static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
2464 const char *name)
2465{
2466 QEMUSnapshotInfo *sn_tab, *sn;
2467 int nb_sns, i, ret;
2468
2469 ret = -ENOENT;
2470 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
2471 if (nb_sns < 0)
2472 return ret;
2473 for(i = 0; i < nb_sns; i++) {
2474 sn = &sn_tab[i];
2475 if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
2476 *sn_info = *sn;
2477 ret = 0;
2478 break;
2479 }
2480 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002481 g_free(sn_tab);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002482 return ret;
2483}
2484
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002485void do_savevm(Monitor *err, const char *name)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002486{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002487 BlockDriverState *bs, *bs1;
2488 QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002489 int must_delete, ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002490 BlockDriverInfo bdi1, *bdi = &bdi1;
2491 QEMUFile *f;
2492 int saved_vm_running;
2493 uint32_t vm_state_size;
2494#ifdef _WIN32
2495 struct _timeb tb;
2496#else
2497 struct timeval tv;
2498#endif
2499
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002500 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002501 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002502 monitor_printf(err, "No block device can accept snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002503 return;
2504 }
2505
2506 /* ??? Should this occur after vm_stop? */
2507 qemu_aio_flush();
2508
2509 saved_vm_running = vm_running;
2510 vm_stop(0);
2511
2512 must_delete = 0;
2513 if (name) {
2514 ret = bdrv_snapshot_find(bs, old_sn, name);
2515 if (ret >= 0) {
2516 must_delete = 1;
2517 }
2518 }
2519 memset(sn, 0, sizeof(*sn));
2520 if (must_delete) {
2521 pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
2522 pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
2523 } else {
2524 if (name)
2525 pstrcpy(sn->name, sizeof(sn->name), name);
2526 }
2527
2528 /* fill auxiliary fields */
2529#ifdef _WIN32
2530 _ftime(&tb);
2531 sn->date_sec = tb.time;
2532 sn->date_nsec = tb.millitm * 1000000;
2533#else
2534 gettimeofday(&tv, NULL);
2535 sn->date_sec = tv.tv_sec;
2536 sn->date_nsec = tv.tv_usec * 1000;
2537#endif
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +01002538 sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002539
2540 if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002541 monitor_printf(err, "Device %s does not support VM state snapshots\n",
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002542 bdrv_get_device_name(bs));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002543 goto the_end;
2544 }
2545
2546 /* save the VM state */
David 'Digit' Turner986acc92011-05-10 16:50:01 +02002547 f = qemu_fopen_bdrv(bs, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002548 if (!f) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002549 monitor_printf(err, "Could not open VM state file\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002550 goto the_end;
2551 }
2552 ret = qemu_savevm_state(f);
2553 vm_state_size = qemu_ftell(f);
2554 qemu_fclose(f);
2555 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002556 monitor_printf(err, "Error %d while writing VM\n", ret);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002557 goto the_end;
2558 }
2559
2560 /* create the snapshots */
2561
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002562 bs1 = NULL;
2563 while ((bs1 = bdrv_next(bs1))) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002564 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002565 if (must_delete) {
2566 ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
2567 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002568 monitor_printf(err,
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002569 "Error while deleting snapshot on '%s'\n",
2570 bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002571 }
2572 }
2573 /* Write VM state size only to the image that contains the state */
2574 sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
2575 ret = bdrv_snapshot_create(bs1, sn);
2576 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002577 monitor_printf(err, "Error while creating snapshot on '%s'\n",
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002578 bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002579 }
2580 }
2581 }
2582
2583 the_end:
2584 if (saved_vm_running)
2585 vm_start();
2586}
2587
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002588void do_loadvm(Monitor *err, const char *name)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002589{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002590 BlockDriverState *bs, *bs1;
2591 BlockDriverInfo bdi1, *bdi = &bdi1;
2592 QEMUSnapshotInfo sn;
2593 QEMUFile *f;
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002594 int ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002595 int saved_vm_running;
2596
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002597 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002598 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002599 monitor_printf(err, "No block device supports snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002600 return;
2601 }
2602
2603 /* Flush all IO requests so they don't interfere with the new state. */
2604 qemu_aio_flush();
2605
2606 saved_vm_running = vm_running;
2607 vm_stop(0);
2608
Vladimir Chtchetkine05e07482012-02-03 10:02:50 -08002609 bs1 = bs;
2610 do {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002611 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002612 ret = bdrv_snapshot_goto(bs1, name);
2613 if (ret < 0) {
2614 if (bs != bs1)
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002615 monitor_printf(err, "Warning: ");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002616 switch(ret) {
2617 case -ENOTSUP:
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002618 monitor_printf(err,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002619 "Snapshots not supported on device '%s'\n",
2620 bdrv_get_device_name(bs1));
2621 break;
2622 case -ENOENT:
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002623 monitor_printf(err, "Could not find snapshot '%s' on "
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002624 "device '%s'\n",
2625 name, bdrv_get_device_name(bs1));
2626 break;
2627 default:
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002628 monitor_printf(err, "Error %d while activating snapshot on"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002629 " '%s'\n", ret, bdrv_get_device_name(bs1));
2630 break;
2631 }
2632 /* fatal on snapshot block device */
2633 if (bs == bs1)
2634 goto the_end;
2635 }
2636 }
Vladimir Chtchetkine05e07482012-02-03 10:02:50 -08002637 } while ((bs1 = bdrv_next(bs)));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002638
2639 if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002640 monitor_printf(err, "Device %s does not support VM state snapshots\n",
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002641 bdrv_get_device_name(bs));
2642 return;
2643 }
2644
2645 /* Don't even try to load empty VM states */
2646 ret = bdrv_snapshot_find(bs, &sn, name);
2647 if ((ret >= 0) && (sn.vm_state_size == 0))
2648 goto the_end;
2649
2650 /* restore the VM state */
David 'Digit' Turner986acc92011-05-10 16:50:01 +02002651 f = qemu_fopen_bdrv(bs, 0);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002652 if (!f) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002653 monitor_printf(err, "Could not open VM state file\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002654 goto the_end;
2655 }
2656 ret = qemu_loadvm_state(f);
2657 qemu_fclose(f);
2658 if (ret < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002659 monitor_printf(err, "Error %d while loading VM state\n", ret);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002660 }
2661 the_end:
2662 if (saved_vm_running)
2663 vm_start();
2664}
2665
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002666void do_delvm(Monitor *err, const char *name)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002667{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002668 BlockDriverState *bs, *bs1;
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002669 int ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002670
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002671 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002672 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002673 monitor_printf(err, "No block device supports snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002674 return;
2675 }
2676
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002677 bs1 = NULL;
2678 while ((bs1 = bdrv_next(bs1))) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002679 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002680 ret = bdrv_snapshot_delete(bs1, name);
2681 if (ret < 0) {
2682 if (ret == -ENOTSUP)
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002683 monitor_printf(err,
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002684 "Snapshots not supported on device '%s'\n",
2685 bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002686 else
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002687 monitor_printf(err, "Error %d while deleting snapshot on "
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002688 "'%s'\n", ret, bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002689 }
2690 }
2691 }
2692}
2693
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002694void do_info_snapshots(Monitor* out, Monitor* err)
Ot ten Thije2ff39a32010-10-06 17:48:15 +01002695{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002696 BlockDriverState *bs, *bs1;
2697 QEMUSnapshotInfo *sn_tab, *sn;
2698 int nb_sns, i;
2699 char buf[256];
2700
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002701 bs = bdrv_snapshots();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002702 if (!bs) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002703 monitor_printf(err, "No available block device supports snapshots\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002704 return;
2705 }
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002706 monitor_printf(out, "Snapshot devices:");
David 'Digit' Turnercb42a1b2010-12-23 02:54:08 +01002707 bs1 = NULL;
2708 while ((bs1 = bdrv_next(bs1))) {
Ot ten Thije8f2de6d2010-09-30 14:17:10 +01002709 if (bdrv_can_snapshot(bs1)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002710 if (bs == bs1)
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002711 monitor_printf(out, " %s", bdrv_get_device_name(bs1));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002712 }
2713 }
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002714 monitor_printf(out, "\n");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002715
2716 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
2717 if (nb_sns < 0) {
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002718 monitor_printf(err, "bdrv_snapshot_list: error %d\n", nb_sns);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002719 return;
2720 }
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002721 monitor_printf(out, "Snapshot list (from %s):\n",
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002722 bdrv_get_device_name(bs));
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002723 monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002724 for(i = 0; i < nb_sns; i++) {
2725 sn = &sn_tab[i];
David 'Digit' Turner95a83ce2011-05-10 17:31:15 +02002726 monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002727 }
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +01002728 g_free(sn_tab);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002729}