savevm.c revision 34c48ff1e3ad5cd2084ca40188754d45f423750b
15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU System Emulator 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2003-2008 Fabrice Bellard 55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy 75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal 85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in the Software without restriction, including without limitation the rights 95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is 115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * furnished to do so, subject to the following conditions: 125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included in 145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * all copies or substantial portions of the Software. 155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE. 235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <unistd.h> 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <fcntl.h> 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <signal.h> 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <time.h> 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <errno.h> 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/time.h> 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <zlib.h> 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 322c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner/* Needed early for CONFIG_BSD etc. */ 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "config-host.h" 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/times.h> 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/wait.h> 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <termios.h> 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/mman.h> 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/ioctl.h> 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/resource.h> 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/socket.h> 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in.h> 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if.h> 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <arpa/inet.h> 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dirent.h> 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netdb.h> 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/select.h> 492c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner#ifdef CONFIG_BSD 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h> 51cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libutil.h> 535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <util.h> 555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__ 575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <pty.h> 585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h> 595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/rtc.h> 605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <windows.h> 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h> 675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/timeb.h> 685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <mmsystem.h> 695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define getopt_long_only getopt_long 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define memalign(align, size) malloc(size) 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h" 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/hw.h" 75cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turner#include "net/net.h" 766af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h" 7734c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/sysemu.h" 787a78db75ad42aea283f5073f51891464104a9fc3David 'Digit' Turner#include "qemu/timer.h" 795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-char.h" 8034c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/blockdev.h" 815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "block.h" 825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio/audio.h" 8328a09b6fe8d8f3e92ffee9263609a6da881b8818David 'Digit' Turner#include "migration/migration.h" 845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_socket.h" 85cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#include "qemu-queue.h" 8628a09b6fe8d8f3e92ffee9263609a6da881b8818David 'Digit' Turner#include "migration/qemu-file.h" 87622b8f4c760b8c4479d28430f978bad8bb9ea32cTim Baverstock#include "android/snapshot.h" 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SELF_ANNOUNCE_ROUNDS 5 91986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 92986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#ifndef ETH_P_RARP 93986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ETH_P_RARP 0x8035 94986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#endif 95986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_HTYPE_ETH 0x0001 96986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_PTYPE_IP 0x0800 97986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_OP_REQUEST_REV 0x3 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 995973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turnerstatic int announce_self_create(uint8_t *buf, 1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *mac_addr) 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 102986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* Ethernet header. */ 103986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf, 0xff, 6); /* destination MAC addr */ 104986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memcpy(buf + 6, mac_addr, 6); /* source MAC addr */ 105986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */ 106986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 107986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* RARP header. */ 108986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */ 109986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */ 110986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(buf + 18) = 6; /* hardware addr length (ethernet) */ 111986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(buf + 19) = 4; /* protocol addr length (IPv4) */ 112986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */ 113986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memcpy(buf + 22, mac_addr, 6); /* source hw addr */ 114986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf + 28, 0x00, 4); /* source protocol addr */ 115986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memcpy(buf + 32, mac_addr, 6); /* target hw addr */ 116986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf + 38, 0x00, 4); /* target protocol addr */ 117986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 118986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */ 119986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf + 42, 0x00, 18); 120986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 121986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return 60; /* len (FCS will be added by hardware) */ 1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_announce_self_once(void *opaque) 1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i, len; 1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner VLANState *vlan; 1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner VLANClientState *vc; 1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t buf[256]; 1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static int count = SELF_ANNOUNCE_ROUNDS; 1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUTimer *timer = *(QEMUTimer **)opaque; 1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < MAX_NICS; i++) { 1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!nd_table[i].used) 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = announce_self_create(buf, nd_table[i].macaddr); 1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vlan = nd_table[i].vlan; 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(vc = vlan->first_client; vc != NULL; vc = vc->next) { 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vc->receive(vc, buf, len); 1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 142986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (--count) { 143986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* delay 50ms, 150ms, 250ms, ... */ 144986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_mod_timer(timer, qemu_get_clock_ms(rt_clock) + 145986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100); 1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(timer); 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_timer(timer); 1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_announce_self(void) 1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static QEMUTimer *timer; 1555973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner timer = qemu_new_timer_ms(rt_clock, qemu_announce_self_once, &timer); 1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_announce_self_once(&timer); 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/ 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* savevm/loadvm support */ 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IO_BUF_SIZE 32768 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct QEMUFile { 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePutBufferFunc *put_buffer; 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileGetBufferFunc *get_buffer; 1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileCloseFunc *close; 1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileRateLimit *rate_limit; 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSetRateLimit *set_rate_limit; 170a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileGetRateLimit *get_rate_limit; 1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int is_write; 1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t buf_offset; /* start of buffer when writing, end of buffer 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner when reading */ 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_index; 1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_size; /* 0 when writing */ 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t buf[IO_BUF_SIZE]; 1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int has_error; 1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 183986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnertypedef struct QEMUFileStdio 1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 185986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner FILE *stdio_file; 1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 187986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} QEMUFileStdio; 1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFileSocket 1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFileSocket; 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 195986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ssize_t len; 1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = recv(s->fd, (void *)buf, size, 0); 2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (len == -1 && socket_error() == EINTR); 2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len == -1) 2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = -socket_error(); 2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return len; 2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_socket_close(void *opaque) 2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 217986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) 2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 219986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 220986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return fwrite(buf, 1, size, s->stdio_file); 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 223986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 225986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 226986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner FILE *fp = s->stdio_file; 2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int bytes; 2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner clearerr(fp); 2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bytes = fread(buf, 1, size, fp); 2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while ((bytes == 0) && ferror(fp) && (errno == EINTR)); 2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bytes; 2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 236986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_pclose(void *opaque) 2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 238986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 239986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner int ret; 240986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner ret = pclose(s->stdio_file); 241986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_free(s); 242986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return ret; 243986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 244986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 245986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_fclose(void *opaque) 246986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 247986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 248986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fclose(s->stdio_file); 2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 253986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' TurnerQEMUFile *qemu_popen(FILE *stdio_file, const char *mode) 2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 255986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s; 2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 257986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { 2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu_popen: Argument validity check failed\n"); 2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 262986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileStdio)); 2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 264986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = stdio_file; 2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(mode[0] == 'r') { 26795a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, 268986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 27095a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, 271986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->file; 2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_popen_cmd(const char *command, const char *mode) 2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FILE *popen_file; 2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner popen_file = popen(command, mode); 2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(popen_file == NULL) { 2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return qemu_popen(popen_file, mode); 2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 288986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint qemu_stdio_fd(QEMUFile *f) 2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 290986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *p; 2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 293986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner p = (QEMUFileStdio *)f->opaque; 294986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fd = fileno(p->stdio_file); 2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return fd; 2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 299986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' TurnerQEMUFile *qemu_fdopen(int fd, const char *mode) 300986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 301986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s; 302986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 303986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (mode == NULL || 304986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner (mode[0] != 'r' && mode[0] != 'w') || 305986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner mode[1] != 'b' || mode[2] != 0) { 306986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fprintf(stderr, "qemu_fdopen: Argument validity check failed\n"); 307986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 308986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 309986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 310986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileStdio)); 311986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = fdopen(fd, mode); 312986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (!s->stdio_file) 313986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner goto fail; 314986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 315986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if(mode[0] == 'r') { 31695a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, 317986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 318986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } else { 31995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, 320986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 321986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 322986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return s->file; 323986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 324986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerfail: 325986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_free(s); 326986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 327986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 328986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_socket(int fd) 3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket)); 3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->fd = fd; 33495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, file_socket_close, 335986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->file; 3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_put_buffer(void *opaque, const uint8_t *buf, 3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t pos, int size) 3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s = opaque; 343986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fseek(s->stdio_file, pos, SEEK_SET); 344986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return fwrite(buf, 1, size, s->stdio_file); 3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s = opaque; 350986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fseek(s->stdio_file, pos, SEEK_SET); 351986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return fread(buf, 1, size, s->stdio_file); 3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen(const char *filename, const char *mode) 3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s; 3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 358986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (mode == NULL || 359986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner (mode[0] != 'r' && mode[0] != 'w') || 360986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner mode[1] != 'b' || mode[2] != 0) { 361986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fprintf(stderr, "qemu_fopen: Argument validity check failed\n"); 362986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 363986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 364986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileStdio)); 3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 367986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = fopen(filename, mode); 368986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (!s->stdio_file) 3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto fail; 37095a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner 371986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if(mode[0] == 'w') { 37295a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, 373986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 374986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } else { 37595a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, 376986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 377986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 378986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return s->file; 3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfail: 3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_put_buffer(void *opaque, const uint8_t *buf, 3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t pos, int size) 3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 387986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner bdrv_save_vmstate(opaque, buf, pos, size); 3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size; 3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 393986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return bdrv_load_vmstate(opaque, buf, pos, size); 3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_fclose(void *opaque) 3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 401986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) 4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (is_writable) 40495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, 405986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 406986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL); 4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, 4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileGetBufferFunc *get_buffer, 4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileCloseFunc *close, 4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileRateLimit *rate_limit, 413a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileSetRateLimit *set_rate_limit, 414a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileGetRateLimit *get_rate_limit) 4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f = qemu_mallocz(sizeof(QEMUFile)); 4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->opaque = opaque; 4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->put_buffer = put_buffer; 4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->get_buffer = get_buffer; 4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->close = close; 4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->rate_limit = rate_limit; 4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->set_rate_limit = set_rate_limit; 426986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f->get_rate_limit = get_rate_limit; 4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 0; 4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f; 4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_has_error(QEMUFile *f) 4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->has_error; 4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_set_error(QEMUFile *f) 4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_fflush(QEMUFile *f) 4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->put_buffer) 4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write && f->buf_index > 0) { 4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); 4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 0) 4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset += f->buf_index; 4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_fill_buffer(QEMUFile *f) 4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->get_buffer) 4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE); 4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 0) { 4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_size = len; 4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset += len; 4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (len != -EAGAIN) 4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_fclose(QEMUFile *f) 4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 0; 4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->close) 4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = f->close(f->opaque); 4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(f); 4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_put_notify(QEMUFile *f) 4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->put_buffer(f->opaque, NULL, 0, 0); 4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) 4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int l; 4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { 4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, 4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Attempted to write to buffer while read buffer is not empty\n"); 5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (!f->has_error && size > 0) { 5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = IO_BUF_SIZE - f->buf_index; 5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l > size) 5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = size; 5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(f->buf + f->buf_index, buf, l); 5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 1; 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index += l; 5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner buf += l; 5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size -= l; 5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= IO_BUF_SIZE) 5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_byte(QEMUFile *f, int v) 5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { 5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, 5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Attempted to write to buffer while read buffer is not empty\n"); 5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf[f->buf_index++] = v; 5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 1; 5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= IO_BUF_SIZE) 5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1) 5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int size, l; 5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size = size1; 5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (size > 0) { 5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = f->buf_size - f->buf_index; 5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l == 0) { 5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fill_buffer(f); 5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = f->buf_size - f->buf_index; 5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l == 0) 5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l > size) 5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = size; 5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(buf, f->buf + f->buf_index, l); 5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index += l; 5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner buf += l; 5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size -= l; 5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size1 - size; 5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_byte(QEMUFile *f) 5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= f->buf_size) { 5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fill_buffer(f); 5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= f->buf_size) 5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->buf[f->buf_index++]; 5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5703e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner#ifdef CONFIG_ANDROID 5713e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnervoid qemu_put_string(QEMUFile *f, const char* str) 5723e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{ 5733e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner /* We will encode NULL and the empty string in the same way */ 5743e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner int slen; 5753e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (str == NULL) { 5763e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner str = ""; 5773e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } 5783e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner slen = strlen(str); 5793e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner qemu_put_be32(f, slen); 5803e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner qemu_put_buffer(f, (const uint8_t*)str, slen); 5813e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner} 5823e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 5833e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerchar* qemu_get_string(QEMUFile *f) 5843e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{ 5853e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner int slen = qemu_get_be32(f); 5863e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner char* str; 5873e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (slen == 0) 5883e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return NULL; 5893e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 5903e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner str = qemu_malloc(slen+1); 5913e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (qemu_get_buffer(f, (uint8_t*)str, slen) != slen) { 5923e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner qemu_free(str); 5933e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return NULL; 5943e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } 5953e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner str[slen] = '\0'; 5963e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return str; 5973e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner} 5983e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner#endif 5993e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 6003e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_ftell(QEMUFile *f) 6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->buf_offset - f->buf_size + f->buf_index; 6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) 6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (whence == SEEK_SET) { 6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* nothing to do */ 6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (whence == SEEK_CUR) { 6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pos += qemu_ftell(f); 6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* SEEK_END not supported */ 6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->put_buffer) { 6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset = pos; 6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset = pos; 6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_size = 0; 6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return pos; 6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_rate_limit(QEMUFile *f) 6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->rate_limit) 6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->rate_limit(f->opaque); 6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 635986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint64_t qemu_file_get_rate_limit(QEMUFile *f) 636986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 637986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (f->get_rate_limit) 638986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return f->get_rate_limit(f->opaque); 639986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 640986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return 0; 641986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 642986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 643986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate) 6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 645986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* any failed or completed migration keeps its state to allow probing of 646986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner * migration data, but has no associated file anymore */ 647986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (f && f->set_rate_limit) 6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->set_rate_limit(f->opaque, new_rate); 6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be16(QEMUFile *f, unsigned int v) 6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be32(QEMUFile *f, unsigned int v) 6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 24); 6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 16); 6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be64(QEMUFile *f, uint64_t v) 6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v >> 32); 6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v); 6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be16(QEMUFile *f) 6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 8; 6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be32(QEMUFile *f) 6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 24; 6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 16; 6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 8; 6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint64_t qemu_get_be64(QEMUFile *f) 6925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t v; 6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = (uint64_t)qemu_get_be32(f) << 32; 6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_be32(f); 6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_struct(QEMUFile* f, const QField* fields, const void* s) 7005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7037fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 7047fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, p[0]); 7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be16(f, ((uint16_t*)p)[0]); 7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, ((uint32_t*)p)[0]); 7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be64(f, ((uint64_t*)p)[0]); 7195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 7217fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 7227fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n", 7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7307fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, p, size); 7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 7375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_struct(QEMUFile* f, const QField* fields, void* s) 7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7487fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 7497fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p[0] = qemu_get_byte(f); 7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint16_t*)p)[0] = qemu_get_be16(f); 7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint32_t*)p)[0] = qemu_get_be32(f); 7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t*)p)[0] = qemu_get_be64(f); 7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 7667fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 7677fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n", 7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7757fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = qemu_get_buffer(f, p, size); 7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret != size) { 7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__); 7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 794871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* write a float to file */ 795871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijevoid qemu_put_float(QEMUFile *f, float v) 796871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 797871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t *bytes = (uint8_t*) &v; 798871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_put_buffer(f, bytes, sizeof(float)); 799871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 800871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 801871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* read a float from file */ 802871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijefloat qemu_get_float(QEMUFile *f) 803871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 804871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t bytes[sizeof(float)]; 805871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_get_buffer(f, bytes, sizeof(float)); 806871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 807871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije return *((float*) bytes); 808871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 809871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct SaveStateEntry { 8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id; 8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state; 8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state; 8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state; 8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct SaveStateEntry *next; 8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} SaveStateEntry; 8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *first_se; 8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* TODO: Individual devices generally have very little idea about the rest 8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner of the system, so instance_id should be removed/replaced. 8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner Meanwhile pass -1 as instance_id if you do not already have a clearly 8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner distinguishing id for all instances of your device class. */ 8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm_live(const char *idstr, 8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state, 8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se, **pse; 8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static int global_section_id; 8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = qemu_malloc(sizeof(SaveStateEntry)); 8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(se->idstr, sizeof(se->idstr), idstr); 8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (instance_id == -1) ? 0 : instance_id; 8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->version_id = version_id; 8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->section_id = global_section_id++; 8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state = save_live_state; 8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state = save_state; 8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->load_state = load_state; 8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->opaque = opaque; 8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->next = NULL; 8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* add at the end of list */ 8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (instance_id == -1 8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && strcmp(se->idstr, (*pse)->idstr) == 0 8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && se->instance_id <= (*pse)->instance_id) 8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (*pse)->instance_id + 1; 8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = se; 8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm(const char *idstr, 8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return register_savevm_live(idstr, instance_id, version_id, 8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner NULL, save_state, load_state, opaque); 8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid unregister_savevm(const char *idstr, void *opaque) 8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry **pse; 8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) { 8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *next = (*pse)->next; 8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(*pse); 8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = next; 8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_MAGIC 0x5145564d 8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 8923e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner#define QEMU_VM_FILE_VERSION 0x00000004 8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_EOF 0x00 8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_START 0x01 8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_PART 0x02 8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_END 0x03 8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_FULL 0x04 8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_begin(QEMUFile *f) 9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_MAGIC); 9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_VERSION); 9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_START); 9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); 9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_iterate(QEMUFile *f) 9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 1; 9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_PART); 9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); 9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret) 9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 1; 9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_complete(QEMUFile *f) 9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_END); 9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); 9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9778f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (se->save_state == NULL) 9788f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije continue; 9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_FULL); 9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state(f, se->opaque); 9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_EOF); 9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state(QEMUFile *f) 10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_flush_all(); 10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_begin(f); 10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_iterate(f); 10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (ret == 0); 10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_complete(f); 10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EIO; 10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!ret && saved_vm_running) 10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *find_se(const char *idstr, int instance_id) 10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(se->idstr, idstr) && 10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id == se->instance_id) 10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return se; 10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct LoadStateEntry { 10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct LoadStateEntry *next; 10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} LoadStateEntry; 10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int qemu_loadvm_state_v2(QEMUFile *f) 10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len, ret, instance_id, record_len, version_id; 10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t total_len, end_pos, cur_pos; 10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner total_len = qemu_get_be64(f); 10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner end_pos = total_len + qemu_ftell(f); 10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(;;) { 10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_ftell(f) >= end_pos) 10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = '\0'; 10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner record_len = qemu_get_be32(f); 10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cur_pos = qemu_ftell(f); 10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!se) { 10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", 10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = se->load_state(f, se->opaque, version_id); 10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", 10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* always seek to exact end of record */ 10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fseek(f, cur_pos + record_len, SEEK_SET); 10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_loadvm_state(QEMUFile *f) 10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *first_le = NULL; 10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t section_type; 10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v != QEMU_VM_FILE_MAGIC) 11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EINVAL; 11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v == QEMU_VM_FILE_VERSION_COMPAT) 11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return qemu_loadvm_state_v2(f); 11093e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (v < QEMU_VM_FILE_VERSION) { 11103e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner fprintf(stderr, "Snapshot format %d is too old for this version of the emulator, please create a new one.\n", v); 11113e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return -ENOTSUP; 11123e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } else if (v > QEMU_VM_FILE_VERSION) { 11133e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner fprintf(stderr, "Snapshot format %d is more recent than the emulator, please update your Android SDK Tools.\n", v); 11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENOTSUP; 11153e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } 11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { 11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t instance_id, version_id, section_id; 11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le; 11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[257]; 11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (section_type) { 11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_START: 11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_FULL: 11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Read section start */ 11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = 0; 11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Find savevm section */ 11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se == NULL) { 11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id); 11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Validate version */ 11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (version_id > se->version_id) { 11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n", 11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id, idstr, se->version_id); 11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Add entry */ 11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le = qemu_mallocz(sizeof(*le)); 11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se = se; 11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->section_id = section_id; 11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->version_id = version_id; 11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->next = first_le; 11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = le; 11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1160d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine if (le->se->load_state(f, le->se->opaque, le->version_id)) { 1161d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine fprintf(stderr, "savevm: unable to load section %s\n", idstr); 1162d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine ret = -EINVAL; 1163d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine goto out; 1164d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine } 11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_PART: 11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_END: 11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (le = first_le; le && le->section_id != section_id; le = le->next); 11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (le == NULL) { 11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section %d\n", section_id); 11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se->load_state(f, le->se->opaque, le->version_id); 11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section type %d\n", section_type); 11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (first_le) { 11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le = first_le; 11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = first_le->next; 11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(le); 11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EIO; 11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1200cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if 0 12015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriverState *get_bs_snapshots(void) 12025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs; 12045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 12055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs_snapshots) 12075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs_snapshots; 12085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i <= nb_drives; i++) { 12095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = drives_table[i].bdrv; 12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_can_snapshot(bs)) 12115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto ok; 12125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 12145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ok: 12155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs_snapshots = bs; 12165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs; 12175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1218cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#endif 12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, 12205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *name) 12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i, ret; 12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -ENOENT; 12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) 12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 12315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { 12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *sn_info = *sn; 12335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(sn_tab); 12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 124195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_savevm(Monitor *err, const char *name) 12422ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 12445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; 1245cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int must_delete, ret; 12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t vm_state_size; 12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct _timeb tb; 12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct timeval tv; 12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1256cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 125895a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No block device can accept snapshots\n"); 12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ??? Should this occur after vm_stop? */ 12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 12665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 0; 12695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) { 12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, old_sn, name); 12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret >= 0) { 12725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 1; 12735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(sn, 0, sizeof(*sn)); 12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), old_sn->name); 12785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); 12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 12805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) 12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), name); 12825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fill auxiliary fields */ 12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner _ftime(&tb); 12875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tb.time; 12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tb.millitm * 1000000; 12895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 12905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner gettimeofday(&tv, NULL); 12915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tv.tv_sec; 12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tv.tv_usec * 1000; 12935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 12945973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); 12955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 129795a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Device %s does not support VM state snapshots\n", 12982ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs)); 12995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* save the VM state */ 1303986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f = qemu_fopen_bdrv(bs, 1); 13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 130595a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Could not open VM state file\n"); 13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state(f); 13095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_state_size = qemu_ftell(f); 13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 131295a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while writing VM\n", ret); 13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* create the snapshots */ 13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1318cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1319cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 13208f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 13215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 13225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, old_sn->id_str); 13235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 132495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, 13252ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "Error while deleting snapshot on '%s'\n", 13262ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 13275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Write VM state size only to the image that contains the state */ 13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->vm_state_size = (bs == bs1 ? vm_state_size : 0); 13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_create(bs1, sn); 13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 133395a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error while creating snapshot on '%s'\n", 13342ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 134495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_loadvm(Monitor *err, const char *name) 13452ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 13485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn; 13495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 1350cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int ret; 13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1353cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 13545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 135595a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No block device supports snapshots\n"); 13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 13575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Flush all IO requests so they don't interfere with the new state. */ 13605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 136505e074899c900b99adca7b37eee19a4ddc090e38Vladimir Chtchetkine bs1 = bs; 136605e074899c900b99adca7b37eee19a4ddc090e38Vladimir Chtchetkine do { 13678f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_goto(bs1, name); 13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs != bs1) 137195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Warning: "); 13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch(ret) { 13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOTSUP: 137495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, 13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Snapshots not supported on device '%s'\n", 13765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs1)); 13775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOENT: 137995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Could not find snapshot '%s' on " 13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "device '%s'\n", 13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner name, bdrv_get_device_name(bs1)); 13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 138495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while activating snapshot on" 13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner " '%s'\n", ret, bdrv_get_device_name(bs1)); 13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fatal on snapshot block device */ 13895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 13905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 139305e074899c900b99adca7b37eee19a4ddc090e38Vladimir Chtchetkine } while ((bs1 = bdrv_next(bs))); 13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 139695a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Device %s does not support VM state snapshots\n", 13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 13985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Don't even try to load empty VM states */ 14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, &sn, name); 14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((ret >= 0) && (sn.vm_state_size == 0)) 14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* restore the VM state */ 1407986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f = qemu_fopen_bdrv(bs, 0); 14085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 140995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Could not open VM state file\n"); 14105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 14115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_loadvm_state(f); 14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 14145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 141595a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while loading VM state\n", ret); 14165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 14185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 142295a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_delvm(Monitor *err, const char *name) 14232ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 14245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 1425cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int ret; 14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1427cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 14285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 142995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No block device supports snapshots\n"); 14305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1433cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1434cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 14358f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, name); 14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret == -ENOTSUP) 143995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, 14402ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "Snapshots not supported on device '%s'\n", 14412ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 14425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 144395a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while deleting snapshot on " 14442ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "'%s'\n", ret, bdrv_get_device_name(bs1)); 14455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 145095a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_info_snapshots(Monitor* out, Monitor* err) 14512ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 14535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 14545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i; 14555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char buf[256]; 14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1457cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 14585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 145995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No available block device supports snapshots\n"); 14605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 146295a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "Snapshot devices:"); 1463cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1464cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 14658f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 14665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 146795a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, " %s", bdrv_get_device_name(bs1)); 14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 147095a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "\n"); 14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 14735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) { 147495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "bdrv_snapshot_list: error %d\n", nb_sns); 14755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 147795a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "Snapshot list (from %s):\n", 14785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 147995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); 14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 148295a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); 14835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(sn_tab); 14855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1486