savevm.c revision 986acc9eba2cf7c9b468c2f84764fa478907ac66
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" 755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "net.h" 765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "monitor.h" 775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sysemu.h" 785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-timer.h" 795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-char.h" 80cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#include "blockdev.h" 812ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije#include "outputchannel.h" 825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "block.h" 835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio/audio.h" 845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "migration.h" 855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_socket.h" 86cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#include "qemu-queue.h" 875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_file.h" 88622b8f4c760b8c4479d28430f978bad8bb9ea32cTim Baverstock#include "android/snapshot.h" 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SELF_ANNOUNCE_ROUNDS 5 92986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 93986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#ifndef ETH_P_RARP 94986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ETH_P_RARP 0x8035 95986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#endif 96986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_HTYPE_ETH 0x0001 97986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_PTYPE_IP 0x0800 98986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_OP_REQUEST_REV 0x3 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1005973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turnerstatic int announce_self_create(uint8_t *buf, 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *mac_addr) 1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 103986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* Ethernet header. */ 104986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf, 0xff, 6); /* destination MAC addr */ 105986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memcpy(buf + 6, mac_addr, 6); /* source MAC addr */ 106986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */ 107986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 108986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* RARP header. */ 109986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */ 110986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */ 111986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(buf + 18) = 6; /* hardware addr length (ethernet) */ 112986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(buf + 19) = 4; /* protocol addr length (IPv4) */ 113986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */ 114986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memcpy(buf + 22, mac_addr, 6); /* source hw addr */ 115986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf + 28, 0x00, 4); /* source protocol addr */ 116986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memcpy(buf + 32, mac_addr, 6); /* target hw addr */ 117986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf + 38, 0x00, 4); /* target protocol addr */ 118986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 119986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */ 120986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner memset(buf + 42, 0x00, 18); 121986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 122986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return 60; /* len (FCS will be added by hardware) */ 1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_announce_self_once(void *opaque) 1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i, len; 1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner VLANState *vlan; 1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner VLANClientState *vc; 1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t buf[256]; 1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static int count = SELF_ANNOUNCE_ROUNDS; 1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUTimer *timer = *(QEMUTimer **)opaque; 1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < MAX_NICS; i++) { 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!nd_table[i].used) 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = announce_self_create(buf, nd_table[i].macaddr); 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vlan = nd_table[i].vlan; 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(vc = vlan->first_client; vc != NULL; vc = vc->next) { 1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vc->receive(vc, buf, len); 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 143986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (--count) { 144986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* delay 50ms, 150ms, 250ms, ... */ 145986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_mod_timer(timer, qemu_get_clock_ms(rt_clock) + 146986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100); 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(timer); 1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_timer(timer); 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_announce_self(void) 1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static QEMUTimer *timer; 1565973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner timer = qemu_new_timer_ms(rt_clock, qemu_announce_self_once, &timer); 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_announce_self_once(&timer); 1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/ 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* savevm/loadvm support */ 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IO_BUF_SIZE 32768 1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct QEMUFile { 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePutBufferFunc *put_buffer; 1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileGetBufferFunc *get_buffer; 1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileCloseFunc *close; 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileRateLimit *rate_limit; 1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSetRateLimit *set_rate_limit; 171a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileGetRateLimit *get_rate_limit; 1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int is_write; 1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t buf_offset; /* start of buffer when writing, end of buffer 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner when reading */ 1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_index; 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_size; /* 0 when writing */ 1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t buf[IO_BUF_SIZE]; 1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int has_error; 1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 184986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnertypedef struct QEMUFileStdio 1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 186986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner FILE *stdio_file; 1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 188986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} QEMUFileStdio; 1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFileSocket 1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFileSocket; 1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 196986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ssize_t len; 2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = recv(s->fd, (void *)buf, size, 0); 2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (len == -1 && socket_error() == EINTR); 2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len == -1) 2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = -socket_error(); 2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return len; 2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_socket_close(void *opaque) 2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 218986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) 2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 220986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 221986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return fwrite(buf, 1, size, s->stdio_file); 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 224986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 226986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 227986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner FILE *fp = s->stdio_file; 2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int bytes; 2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner clearerr(fp); 2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bytes = fread(buf, 1, size, fp); 2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while ((bytes == 0) && ferror(fp) && (errno == EINTR)); 2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bytes; 2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 237986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_pclose(void *opaque) 2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 239986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 240986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner int ret; 241986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner ret = pclose(s->stdio_file); 242986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_free(s); 243986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return ret; 244986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 245986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 246986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_fclose(void *opaque) 247986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 248986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 249986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fclose(s->stdio_file); 2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 254986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' TurnerQEMUFile *qemu_popen(FILE *stdio_file, const char *mode) 2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 256986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s; 2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 258986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { 2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu_popen: Argument validity check failed\n"); 2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 263986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileStdio)); 2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 265986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = stdio_file; 2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(mode[0] == 'r') { 268986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, 269986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 271986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, 272986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->file; 2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_popen_cmd(const char *command, const char *mode) 2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FILE *popen_file; 2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner popen_file = popen(command, mode); 2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(popen_file == NULL) { 2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return qemu_popen(popen_file, mode); 2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 289986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint qemu_stdio_fd(QEMUFile *f) 2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 291986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *p; 2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 294986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner p = (QEMUFileStdio *)f->opaque; 295986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fd = fileno(p->stdio_file); 2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return fd; 2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 300986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' TurnerQEMUFile *qemu_fdopen(int fd, const char *mode) 301986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 302986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s; 303986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 304986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (mode == NULL || 305986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner (mode[0] != 'r' && mode[0] != 'w') || 306986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner mode[1] != 'b' || mode[2] != 0) { 307986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fprintf(stderr, "qemu_fdopen: Argument validity check failed\n"); 308986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 309986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 310986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 311986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileStdio)); 312986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = fdopen(fd, mode); 313986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (!s->stdio_file) 314986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner goto fail; 315986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 316986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if(mode[0] == 'r') { 317986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, 318986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 319986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } else { 320986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, 321986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 322986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 323986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return s->file; 324986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 325986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerfail: 326986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_free(s); 327986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 328986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 329986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_socket(int fd) 3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket)); 3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->fd = fd; 335986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, file_socket_close, 336986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->file; 3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_put_buffer(void *opaque, const uint8_t *buf, 3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t pos, int size) 3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s = opaque; 344986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fseek(s->stdio_file, pos, SEEK_SET); 345986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return fwrite(buf, 1, size, s->stdio_file); 3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s = opaque; 351986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fseek(s->stdio_file, pos, SEEK_SET); 352986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return fread(buf, 1, size, s->stdio_file); 3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen(const char *filename, const char *mode) 3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s; 3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 359986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (mode == NULL || 360986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner (mode[0] != 'r' && mode[0] != 'w') || 361986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner mode[1] != 'b' || mode[2] != 0) { 362986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fprintf(stderr, "qemu_fopen: Argument validity check failed\n"); 363986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 364986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 365986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileStdio)); 3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 368986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = fopen(filename, mode); 369986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (!s->stdio_file) 3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto fail; 371986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 372986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if(mode[0] == 'w') { 373986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, 374986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 375986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } else { 376986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, 377986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 378986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 379986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return s->file; 3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfail: 3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_put_buffer(void *opaque, const uint8_t *buf, 3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t pos, int size) 3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 388986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner bdrv_save_vmstate(opaque, buf, pos, size); 3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size; 3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 394986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return bdrv_load_vmstate(opaque, buf, pos, size); 3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_fclose(void *opaque) 3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 402986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) 4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (is_writable) 405986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, 406986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner NULL, NULL, NULL); 407986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL); 4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, 4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileGetBufferFunc *get_buffer, 4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileCloseFunc *close, 4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileRateLimit *rate_limit, 414a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileSetRateLimit *set_rate_limit, 415a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileGetRateLimit *get_rate_limit) 4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f = qemu_mallocz(sizeof(QEMUFile)); 4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->opaque = opaque; 4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->put_buffer = put_buffer; 4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->get_buffer = get_buffer; 4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->close = close; 4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->rate_limit = rate_limit; 4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->set_rate_limit = set_rate_limit; 427986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f->get_rate_limit = get_rate_limit; 4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 0; 4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f; 4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_has_error(QEMUFile *f) 4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->has_error; 4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_set_error(QEMUFile *f) 4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_fflush(QEMUFile *f) 4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->put_buffer) 4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write && f->buf_index > 0) { 4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); 4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 0) 4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset += f->buf_index; 4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_fill_buffer(QEMUFile *f) 4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->get_buffer) 4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE); 4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 0) { 4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_size = len; 4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset += len; 4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (len != -EAGAIN) 4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_fclose(QEMUFile *f) 4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 0; 4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->close) 4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = f->close(f->opaque); 4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(f); 4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_put_notify(QEMUFile *f) 4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->put_buffer(f->opaque, NULL, 0, 0); 4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) 4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int l; 4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { 4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, 5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Attempted to write to buffer while read buffer is not empty\n"); 5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (!f->has_error && size > 0) { 5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = IO_BUF_SIZE - f->buf_index; 5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l > size) 5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = size; 5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(f->buf + f->buf_index, buf, l); 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 1; 5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index += l; 5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner buf += l; 5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size -= l; 5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= IO_BUF_SIZE) 5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_byte(QEMUFile *f, int v) 5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { 5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, 5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Attempted to write to buffer while read buffer is not empty\n"); 5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf[f->buf_index++] = v; 5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 1; 5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= IO_BUF_SIZE) 5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1) 5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int size, l; 5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size = size1; 5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (size > 0) { 5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = f->buf_size - f->buf_index; 5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l == 0) { 5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fill_buffer(f); 5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = f->buf_size - f->buf_index; 5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l == 0) 5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l > size) 5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = size; 5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(buf, f->buf + f->buf_index, l); 5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index += l; 5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner buf += l; 5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size -= l; 5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size1 - size; 5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_byte(QEMUFile *f) 5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= f->buf_size) { 5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fill_buffer(f); 5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= f->buf_size) 5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->buf[f->buf_index++]; 5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_ftell(QEMUFile *f) 5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->buf_offset - f->buf_size + f->buf_index; 5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) 5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (whence == SEEK_SET) { 5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* nothing to do */ 5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (whence == SEEK_CUR) { 5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pos += qemu_ftell(f); 5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* SEEK_END not supported */ 5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->put_buffer) { 5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset = pos; 5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset = pos; 5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_size = 0; 5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return pos; 5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_rate_limit(QEMUFile *f) 5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->rate_limit) 6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->rate_limit(f->opaque); 6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 605986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint64_t qemu_file_get_rate_limit(QEMUFile *f) 606986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 607986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (f->get_rate_limit) 608986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return f->get_rate_limit(f->opaque); 609986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 610986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return 0; 611986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 612986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 613986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate) 6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 615986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner /* any failed or completed migration keeps its state to allow probing of 616986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner * migration data, but has no associated file anymore */ 617986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (f && f->set_rate_limit) 6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->set_rate_limit(f->opaque, new_rate); 6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be16(QEMUFile *f, unsigned int v) 6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be32(QEMUFile *f, unsigned int v) 6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 24); 6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 16); 6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be64(QEMUFile *f, uint64_t v) 6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v >> 32); 6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v); 6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be16(QEMUFile *f) 6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 8; 6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be32(QEMUFile *f) 6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 24; 6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 16; 6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 8; 6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint64_t qemu_get_be64(QEMUFile *f) 6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t v; 6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = (uint64_t)qemu_get_be32(f) << 32; 6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_be32(f); 6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_struct(QEMUFile* f, const QField* fields, const void* s) 6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6737fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 6747fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, p[0]); 6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be16(f, ((uint16_t*)p)[0]); 6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, ((uint32_t*)p)[0]); 6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be64(f, ((uint64_t*)p)[0]); 6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 6917fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 6927fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n", 6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 6995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7007fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, p, size); 7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_struct(QEMUFile* f, const QField* fields, void* s) 7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7187fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 7197fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p[0] = qemu_get_byte(f); 7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint16_t*)p)[0] = qemu_get_be16(f); 7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint32_t*)p)[0] = qemu_get_be32(f); 7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t*)p)[0] = qemu_get_be64(f); 7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 7367fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 7377fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n", 7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7457fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = qemu_get_buffer(f, p, size); 7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret != size) { 7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__); 7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 764871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* write a float to file */ 765871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijevoid qemu_put_float(QEMUFile *f, float v) 766871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 767871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t *bytes = (uint8_t*) &v; 768871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_put_buffer(f, bytes, sizeof(float)); 769871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 770871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 771871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* read a float from file */ 772871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijefloat qemu_get_float(QEMUFile *f) 773871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 774871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t bytes[sizeof(float)]; 775871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_get_buffer(f, bytes, sizeof(float)); 776871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 777871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije return *((float*) bytes); 778871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 779871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct SaveStateEntry { 7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id; 7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state; 7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state; 7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state; 7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct SaveStateEntry *next; 7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} SaveStateEntry; 7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *first_se; 7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* TODO: Individual devices generally have very little idea about the rest 7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner of the system, so instance_id should be removed/replaced. 7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner Meanwhile pass -1 as instance_id if you do not already have a clearly 7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner distinguishing id for all instances of your device class. */ 7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm_live(const char *idstr, 7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state, 8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se, **pse; 8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static int global_section_id; 8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = qemu_malloc(sizeof(SaveStateEntry)); 8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(se->idstr, sizeof(se->idstr), idstr); 8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (instance_id == -1) ? 0 : instance_id; 8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->version_id = version_id; 8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->section_id = global_section_id++; 8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state = save_live_state; 8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state = save_state; 8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->load_state = load_state; 8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->opaque = opaque; 8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->next = NULL; 8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* add at the end of list */ 8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (instance_id == -1 8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && strcmp(se->idstr, (*pse)->idstr) == 0 8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && se->instance_id <= (*pse)->instance_id) 8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (*pse)->instance_id + 1; 8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = se; 8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm(const char *idstr, 8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return register_savevm_live(idstr, instance_id, version_id, 8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner NULL, save_state, load_state, opaque); 8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid unregister_savevm(const char *idstr, void *opaque) 8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry **pse; 8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) { 8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *next = (*pse)->next; 8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(*pse); 8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = next; 8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_MAGIC 0x5145564d 8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION 0x00000003 8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_EOF 0x00 8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_START 0x01 8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_PART 0x02 8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_END 0x03 8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_FULL 0x04 8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_begin(QEMUFile *f) 8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_MAGIC); 8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_VERSION); 8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_START); 8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); 8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_iterate(QEMUFile *f) 9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 1; 9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 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_PART); 9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); 9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret) 9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 1; 9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_complete(QEMUFile *f) 9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_END); 9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); 9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9478f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (se->save_state == NULL) 9488f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije continue; 9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_FULL); 9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state(f, se->opaque); 9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_EOF); 9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state(QEMUFile *f) 9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_flush_all(); 9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_begin(f); 9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_iterate(f); 9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (ret == 0); 9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_complete(f); 9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EIO; 9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!ret && saved_vm_running) 10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *find_se(const char *idstr, int instance_id) 10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(se->idstr, idstr) && 10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id == se->instance_id) 10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return se; 10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct LoadStateEntry { 10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct LoadStateEntry *next; 10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} LoadStateEntry; 10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int qemu_loadvm_state_v2(QEMUFile *f) 10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len, ret, instance_id, record_len, version_id; 10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t total_len, end_pos, cur_pos; 10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner total_len = qemu_get_be64(f); 10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner end_pos = total_len + qemu_ftell(f); 10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(;;) { 10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_ftell(f) >= end_pos) 10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = '\0'; 10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner record_len = qemu_get_be32(f); 10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cur_pos = qemu_ftell(f); 10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!se) { 10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", 10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = se->load_state(f, se->opaque, version_id); 10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", 10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* always seek to exact end of record */ 10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fseek(f, cur_pos + record_len, SEEK_SET); 10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_loadvm_state(QEMUFile *f) 10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *first_le = NULL; 10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t section_type; 10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v != QEMU_VM_FILE_MAGIC) 10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EINVAL; 10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v == QEMU_VM_FILE_VERSION_COMPAT) 10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return qemu_loadvm_state_v2(f); 10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v != QEMU_VM_FILE_VERSION) 10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENOTSUP; 10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { 10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t instance_id, version_id, section_id; 10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le; 10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[257]; 10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (section_type) { 10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_START: 10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_FULL: 10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Read section start */ 10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = 0; 10975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Find savevm section */ 11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se == NULL) { 11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id); 11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Validate version */ 11095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (version_id > se->version_id) { 11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n", 11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id, idstr, se->version_id); 11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Add entry */ 11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le = qemu_mallocz(sizeof(*le)); 11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se = se; 11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->section_id = section_id; 11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->version_id = version_id; 11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->next = first_le; 11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = le; 11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se->load_state(f, le->se->opaque, le->version_id); 11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_PART: 11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_END: 11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (le = first_le; le && le->section_id != section_id; le = le->next); 11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (le == NULL) { 11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section %d\n", section_id); 11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se->load_state(f, le->se->opaque, le->version_id); 11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 11415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section type %d\n", section_type); 11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (first_le) { 11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le = first_le; 11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = first_le->next; 11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(le); 11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EIO; 11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1161cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if 0 11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriverState *get_bs_snapshots(void) 11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs; 11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs_snapshots) 11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs_snapshots; 11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i <= nb_drives; i++) { 11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = drives_table[i].bdrv; 11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_can_snapshot(bs)) 11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto ok; 11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ok: 11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs_snapshots = bs; 11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs; 11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1179cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#endif 11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, 11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *name) 11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i, ret; 11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -ENOENT; 11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) 11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { 11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *sn_info = *sn; 11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(sn_tab); 11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 12005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12022ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijestatic int 12032ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijemonitor_output_channel_cb(void* opaque, const char* fmt, va_list ap) 12042ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 12052ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije return monitor_vprintf((Monitor*) opaque, fmt, ap); 12062ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije} 12072ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije 12082ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije 12095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_savevm(Monitor *mon, const char *name) 12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12112ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb); 12122ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije do_savevm_oc(oc, name); 12132ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_free(oc); 12142ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije} 12152ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije 12162ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_savevm_oc(OutputChannel *err, const char *name) 12172ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 12185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; 1220cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int must_delete, ret; 12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t vm_state_size; 12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct _timeb tb; 12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct timeval tv; 12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1231cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 12332ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "No block device can accept snapshots\n"); 12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ??? Should this occur after vm_stop? */ 12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 0; 12445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) { 12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, old_sn, name); 12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret >= 0) { 12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 1; 12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(sn, 0, sizeof(*sn)); 12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), old_sn->name); 12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); 12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) 12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), name); 12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fill auxiliary fields */ 12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner _ftime(&tb); 12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tb.time; 12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tb.millitm * 1000000; 12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner gettimeofday(&tv, NULL); 12665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tv.tv_sec; 12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tv.tv_usec * 1000; 12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 12695973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); 12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 12722ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Device %s does not support VM state snapshots\n", 12732ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs)); 12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 12755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* save the VM state */ 1278986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f = qemu_fopen_bdrv(bs, 1); 12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 12802ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Could not open VM state file\n"); 12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 12825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state(f); 12845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_state_size = qemu_ftell(f); 12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 12872ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Error %d while writing VM\n", ret); 12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 12895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* create the snapshots */ 12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1293cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1294cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 12958f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 12975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, old_sn->id_str); 12985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 12992ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, 13002ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "Error while deleting snapshot on '%s'\n", 13012ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Write VM state size only to the image that contains the state */ 13055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->vm_state_size = (bs == bs1 ? vm_state_size : 0); 13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_create(bs1, sn); 13075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 13082ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Error while creating snapshot on '%s'\n", 13092ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_loadvm(Monitor *mon, const char *name) 13205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13212ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb); 1322622b8f4c760b8c4479d28430f978bad8bb9ea32cTim Baverstock android_snapshot_update_time_request = 1; 13232ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije do_loadvm_oc(oc, name); 13242ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_free(oc); 13252ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije} 13262ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije 13272ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_loadvm_oc(OutputChannel *err, const char *name) 13282ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn; 13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 1333cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int ret; 13345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1336cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 13382ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "No block device supports snapshots\n"); 13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Flush all IO requests so they don't interfere with the new state. */ 13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 13445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1348cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1349cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs))) { 13508f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_goto(bs1, name); 13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 13535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs != bs1) 13542ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Warning: "); 13555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch(ret) { 13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOTSUP: 13572ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, 13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Snapshots not supported on device '%s'\n", 13595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs1)); 13605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOENT: 13622ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Could not find snapshot '%s' on " 13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "device '%s'\n", 13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner name, bdrv_get_device_name(bs1)); 13655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 13672ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Error %d while activating snapshot on" 13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner " '%s'\n", ret, bdrv_get_device_name(bs1)); 13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fatal on snapshot block device */ 13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 13792ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Device %s does not support VM state snapshots\n", 13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Don't even try to load empty VM states */ 13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, &sn, name); 13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((ret >= 0) && (sn.vm_state_size == 0)) 13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* restore the VM state */ 1390986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f = qemu_fopen_bdrv(bs, 0); 13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 13922ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Could not open VM state file\n"); 13935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_loadvm_state(f); 13965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 13982ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Error %d while loading VM state\n", ret); 13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_delvm(Monitor *mon, const char *name) 14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14072ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb); 14082ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije do_delvm_oc(oc, name); 14092ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_free(oc); 14102ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije} 14112ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_delvm_oc(OutputChannel *err, const char *name) 14122ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 1414cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int ret; 14155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1416cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 14182ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "No block device supports snapshots\n"); 14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1422cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1423cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 14248f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, name); 14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret == -ENOTSUP) 14282ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, 14292ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "Snapshots not supported on device '%s'\n", 14302ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 14322ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "Error %d while deleting snapshot on " 14332ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "'%s'\n", ret, bdrv_get_device_name(bs1)); 14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_info_snapshots(Monitor *mon) 14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14412ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb); 14422ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije do_info_snapshots_oc(oc, oc); 14432ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_free(oc); 14442ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije} 14452ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije 14462ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_info_snapshots_oc(OutputChannel *out, OutputChannel *err) 14472ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i; 14515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char buf[256]; 14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1453cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 14545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 14552ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "No available block device supports snapshots\n"); 14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14582ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(out, "Snapshot devices:"); 1459cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1460cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 14618f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 14625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 14632ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(out, " %s", bdrv_get_device_name(bs1)); 14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14662ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(out, "\n"); 14675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) { 14702ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(err, "bdrv_snapshot_list: error %d\n", nb_sns); 14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14732ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(out, "Snapshot list (from %s):\n", 14745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 14752ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); 14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 14775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 14782ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije output_channel_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); 14795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(sn_tab); 14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1482