savevm.c revision dcda949f769a11b197f4784fe299a448d87e6e14
15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU System Emulator 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2003-2008 Fabrice Bellard 55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy 75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal 85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in the Software without restriction, including without limitation the rights 95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is 115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * furnished to do so, subject to the following conditions: 125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included in 145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * all copies or substantial portions of the Software. 155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE. 235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <unistd.h> 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <fcntl.h> 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <signal.h> 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <time.h> 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <errno.h> 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/time.h> 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <zlib.h> 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 322c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner/* Needed early for CONFIG_BSD etc. */ 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "config-host.h" 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/times.h> 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/wait.h> 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <termios.h> 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/mman.h> 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/ioctl.h> 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/resource.h> 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/socket.h> 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in.h> 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if.h> 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <arpa/inet.h> 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dirent.h> 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netdb.h> 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/select.h> 492c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner#ifdef CONFIG_BSD 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h> 51cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libutil.h> 535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <util.h> 555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__ 575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <pty.h> 585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h> 595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/rtc.h> 605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <windows.h> 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h> 675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/timeb.h> 685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <mmsystem.h> 695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define getopt_long_only getopt_long 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define memalign(align, size) malloc(size) 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h" 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/hw.h" 75cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turner#include "net/net.h" 766af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h" 7734c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/sysemu.h" 78c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#include "qemu/iov.h" 797a78db75ad42aea283f5073f51891464104a9fc3David 'Digit' Turner#include "qemu/timer.h" 80e7216d82dbaa19892ad62b07402d512234559a6eDavid 'Digit' Turner#include "sysemu/char.h" 8134c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/blockdev.h" 82e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "block/block.h" 835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio/audio.h" 8428a09b6fe8d8f3e92ffee9263609a6da881b8818David 'Digit' Turner#include "migration/migration.h" 85d0edecb426b34ddb9b10b81dea19aee04a61a385David 'Digit' Turner#include "qemu/sockets.h" 86031d655004e505a15e92580a16a181d1d247c4d5David 'Digit' Turner#include "qemu/queue.h" 8728a09b6fe8d8f3e92ffee9263609a6da881b8818David 'Digit' Turner#include "migration/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, ... */ 145dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 146986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100); 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 148dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_del(timer); 149dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_free(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; 156dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer = timer_new_ms(QEMU_CLOCK_REALTIME, 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 164c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#define MAX_IOV_SIZE MIN(IOV_MAX, 64) 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct QEMUFile { 167c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner const QEMUFileOps *ops; 1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 170c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int64_t bytes_xfer; 171c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int64_t xfer_limit; 172c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 173c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int64_t pos; /* start of buffer when writing, end of buffer 174c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner when reading */ 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_index; 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_size; /* 0 when writing */ 1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t buf[IO_BUF_SIZE]; 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 179c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner struct iovec iov[MAX_IOV_SIZE]; 180c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner unsigned int iovcnt; 181c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 182c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int last_error; 1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 185986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnertypedef struct QEMUFileStdio 1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 187986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner FILE *stdio_file; 1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 189986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} QEMUFileStdio; 1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFileSocket 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFileSocket; 1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 197c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, 198c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int64_t pos) 199c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 200c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner QEMUFileSocket *s = opaque; 201c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ssize_t len; 202c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ssize_t size = iov_size(iov, iovcnt); 203c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 204c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner len = iov_send(s->fd, iov, iovcnt, 0, size); 205c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (len < size) { 206c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner len = -socket_error(); 207c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 208c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return len; 209c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 210c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 2110e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turnerstatic int socket_get_fd(void *opaque) 2120e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner{ 2130e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner QEMUFileSocket *s = opaque; 2140e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 2150e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner return s->fd; 2160e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner} 2170e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 218986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ssize_t len; 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 223c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner for (;;) { 224c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner len = qemu_recv(s->fd, buf, size, 0); 225c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (len != -1) { 226c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 227c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 228c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#ifndef CONFIG_ANDROID 229c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (socket_error() == EAGAIN) { 230c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner yield_until_fd_readable(s->fd); 231c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else if (socket_error() != EINTR) { 232c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 233c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 234c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#else 235c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (socket_error() != EINTR) 236c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 237c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#endif 238c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 240c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (len == -1) { 2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = -socket_error(); 242c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return len; 2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_socket_close(void *opaque) 2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 2490e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner if (s->fd >= 0) 2500e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner socket_close(s->fd); 251aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(s); 2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 255c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic int stdio_get_fd(void *opaque) 2560e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner{ 2570e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner QEMUFileStdio *s = opaque; 258c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 2590e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner return fileno(s->stdio_file); 2600e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner} 2610e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 262986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) 2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 264986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 265986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return fwrite(buf, 1, size, s->stdio_file); 2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 268986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 270986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 271986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner FILE *fp = s->stdio_file; 2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int bytes; 2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 274c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner for (;;) { 2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner clearerr(fp); 2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bytes = fread(buf, 1, size, fp); 277c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (bytes != 0 || !ferror(fp)) { 278c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 279c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 280c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#ifndef CONFIG_ANDROID 281c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (errno == EAGAIN) { 282c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner yield_until_fd_readable(fileno(fp)); 283c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else if (errno != EINTR) { 284c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 285c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 286c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#else 287c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (errno != EINTR) 288c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 289c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#endif 290c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bytes; 2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 294986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_pclose(void *opaque) 2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 296986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 297986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner int ret; 298986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner ret = pclose(s->stdio_file); 299c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret == -1) { 300c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = -errno; 301c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) { 302c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* close succeeded, but non-zero exit code: */ 303c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = -EIO; /* fake errno value */ 304c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 305aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(s); 306986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return ret; 307986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 308986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 309986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_fclose(void *opaque) 310986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 311986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s = opaque; 312c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret = 0; 313c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 314c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (s->file->ops->put_buffer || s->file->ops->writev_buffer) { 315c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int fd = fileno(s->stdio_file); 316c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner struct stat st; 317c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 318c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = fstat(fd, &st); 319c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret == 0 && S_ISREG(st.st_mode)) { 320c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* 321c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * If the file handle is a regular file make sure the 322c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * data is flushed to disk before signaling success. 323c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner */ 324c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = fsync(fd); 325c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret != 0) { 326c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = -errno; 327c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return ret; 328c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 329c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 330c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 331c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (fclose(s->stdio_file) == EOF) { 332c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = -errno; 333c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 334aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(s); 335c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return ret; 3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3380e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turnerstatic const QEMUFileOps stdio_pipe_read_ops = { 3390e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .get_fd = stdio_get_fd, 3400e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .get_buffer = stdio_get_buffer, 3410e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .close = stdio_pclose 3420e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 3430e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 3440e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turnerstatic const QEMUFileOps stdio_pipe_write_ops = { 3450e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .get_fd = stdio_get_fd, 3460e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .put_buffer = stdio_put_buffer, 3470e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .close = stdio_pclose 3480e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 3490e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 350c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' TurnerQEMUFile *qemu_popen_cmd(const char *command, const char *mode) 3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 352c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner FILE *stdio_file; 353986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner QEMUFileStdio *s; 3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 355c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { 3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu_popen: Argument validity check failed\n"); 3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 360c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner stdio_file = popen(command, mode); 361c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (stdio_file == NULL) { 362c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return NULL; 363c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 364c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 365aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner s = g_malloc0(sizeof(QEMUFileStdio)); 3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 367986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = stdio_file; 3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(mode[0] == 'r') { 3700e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops); 3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 3720e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops); 3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->file; 3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 377c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic const QEMUFileOps stdio_file_read_ops = { 378c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .get_fd = stdio_get_fd, 379c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .get_buffer = stdio_get_buffer, 380c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .close = stdio_fclose 381c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner}; 382c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 383c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic const QEMUFileOps stdio_file_write_ops = { 384c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .get_fd = stdio_get_fd, 385c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .put_buffer = stdio_put_buffer, 386c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .close = stdio_fclose 387c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner}; 388c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 389c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, 390c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int64_t pos) 3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 392c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner QEMUFileSocket *s = opaque; 393c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ssize_t len, offset; 394c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ssize_t size = iov_size(iov, iovcnt); 395c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ssize_t total = 0; 3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 397c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner assert(iovcnt > 0); 398c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner offset = 0; 399c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner while (size > 0) { 400c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* Find the next start position; skip all full-sized vector elements */ 401c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner while (offset >= iov[0].iov_len) { 402c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner offset -= iov[0].iov_len; 403c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner iov++, iovcnt--; 404c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 405c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 406c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* skip `offset' bytes from the (now) first element, undo it on exit */ 407c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner assert(iovcnt > 0); 408c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner iov[0].iov_base += offset; 409c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner iov[0].iov_len -= offset; 410c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 411c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner do { 412c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner len = writev(s->fd, iov, iovcnt); 413c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } while (len == -1 && errno == EINTR); 414c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (len == -1) { 415c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return -errno; 416c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 417c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 418c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* Undo the changes above */ 419c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner iov[0].iov_base -= offset; 420c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner iov[0].iov_len += offset; 421c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 422c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* Prepare for the next iteration */ 423c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner offset += len; 424c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner total += len; 425c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner size -= len; 4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 428c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return total; 4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 431c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 433c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner QEMUFileSocket *s = opaque; 434c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ssize_t len; 4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 436c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner for (;;) { 437c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner len = read(s->fd, buf, size); 438c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (len != -1) { 439c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 440c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 441c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (errno == EAGAIN) { 442c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner yield_until_fd_readable(s->fd); 443c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else if (errno != EINTR) { 444c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 445c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 446c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 447c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 448c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (len == -1) { 449c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner len = -errno; 450c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 451c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return len; 4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 454c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic int unix_close(void *opaque) 455c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 456c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner QEMUFileSocket *s = opaque; 457c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner close(s->fd); 458c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner g_free(s); 459c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return 0; 460c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 461c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 462c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic const QEMUFileOps unix_read_ops = { 463c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .get_fd = socket_get_fd, 464c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .get_buffer = unix_get_buffer, 465c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .close = unix_close 4660e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 4670e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 468c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic const QEMUFileOps unix_write_ops = { 469c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .get_fd = socket_get_fd, 470c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .writev_buffer = unix_writev_buffer, 471c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .close = unix_close 4720e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 4730e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 474986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' TurnerQEMUFile *qemu_fdopen(int fd, const char *mode) 475986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 476c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner QEMUFileSocket *s; 477986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 478986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (mode == NULL || 479c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner (mode[0] != 'r' && mode[0] != 'w') || 480c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner mode[1] != 'b' || mode[2] != 0) { 481986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner fprintf(stderr, "qemu_fdopen: Argument validity check failed\n"); 482986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 483986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 484986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 485c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s = g_malloc0(sizeof(QEMUFileSocket)); 486c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s->fd = fd; 487986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 488986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if(mode[0] == 'r') { 489c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s->file = qemu_fopen_ops(s, &unix_read_ops); 490986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } else { 491c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s->file = qemu_fopen_ops(s, &unix_write_ops); 492986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 493986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return s->file; 494986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 495986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 4960e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turnerstatic const QEMUFileOps socket_read_ops = { 4970e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .get_fd = socket_get_fd, 4980e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .get_buffer = socket_get_buffer, 4990e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .close = file_socket_close 5000e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 5010e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 5020e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turnerstatic const QEMUFileOps socket_write_ops = { 5030e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .get_fd = socket_get_fd, 504c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .writev_buffer = socket_writev_buffer, 5050e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .close = file_socket_close 5060e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 5070e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 5080e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turnerbool qemu_file_mode_is_not_valid(const char *mode) 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5100e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner if (mode == NULL || 5110e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner (mode[0] != 'r' && mode[0] != 'w') || 5120e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner mode[1] != 'b' || mode[2] != 0) { 5130e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fprintf(stderr, "qemu_fopen: Argument validity check failed\n"); 5140e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner return true; 5150e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner } 5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5170e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner return false; 5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 520c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' TurnerQEMUFile *qemu_fopen_socket(int fd, const char *mode) 521c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 522c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner QEMUFileSocket *s; 523c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 524c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (qemu_file_mode_is_not_valid(mode)) { 525c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return NULL; 526c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 527c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 528c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s = g_malloc0(sizeof(QEMUFileSocket)); 529c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s->fd = fd; 530c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (mode[0] == 'w') { 531c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_set_block(s->fd); 532c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s->file = qemu_fopen_ops(s, &socket_write_ops); 533c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else { 534c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner s->file = qemu_fopen_ops(s, &socket_read_ops); 535c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 536c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return s->file; 537c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 538c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen(const char *filename, const char *mode) 5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s; 5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5430e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner if (qemu_file_mode_is_not_valid(mode)) { 544986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return NULL; 545986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 546986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 547aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner s = g_malloc0(sizeof(QEMUFileStdio)); 5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 549986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner s->stdio_file = fopen(filename, mode); 550986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (!s->stdio_file) 5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto fail; 552c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 553986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if(mode[0] == 'w') { 5540e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner s->file = qemu_fopen_ops(s, &stdio_file_write_ops); 555986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } else { 5560e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner s->file = qemu_fopen_ops(s, &stdio_file_read_ops); 557986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 558986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return s->file; 5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfail: 560aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(s); 5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 564c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#ifndef CONFIG_ANDROID 565c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner// TODO(digit): Once bdrv_writev_vmstate() is implemented. 566c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, 567c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int64_t pos) 568c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 569c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret; 570c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner QEMUIOVector qiov; 571c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 572c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_iovec_init_external(&qiov, iov, iovcnt); 573c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = bdrv_writev_vmstate(opaque, &qiov, pos); 574c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret < 0) { 575c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return ret; 576c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 577c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 578c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return qiov.size; 579c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 580c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#endif 581c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_put_buffer(void *opaque, const uint8_t *buf, 5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t pos, int size) 5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 585986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner bdrv_save_vmstate(opaque, buf, pos, size); 5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size; 5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 591986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return bdrv_load_vmstate(opaque, buf, pos, size); 5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_fclose(void *opaque) 5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 596c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner // TODO(digit): bdrv_flush() should return error code. 597c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner bdrv_flush(opaque); 5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 601c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic const QEMUFileOps bdrv_read_ops = { 6020e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner .get_buffer = block_get_buffer, 603c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .close = bdrv_fclose 6040e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 6050e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 606c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic const QEMUFileOps bdrv_write_ops = { 607c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .put_buffer = block_put_buffer, 608c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner //.writev_buffer = block_writev_buffer, 609c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner .close = bdrv_fclose 6100e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner}; 6110e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 612986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) 6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (is_writable) 615c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return qemu_fopen_ops(bs, &bdrv_write_ops); 616c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return qemu_fopen_ops(bs, &bdrv_read_ops); 6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 619c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' TurnerQEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) 6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 623aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner f = g_malloc0(sizeof(QEMUFile)); 6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->opaque = opaque; 626c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->ops = ops; 6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f; 6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 630c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner/* 631c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * Get last error for stream f 632c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * 633c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * Return negative error value if there has been an error on previous 634c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * operations, return 0 if no error happened. 635c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * 636c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner */ 637c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerint qemu_file_get_error(QEMUFile *f) 638c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 639c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return f->last_error; 640c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 641c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 642c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid qemu_file_set_error(QEMUFile *f, int ret) 6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 644c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->last_error == 0) { 645c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->last_error = ret; 646c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 649c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic inline bool qemu_file_is_writable(QEMUFile *f) 6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 651c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return f->ops->writev_buffer || f->ops->put_buffer; 6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 654c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner/** 655c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * Flushes QEMUFile buffer 656c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * 657c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * If there is writev_buffer QEMUFileOps it uses it otherwise uses 658c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * put_buffer ops. 659c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner */ 6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_fflush(QEMUFile *f) 6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 662c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ssize_t ret = 0; 663c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 664c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (!qemu_file_is_writable(f)) { 6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 666c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 668c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->writev_buffer) { 669c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->iovcnt > 0) { 670c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos); 671c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 672c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else { 673c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->buf_index > 0) { 674c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index); 675c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 676c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 677c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret >= 0) { 678c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->pos += ret; 679c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 680c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->buf_index = 0; 681c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->iovcnt = 0; 682c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret < 0) { 683c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, ret); 684c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 685c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 686c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 687c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#ifndef CONFIG_ANDROID 688c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner// TODO(digit). 689c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid ram_control_before_iterate(QEMUFile *f, uint64_t flags) 690c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 691c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret = 0; 692c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 693c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->before_ram_iterate) { 694c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = f->ops->before_ram_iterate(f, f->opaque, flags); 695c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret < 0) { 696c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, ret); 697c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 698c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 699c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 700c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 701c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid ram_control_after_iterate(QEMUFile *f, uint64_t flags) 702c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 703c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret = 0; 704c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 705c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->after_ram_iterate) { 706c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = f->ops->after_ram_iterate(f, f->opaque, flags); 707c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret < 0) { 708c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, ret); 709c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 710c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 711c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 712c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 713c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid ram_control_load_hook(QEMUFile *f, uint64_t flags) 714c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 715c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret = -EINVAL; 716c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 717c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->hook_ram_load) { 718c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = f->ops->hook_ram_load(f, f->opaque, flags); 719c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret < 0) { 720c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, ret); 721c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 722c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else { 723c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, ret); 724c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 725c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 726c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 727c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnersize_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, 728c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ram_addr_t offset, size_t size, int *bytes_sent) 729c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 730c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->save_page) { 731c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret = f->ops->save_page(f, f->opaque, block_offset, 732c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner offset, size, bytes_sent); 733c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 734c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret != RAM_SAVE_CONTROL_DELAYED) { 735c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (bytes_sent && *bytes_sent > 0) { 736c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_update_position(f, *bytes_sent); 737c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else if (ret < 0) { 738c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, ret); 739c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 740c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 742c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return ret; 7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 744c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 745c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return RAM_SAVE_CONTROL_NOT_SUPP; 7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 747c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner#endif // !CONFIG_ANDROID 7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_fill_buffer(QEMUFile *f) 7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 752c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int pending; 7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 754c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner assert(!qemu_file_is_writable(f)); 7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 756c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner pending = f->buf_size - f->buf_index; 757c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (pending > 0) { 758c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner memmove(f->buf, f->buf + f->buf_index, pending); 759c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 760c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->buf_index = 0; 761c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->buf_size = pending; 7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 763c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, 764c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner IO_BUF_SIZE - pending); 7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 0) { 766c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->buf_size += len; 767c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->pos += len; 768c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else if (len == 0) { 769c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, -EIO); 7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (len != -EAGAIN) 771c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_set_error(f, len); 7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 774c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerint qemu_get_fd(QEMUFile *f) 775c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 776c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->get_fd) { 777c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return f->ops->get_fd(f->opaque); 778c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 779c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return -1; 780c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 781c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 782c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid qemu_update_position(QEMUFile *f, size_t size) 783c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 784c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->pos += size; 785c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 786c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 787c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner/** Closes the file 788c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * 789c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * Returns negative error value if any error happened on previous operations or 790c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * while closing the file. Returns 0 or positive number on success. 791c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * 792c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * The meaning of return value on success depends on the specific backend 793c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * being used. 794c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner */ 7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_fclose(QEMUFile *f) 7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 797c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret; 7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 799c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = qemu_file_get_error(f); 800c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 801c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->close) { 802c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int ret2 = f->ops->close(f->opaque); 803c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (ret >= 0) { 804c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = ret2; 805c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 806c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 807c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* If any error was spotted before closing, we should report it 808c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner * instead of the close() return value. 809c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner */ 810c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->last_error) { 811c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = f->last_error; 812c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 813aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(f); 8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 817c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size) 8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 819c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner /* check for adjacent buffer and coalesce them */ 820c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base + 821c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->iov[f->iovcnt - 1].iov_len) { 822c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->iov[f->iovcnt - 1].iov_len += size; 823c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } else { 824c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->iov[f->iovcnt].iov_base = (uint8_t *)buf; 825c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->iov[f->iovcnt++].iov_len = size; 826c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 827c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 828c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->iovcnt >= MAX_IOV_SIZE) { 829c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_fflush(f); 830c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 831c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 832c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 833c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size) 834c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 835c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (!f->ops->writev_buffer) { 836c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_put_buffer(f, buf, size); 837c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return; 838c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 839c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 840c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->last_error) { 841c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return; 842c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 843c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 844c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->bytes_xfer += size; 845c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner add_to_iovec(f, buf, size); 8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) 8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int l; 8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 852c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->last_error) { 853c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return; 8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 856c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner while (size > 0) { 8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = IO_BUF_SIZE - f->buf_index; 8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l > size) 8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = size; 8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(f->buf + f->buf_index, buf, l); 861c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->bytes_xfer += l; 862c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->writev_buffer) { 863c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner add_to_iovec(f, f->buf + f->buf_index, l); 864c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index += l; 866c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->buf_index == IO_BUF_SIZE) { 867c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_fflush(f); 868c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 869c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (qemu_file_get_error(f)) { 870c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner break; 871c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner buf += l; 8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size -= l; 8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_byte(QEMUFile *f, int v) 8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 879c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->last_error) { 880c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return; 8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 883c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->buf[f->buf_index] = v; 884c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->bytes_xfer++; 885c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->ops->writev_buffer) { 886c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner add_to_iovec(f, f->buf + f->buf_index, 1); 887c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 888c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->buf_index++; 889c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->buf_index == IO_BUF_SIZE) { 8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 891c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 894c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic void qemu_file_skip(QEMUFile *f, int size) 8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 896c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->buf_index + size <= f->buf_size) { 897c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->buf_index += size; 898c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 899c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 901c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) 902c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 903c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int pending; 904c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int index; 9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 906c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner assert(!qemu_file_is_writable(f)); 907c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 908c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner index = f->buf_index + offset; 909c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner pending = f->buf_size - index; 910c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (pending < size) { 911c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_fill_buffer(f); 912c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner index = f->buf_index + offset; 913c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner pending = f->buf_size - index; 914c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 915c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 916c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (pending <= 0) { 917c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return 0; 918c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 919c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (size > pending) { 920c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner size = pending; 921c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 922c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 923c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner memcpy(buf, f->buf + index, size); 924c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return size; 925c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 926c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 927c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerint qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) 928c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 929c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int pending = size; 930c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int done = 0; 931c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 932c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner while (pending > 0) { 933c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int res; 934c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 935c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner res = qemu_peek_buffer(f, buf, pending, 0); 936c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (res == 0) { 937c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return done; 9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 939c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_skip(f, res); 940c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner buf += res; 941c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner pending -= res; 942c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner done += res; 9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 944c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return done; 9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 947c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerstatic int qemu_peek_byte(QEMUFile *f, int offset) 9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 949c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int index = f->buf_index + offset; 950c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 951c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner assert(!qemu_file_is_writable(f)); 9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 953c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (index >= f->buf_size) { 9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fill_buffer(f); 955c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner index = f->buf_index + offset; 956c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (index >= f->buf_size) { 9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 958c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner } 9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 960c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return f->buf[index]; 961c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 962c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 963c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerint qemu_get_byte(QEMUFile *f) 964c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 965c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner int result; 966c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner 967c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner result = qemu_peek_byte(f, 0); 968c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_skip(f, 1); 969c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return result; 9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9723e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner#ifdef CONFIG_ANDROID 9733e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnervoid qemu_put_string(QEMUFile *f, const char* str) 9743e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{ 9753e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner /* We will encode NULL and the empty string in the same way */ 9763e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner int slen; 9773e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (str == NULL) { 9783e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner str = ""; 9793e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } 9803e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner slen = strlen(str); 9813e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner qemu_put_be32(f, slen); 9823e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner qemu_put_buffer(f, (const uint8_t*)str, slen); 9833e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner} 9843e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 9853e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerchar* qemu_get_string(QEMUFile *f) 9863e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{ 9873e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner int slen = qemu_get_be32(f); 9883e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner char* str; 9893e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (slen == 0) 9903e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return NULL; 9913e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 992aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner str = g_malloc(slen+1); 9933e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (qemu_get_buffer(f, (uint8_t*)str, slen) != slen) { 994aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(str); 9953e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return NULL; 9963e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } 9973e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner str[slen] = '\0'; 9983e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return str; 9993e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner} 10003e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner#endif 10013e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 10023e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner 10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_ftell(QEMUFile *f) 10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1005c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_fflush(f); 1006c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return f->pos; 10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1009c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnerint qemu_file_rate_limit(QEMUFile *f) 10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1011c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (qemu_file_get_error(f)) { 1012c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return 1; 10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1014c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) { 1015c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return 1; 10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1020986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint64_t qemu_file_get_rate_limit(QEMUFile *f) 1021986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{ 1022c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return f->xfer_limit; 1023986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} 1024986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner 1025c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid qemu_file_set_rate_limit(QEMUFile *f, int64_t limit) 10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1027c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->xfer_limit = limit; 1028c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner} 10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1030c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turnervoid qemu_file_reset_rate_limit(QEMUFile *f) 1031c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner{ 1032c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner f->bytes_xfer = 0; 10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be16(QEMUFile *f, unsigned int v) 10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be32(QEMUFile *f, unsigned int v) 10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 24); 10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 16); 10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be64(QEMUFile *f, uint64_t v) 10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v >> 32); 10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v); 10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be16(QEMUFile *f) 10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 8; 10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be32(QEMUFile *f) 10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 24; 10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 16; 10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 8; 10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint64_t qemu_get_be64(QEMUFile *f) 10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t v; 10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = (uint64_t)qemu_get_be32(f) << 32; 10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_be32(f); 10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1081dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 1082dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* timer */ 1083dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 1084dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_put(QEMUFile *f, QEMUTimer *ts) 1085dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 1086dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner uint64_t expire_time; 1087dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 1088dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner expire_time = timer_expire_time_ns(ts); 1089dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_put_be64(f, expire_time); 1090dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 1091dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 1092dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_get(QEMUFile *f, QEMUTimer *ts) 1093dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 1094dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner uint64_t expire_time; 1095dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 1096dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner expire_time = qemu_get_be64(f); 1097dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (expire_time != -1) { 1098dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_mod_ns(ts, expire_time); 1099dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } else { 1100dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_del(ts); 1101dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 1102dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 1103dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_struct(QEMUFile* f, const QField* fields, const void* s) 11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11087fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 11097fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, p[0]); 11155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be16(f, ((uint16_t*)p)[0]); 11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, ((uint32_t*)p)[0]); 11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be64(f, ((uint64_t*)p)[0]); 11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 11267fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 11277fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n", 11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 11357fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, p, size); 11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_struct(QEMUFile* f, const QField* fields, void* s) 11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11537fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 11547fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p[0] = qemu_get_byte(f); 11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint16_t*)p)[0] = qemu_get_be16(f); 11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint32_t*)p)[0] = qemu_get_be32(f); 11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t*)p)[0] = qemu_get_be64(f); 11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 11717fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 11727fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n", 11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 11795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 11807fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = qemu_get_buffer(f, p, size); 11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret != size) { 11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__); 11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1199871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* write a float to file */ 1200871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijevoid qemu_put_float(QEMUFile *f, float v) 1201871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 1202871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t *bytes = (uint8_t*) &v; 1203871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_put_buffer(f, bytes, sizeof(float)); 1204871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 1205871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 1206871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* read a float from file */ 1207871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijefloat qemu_get_float(QEMUFile *f) 1208871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 1209871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t bytes[sizeof(float)]; 1210871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_get_buffer(f, bytes, sizeof(float)); 1211871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 1212871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije return *((float*) bytes); 1213871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 1214871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 12155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct SaveStateEntry { 12165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 12175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id; 12185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 12205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state; 12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state; 12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state; 12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct SaveStateEntry *next; 12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} SaveStateEntry; 12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *first_se; 12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* TODO: Individual devices generally have very little idea about the rest 12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner of the system, so instance_id should be removed/replaced. 12315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner Meanwhile pass -1 as instance_id if you do not already have a clearly 12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner distinguishing id for all instances of your device class. */ 12335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm_live(const char *idstr, 12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state, 12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se, **pse; 12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static int global_section_id; 12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1244aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner se = g_malloc(sizeof(SaveStateEntry)); 12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(se->idstr, sizeof(se->idstr), idstr); 12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (instance_id == -1) ? 0 : instance_id; 12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->version_id = version_id; 12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->section_id = global_section_id++; 12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state = save_live_state; 12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state = save_state; 12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->load_state = load_state; 12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->opaque = opaque; 12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->next = NULL; 12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* add at the end of list */ 12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (instance_id == -1 12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && strcmp(se->idstr, (*pse)->idstr) == 0 12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && se->instance_id <= (*pse)->instance_id) 12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (*pse)->instance_id + 1; 12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = se; 12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 12665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm(const char *idstr, 12695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 12725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 12735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return register_savevm_live(idstr, instance_id, version_id, 12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner NULL, save_state, load_state, opaque); 12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid unregister_savevm(const char *idstr, void *opaque) 12805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry **pse; 12825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 12845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) { 12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *next = (*pse)->next; 1287aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(*pse); 12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = next; 12895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 12905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_MAGIC 0x5145564d 12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 12973e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner#define QEMU_VM_FILE_VERSION 0x00000004 12985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_EOF 0x00 13005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_START 0x01 13015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_PART 0x02 13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_END 0x03 13035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_FULL 0x04 13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_begin(QEMUFile *f) 13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 13085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_MAGIC); 13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_VERSION); 13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 13195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_START); 13205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 13215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 13235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 13245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 13255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 13265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 13285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); 13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1333c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return qemu_file_get_error(f); 13345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_iterate(QEMUFile *f) 13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 1; 13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 13445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_PART); 13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 13485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); 13505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret) 13535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 1; 13545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1355c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return qemu_file_get_error(f); 13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_complete(QEMUFile *f) 13595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 13655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 13675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_END); 13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); 13715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 13745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13768f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (se->save_state == NULL) 13778f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije continue; 13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_FULL); 13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 13845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 13895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 13905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state(f, se->opaque); 13925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_EOF); 13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1396c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return qemu_file_get_error(f); 13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state(QEMUFile *f) 14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_flush_all(); 14085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_begin(f); 14105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 14115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 14125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 14145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_iterate(f); 14155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 14165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (ret == 0); 14185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_complete(f); 14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 1422c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = qemu_file_get_error(f); 14235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!ret && saved_vm_running) 14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 14285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *find_se(const char *idstr, int instance_id) 14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 14335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 14355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(se->idstr, idstr) && 14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id == se->instance_id) 14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return se; 14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct LoadStateEntry { 14435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 14445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 14455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 14465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct LoadStateEntry *next; 14475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} LoadStateEntry; 14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int qemu_loadvm_state_v2(QEMUFile *f) 14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len, ret, instance_id, record_len, version_id; 14535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t total_len, end_pos, cur_pos; 14545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 14555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner total_len = qemu_get_be64(f); 14575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner end_pos = total_len + qemu_ftell(f); 14585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(;;) { 14595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_ftell(f) >= end_pos) 14605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 14615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 14625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 14635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = '\0'; 14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 14655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 14665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner record_len = qemu_get_be32(f); 14675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cur_pos = qemu_ftell(f); 14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!se) { 14705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", 14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 14735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = se->load_state(f, se->opaque, version_id); 14745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 14755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", 14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 14775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 14785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* always seek to exact end of record */ 1481c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner qemu_file_skip(f, cur_pos + record_len - qemu_ftell(f)); 14825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1484c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner return qemu_file_get_error(f); 14855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_loadvm_state(QEMUFile *f) 14885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *first_le = NULL; 14905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t section_type; 14915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 14925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 14935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 14955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v != QEMU_VM_FILE_MAGIC) 14965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EINVAL; 14975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 14995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v == QEMU_VM_FILE_VERSION_COMPAT) 15005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return qemu_loadvm_state_v2(f); 15013e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner if (v < QEMU_VM_FILE_VERSION) { 15023e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner fprintf(stderr, "Snapshot format %d is too old for this version of the emulator, please create a new one.\n", v); 15033e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner return -ENOTSUP; 15043e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } else if (v > QEMU_VM_FILE_VERSION) { 15053e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner fprintf(stderr, "Snapshot format %d is more recent than the emulator, please update your Android SDK Tools.\n", v); 15065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENOTSUP; 15073e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner } 15085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { 15105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t instance_id, version_id, section_id; 15115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le; 15125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 15135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[257]; 15145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 15155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (section_type) { 15175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_START: 15185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_FULL: 15195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Read section start */ 15205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 15215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 15225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 15235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = 0; 15245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 15255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 15265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Find savevm section */ 15285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 15295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se == NULL) { 15305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id); 15315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 15325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 15335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Validate version */ 15365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (version_id > se->version_id) { 15375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n", 15385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id, idstr, se->version_id); 15395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 15405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 15415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Add entry */ 1544aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner le = g_malloc0(sizeof(*le)); 15455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se = se; 15475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->section_id = section_id; 15485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->version_id = version_id; 15495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->next = first_le; 15505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = le; 15515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1552d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine if (le->se->load_state(f, le->se->opaque, le->version_id)) { 1553d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine fprintf(stderr, "savevm: unable to load section %s\n", idstr); 1554d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine ret = -EINVAL; 1555d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine goto out; 1556d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine } 15575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_PART: 15595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_END: 15605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 15615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (le = first_le; le && le->section_id != section_id; le = le->next); 15635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (le == NULL) { 15645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section %d\n", section_id); 15655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 15665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 15675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se->load_state(f, le->se->opaque, le->version_id); 15705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 15725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section type %d\n", section_type); 15735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 15745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 15755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 15795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 15815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (first_le) { 15825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le = first_le; 15835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = first_le->next; 1584aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(le); 15855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1587c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner if (qemu_file_get_error(f)) 1588c79de3c66b3506a1c6b00daedaea9b616b3e140cDavid 'Digit' Turner ret = qemu_file_get_error(f); 15895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 15915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1592cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if 0 15935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriverState *get_bs_snapshots(void) 15945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 15955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs; 15965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 15975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs_snapshots) 15995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs_snapshots; 16005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i <= nb_drives; i++) { 16015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = drives_table[i].bdrv; 16025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_can_snapshot(bs)) 16035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto ok; 16045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 16065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ok: 16075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs_snapshots = bs; 16085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs; 16095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1610cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#endif 16115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, 16125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *name) 16135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 16145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 16155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i, ret; 16165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -ENOENT; 16185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 16195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) 16205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 16215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 16225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 16235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { 16245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *sn_info = *sn; 16255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 16265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1629aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(sn_tab); 16305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 16315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 16325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 163395a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_savevm(Monitor *err, const char *name) 16342ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 16355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 16365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; 1637cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int must_delete, ret; 16385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 16395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 16405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 16415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t vm_state_size; 16425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 16435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct _timeb tb; 16445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 16455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct timeval tv; 16465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 16475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1648cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 16495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 165095a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No block device can accept snapshots\n"); 16515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 16525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ??? Should this occur after vm_stop? */ 16555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 16565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 16585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 16595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 0; 16615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) { 16625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, old_sn, name); 16635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret >= 0) { 16645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 1; 16655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(sn, 0, sizeof(*sn)); 16685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 16695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), old_sn->name); 16705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); 16715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 16725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) 16735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), name); 16745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fill auxiliary fields */ 16775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 16785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner _ftime(&tb); 16795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tb.time; 16805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tb.millitm * 1000000; 16815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 16825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner gettimeofday(&tv, NULL); 16835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tv.tv_sec; 16845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tv.tv_usec * 1000; 16855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 1686dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 16875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 168995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Device %s does not support VM state snapshots\n", 16902ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs)); 16915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 16925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* save the VM state */ 1695986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f = qemu_fopen_bdrv(bs, 1); 16965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 169795a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Could not open VM state file\n"); 16985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 16995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state(f); 17015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_state_size = qemu_ftell(f); 17025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 17035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 170495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while writing VM\n", ret); 17055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 17065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* create the snapshots */ 17095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1710cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1711cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 17128f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 17135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 17145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, old_sn->id_str); 17155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 171695a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, 17172ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "Error while deleting snapshot on '%s'\n", 17182ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 17195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Write VM state size only to the image that contains the state */ 17225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->vm_state_size = (bs == bs1 ? vm_state_size : 0); 17235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_create(bs1, sn); 17245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 172595a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error while creating snapshot on '%s'\n", 17262ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 17275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 17325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 17335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 17345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 17355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 173695a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_loadvm(Monitor *err, const char *name) 17372ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 17385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 17395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 17405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn; 17415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 1742cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int ret; 17435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 17445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1745cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 17465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 174795a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No block device supports snapshots\n"); 17485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 17495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Flush all IO requests so they don't interfere with the new state. */ 17525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 17535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 17555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 17565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 175705e074899c900b99adca7b37eee19a4ddc090e38Vladimir Chtchetkine bs1 = bs; 175805e074899c900b99adca7b37eee19a4ddc090e38Vladimir Chtchetkine do { 17598f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 17605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_goto(bs1, name); 17615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 17625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs != bs1) 176395a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Warning: "); 17645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch(ret) { 17655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOTSUP: 176695a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, 17675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Snapshots not supported on device '%s'\n", 17685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs1)); 17695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOENT: 177195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Could not find snapshot '%s' on " 17725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "device '%s'\n", 17735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner name, bdrv_get_device_name(bs1)); 17745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 177695a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while activating snapshot on" 17775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner " '%s'\n", ret, bdrv_get_device_name(bs1)); 17785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fatal on snapshot block device */ 17815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 17825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 17835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 178505e074899c900b99adca7b37eee19a4ddc090e38Vladimir Chtchetkine } while ((bs1 = bdrv_next(bs))); 17865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 178895a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Device %s does not support VM state snapshots\n", 17895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 17905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 17915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Don't even try to load empty VM states */ 17945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, &sn, name); 17955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((ret >= 0) && (sn.vm_state_size == 0)) 17965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 17975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* restore the VM state */ 1799986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner f = qemu_fopen_bdrv(bs, 0); 18005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 180195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Could not open VM state file\n"); 18025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 18035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_loadvm_state(f); 18055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 18065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 180795a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while loading VM state\n", ret); 18085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 18105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 18115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 18125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 18135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 181495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_delvm(Monitor *err, const char *name) 18152ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 18165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 1817cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner int ret; 18185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1819cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 18205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 182195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No block device supports snapshots\n"); 18225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 18235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1825cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1826cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 18278f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 18285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, name); 18295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 18305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret == -ENOTSUP) 183195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, 18322ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "Snapshots not supported on device '%s'\n", 18332ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije bdrv_get_device_name(bs1)); 18345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 183595a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "Error %d while deleting snapshot on " 18362ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije "'%s'\n", ret, bdrv_get_device_name(bs1)); 18375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 18415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 184295a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turnervoid do_info_snapshots(Monitor* out, Monitor* err) 18432ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{ 18445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 18455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 18465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i; 18475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char buf[256]; 18485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1849cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs = bdrv_snapshots(); 18505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 185195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "No available block device supports snapshots\n"); 18525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 18535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 185495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "Snapshot devices:"); 1855cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bs1 = NULL; 1856cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner while ((bs1 = bdrv_next(bs1))) { 18578f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 18585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 185995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, " %s", bdrv_get_device_name(bs1)); 18605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 186295a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "\n"); 18635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 18655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) { 186695a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(err, "bdrv_snapshot_list: error %d\n", nb_sns); 18675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 18685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 186995a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "Snapshot list (from %s):\n", 18705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 187195a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); 18725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 18735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 187495a83ce7ee413954ba6325584ea659c6685edfd5David 'Digit' Turner monitor_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); 18755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1876aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(sn_tab); 18775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1878