summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-03-19 13:39:42 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2012-03-19 13:39:42 -0500
commit33cf629a3754b58a1e2dbbe01d91d97e712b7c06 (patch)
treefcf874262294eba07fb2f9eca11d594096847679
parentb85a4ec8a7ce348f3f385a53df4e418f2f54c182 (diff)
parentc234572ded381423abca9801ebf5a32abd2495ef (diff)
downloadqemu-33cf629a3754b58a1e2dbbe01d91d97e712b7c06.tar.gz
Merge remote-tracking branch 'sstabellini/saverestore-8' into staging
* sstabellini/saverestore-8: xen: do not allocate RAM during INMIGRATE runstate xen mapcache: check if memory region has moved. xen: record physmap changes to xenstore Set runstate to INMIGRATE earlier Introduce "xen-save-devices-state" cirrus_vga: do not reset videoram Conflicts: qapi-schema.json Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r--docs/xen-save-devices-state.txt34
-rw-r--r--hw/cirrus_vga.c4
-rw-r--r--qapi-schema.json17
-rw-r--r--qmp-commands.hx27
-rw-r--r--savevm.c71
-rw-r--r--vl.c2
-rw-r--r--xen-all.c104
-rw-r--r--xen-mapcache.c22
-rw-r--r--xen-mapcache.h9
9 files changed, 278 insertions, 12 deletions
diff --git a/docs/xen-save-devices-state.txt b/docs/xen-save-devices-state.txt
new file mode 100644
index 0000000000..92e08dbf6a
--- /dev/null
+++ b/docs/xen-save-devices-state.txt
@@ -0,0 +1,34 @@
+= Save Devices =
+
+QEMU has code to load/save the state of the guest that it is running.
+These are two complementary operations. Saving the state just does
+that, saves the state for each device that the guest is running.
+
+These operations are normally used with migration (see migration.txt),
+however it is also possible to save the state of all devices to file,
+without saving the RAM or the block devices of the VM.
+
+This operation is called "xen-save-devices-state" (see
+QMP/qmp-commands.txt)
+
+
+The binary format used in the file is the following:
+
+
+-------------------------------------------
+
+32 bit big endian: QEMU_VM_FILE_MAGIC
+32 bit big endian: QEMU_VM_FILE_VERSION
+
+for_each_device
+{
+ 8 bit: QEMU_VM_SECTION_FULL
+ 32 bit big endian: section_id
+ 8 bit: idstr (ID string) length
+ string: idstr (ID string)
+ 32 bit big endian: instance_id
+ 32 bit big endian: version_id
+ buffer: device specific data
+}
+
+8 bit: QEMU_VM_EOF
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 4edcb94774..afedaa43d3 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2767,10 +2767,6 @@ static void cirrus_reset(void *opaque)
}
s->vga.cr[0x27] = s->device_id;
- /* Win2K seems to assume that the pattern buffer is at 0xff
- initially ! */
- memset(s->vga.vram_ptr, 0xff, s->real_vram_size);
-
s->cirrus_hidden_dac_lockindex = 5;
s->cirrus_hidden_dac_data = 0;
}
diff --git a/qapi-schema.json b/qapi-schema.json
index 3a962c1b40..0d11d6eb14 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1684,3 +1684,20 @@
##
{ 'command': 'migrate',
'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool', '*detach': 'bool' } }
+
+# @xen-save-devices-state:
+#
+# Save the state of all devices to file. The RAM and the block devices
+# of the VM are not saved by this command.
+#
+# @filename: the file to save the state of the devices to as binary
+# data. See xen-save-devices-state.txt for a description of the binary
+# format.
+#
+# Returns: Nothing on success
+# If @filename cannot be opened, OpenFileFailed
+# If an I/O error occurs while writing the file, IOError
+#
+# Since: 1.1
+##
+{ 'command': 'xen-save-devices-state', 'data': {'filename': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 8b820382bc..c626ba8d3d 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -444,6 +444,33 @@ Note: inject-nmi is only supported for x86 guest currently, it will
EQMP
{
+ .name = "xen-save-devices-state",
+ .args_type = "filename:F",
+ .mhandler.cmd_new = qmp_marshal_input_xen_save_devices_state,
+ },
+
+SQMP
+xen-save-devices-state
+-------
+
+Save the state of all devices to file. The RAM and the block devices
+of the VM are not saved by this command.
+
+Arguments:
+
+- "filename": the file to save the state of the devices to as binary
+data. See xen-save-devices-state.txt for a description of the binary
+format.
+
+Example:
+
+-> { "execute": "xen-save-devices-state",
+ "arguments": { "filename": "/tmp/save" } }
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "migrate",
.args_type = "detach:-d,blk:-b,inc:-i,uri:s",
.mhandler.cmd_new = qmp_marshal_input_migrate,
diff --git a/savevm.c b/savevm.c
index 962175ac34..12fb20954f 100644
--- a/savevm.c
+++ b/savevm.c
@@ -84,6 +84,7 @@
#include "qemu-timer.h"
#include "cpus.h"
#include "memory.h"
+#include "qmp-commands.h"
#define SELF_ANNOUNCE_ROUNDS 5
@@ -1177,6 +1178,7 @@ typedef struct SaveStateEntry {
void *opaque;
CompatEntry *compat;
int no_migrate;
+ int is_ram;
} SaveStateEntry;
@@ -1241,6 +1243,10 @@ int register_savevm_live(DeviceState *dev,
se->opaque = opaque;
se->vmsd = NULL;
se->no_migrate = 0;
+ /* if this is a live_savem then set is_ram */
+ if (save_live_state != NULL) {
+ se->is_ram = 1;
+ }
if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
char *id = dev->parent_bus->info->get_dev_path(dev);
@@ -1728,6 +1734,45 @@ out:
return ret;
}
+static int qemu_save_device_state(QEMUFile *f)
+{
+ SaveStateEntry *se;
+
+ qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
+ qemu_put_be32(f, QEMU_VM_FILE_VERSION);
+
+ cpu_synchronize_all_states();
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ int len;
+
+ if (se->is_ram) {
+ continue;
+ }
+ if (se->save_state == NULL && se->vmsd == NULL) {
+ continue;
+ }
+
+ /* Section type */
+ qemu_put_byte(f, QEMU_VM_SECTION_FULL);
+ qemu_put_be32(f, se->section_id);
+
+ /* ID string */
+ len = strlen(se->idstr);
+ qemu_put_byte(f, len);
+ qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+
+ qemu_put_be32(f, se->instance_id);
+ qemu_put_be32(f, se->version_id);
+
+ vmstate_save(f, se);
+ }
+
+ qemu_put_byte(f, QEMU_VM_EOF);
+
+ return qemu_file_get_error(f);
+}
+
static SaveStateEntry *find_se(const char *idstr, int instance_id)
{
SaveStateEntry *se;
@@ -2109,6 +2154,32 @@ void do_savevm(Monitor *mon, const QDict *qdict)
vm_start();
}
+void qmp_xen_save_devices_state(const char *filename, Error **errp)
+{
+ QEMUFile *f;
+ int saved_vm_running;
+ int ret;
+
+ saved_vm_running = runstate_is_running();
+ vm_stop(RUN_STATE_SAVE_VM);
+
+ f = qemu_fopen(filename, "wb");
+ if (!f) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+ goto the_end;
+ }
+ ret = qemu_save_device_state(f);
+ qemu_fclose(f);
+ if (ret < 0) {
+ error_set(errp, QERR_IO_ERROR);
+ }
+
+ the_end:
+ if (saved_vm_running)
+ vm_start();
+ return;
+}
+
int load_vmstate(const char *name)
{
BlockDriverState *bs, *bs_vm_state;
diff --git a/vl.c b/vl.c
index eeb634b9ad..112b0e0af9 100644
--- a/vl.c
+++ b/vl.c
@@ -3099,6 +3099,7 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_incoming:
incoming = optarg;
+ runstate_set(RUN_STATE_INMIGRATE);
break;
case QEMU_OPTION_nodefaults:
default_serial = 0;
@@ -3616,7 +3617,6 @@ int main(int argc, char **argv, char **envp)
}
if (incoming) {
- runstate_set(RUN_STATE_INMIGRATE);
int ret = qemu_start_incoming_migration(incoming);
if (ret < 0) {
fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
diff --git a/xen-all.c b/xen-all.c
index 493112bfda..3e6de417ec 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -65,7 +65,7 @@ static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
typedef struct XenPhysmap {
target_phys_addr_t start_addr;
ram_addr_t size;
- MemoryRegion *mr;
+ char *name;
target_phys_addr_t phys_offset;
QLIST_ENTRY(XenPhysmap) list;
@@ -190,6 +190,14 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr)
xen_pfn_t *pfn_list;
int i;
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ /* RAM already populated in Xen */
+ fprintf(stderr, "%s: do not alloc "RAM_ADDR_FMT
+ " bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE\n",
+ __func__, size, ram_addr);
+ return;
+ }
+
if (mr == &ram_memory) {
return;
}
@@ -225,6 +233,22 @@ static XenPhysmap *get_physmapping(XenIOState *state,
return NULL;
}
+static target_phys_addr_t xen_phys_offset_to_gaddr(target_phys_addr_t start_addr,
+ ram_addr_t size, void *opaque)
+{
+ target_phys_addr_t addr = start_addr & TARGET_PAGE_MASK;
+ XenIOState *xen_io_state = opaque;
+ XenPhysmap *physmap = NULL;
+
+ QLIST_FOREACH(physmap, &xen_io_state->physmap, list) {
+ if (range_covers_byte(physmap->phys_offset, physmap->size, addr)) {
+ return physmap->start_addr;
+ }
+ }
+
+ return start_addr;
+}
+
#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 340
static int xen_add_to_physmap(XenIOState *state,
target_phys_addr_t start_addr,
@@ -237,6 +261,7 @@ static int xen_add_to_physmap(XenIOState *state,
XenPhysmap *physmap = NULL;
target_phys_addr_t pfn, start_gpfn;
target_phys_addr_t phys_offset = memory_region_get_ram_addr(mr);
+ char path[80], value[17];
if (get_physmapping(state, start_addr, size)) {
return 0;
@@ -275,6 +300,7 @@ go_physmap:
physmap->start_addr = start_addr;
physmap->size = size;
+ physmap->name = (char *)mr->name;
physmap->phys_offset = phys_offset;
QLIST_INSERT_HEAD(&state->physmap, physmap, list);
@@ -283,6 +309,30 @@ go_physmap:
start_addr >> TARGET_PAGE_BITS,
(start_addr + size) >> TARGET_PAGE_BITS,
XEN_DOMCTL_MEM_CACHEATTR_WB);
+
+ snprintf(path, sizeof(path),
+ "/local/domain/0/device-model/%d/physmap/%"PRIx64"/start_addr",
+ xen_domid, (uint64_t)phys_offset);
+ snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)start_addr);
+ if (!xs_write(state->xenstore, 0, path, value, strlen(value))) {
+ return -1;
+ }
+ snprintf(path, sizeof(path),
+ "/local/domain/0/device-model/%d/physmap/%"PRIx64"/size",
+ xen_domid, (uint64_t)phys_offset);
+ snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)size);
+ if (!xs_write(state->xenstore, 0, path, value, strlen(value))) {
+ return -1;
+ }
+ if (mr->name) {
+ snprintf(path, sizeof(path),
+ "/local/domain/0/device-model/%d/physmap/%"PRIx64"/name",
+ xen_domid, (uint64_t)phys_offset);
+ if (!xs_write(state->xenstore, 0, path, mr->name, strlen(mr->name))) {
+ return -1;
+ }
+ }
+
return 0;
}
@@ -942,6 +992,55 @@ int xen_init(void)
return 0;
}
+static void xen_read_physmap(XenIOState *state)
+{
+ XenPhysmap *physmap = NULL;
+ unsigned int len, num, i;
+ char path[80], *value = NULL;
+ char **entries = NULL;
+
+ snprintf(path, sizeof(path),
+ "/local/domain/0/device-model/%d/physmap", xen_domid);
+ entries = xs_directory(state->xenstore, 0, path, &num);
+ if (entries == NULL)
+ return;
+
+ for (i = 0; i < num; i++) {
+ physmap = g_malloc(sizeof (XenPhysmap));
+ physmap->phys_offset = strtoull(entries[i], NULL, 16);
+ snprintf(path, sizeof(path),
+ "/local/domain/0/device-model/%d/physmap/%s/start_addr",
+ xen_domid, entries[i]);
+ value = xs_read(state->xenstore, 0, path, &len);
+ if (value == NULL) {
+ free(physmap);
+ continue;
+ }
+ physmap->start_addr = strtoull(value, NULL, 16);
+ free(value);
+
+ snprintf(path, sizeof(path),
+ "/local/domain/0/device-model/%d/physmap/%s/size",
+ xen_domid, entries[i]);
+ value = xs_read(state->xenstore, 0, path, &len);
+ if (value == NULL) {
+ free(physmap);
+ continue;
+ }
+ physmap->size = strtoull(value, NULL, 16);
+ free(value);
+
+ snprintf(path, sizeof(path),
+ "/local/domain/0/device-model/%d/physmap/%s/name",
+ xen_domid, entries[i]);
+ physmap->name = xs_read(state->xenstore, 0, path, &len);
+
+ QLIST_INSERT_HEAD(&state->physmap, physmap, list);
+ }
+ free(entries);
+ return;
+}
+
int xen_hvm_init(void)
{
int i, rc;
@@ -999,7 +1098,7 @@ int xen_hvm_init(void)
}
/* Init RAM management */
- xen_map_cache_init();
+ xen_map_cache_init(xen_phys_offset_to_gaddr, state);
xen_ram_init(ram_size);
qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state);
@@ -1017,6 +1116,7 @@ int xen_hvm_init(void)
xen_be_register("console", &xen_console_ops);
xen_be_register("vkbd", &xen_kbdmouse_ops);
xen_be_register("qdisk", &xen_blkdev_ops);
+ xen_read_physmap(state);
return 0;
}
diff --git a/xen-mapcache.c b/xen-mapcache.c
index 585b559c73..a456479363 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -78,6 +78,9 @@ typedef struct MapCache {
uint8_t *last_address_vaddr;
unsigned long max_mcache_size;
unsigned int mcache_bucket_shift;
+
+ phys_offset_to_gaddr_t phys_offset_to_gaddr;
+ void *opaque;
} MapCache;
static MapCache *mapcache;
@@ -91,13 +94,16 @@ static inline int test_bits(int nr, int size, const unsigned long *addr)
return 0;
}
-void xen_map_cache_init(void)
+void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
{
unsigned long size;
struct rlimit rlimit_as;
mapcache = g_malloc0(sizeof (MapCache));
+ mapcache->phys_offset_to_gaddr = f;
+ mapcache->opaque = opaque;
+
QTAILQ_INIT(&mapcache->locked_entries);
mapcache->last_address_index = -1;
@@ -193,9 +199,14 @@ uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size,
uint8_t lock)
{
MapCacheEntry *entry, *pentry = NULL;
- target_phys_addr_t address_index = phys_addr >> MCACHE_BUCKET_SHIFT;
- target_phys_addr_t address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1);
+ target_phys_addr_t address_index;
+ target_phys_addr_t address_offset;
target_phys_addr_t __size = size;
+ bool translated = false;
+
+tryagain:
+ address_index = phys_addr >> MCACHE_BUCKET_SHIFT;
+ address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1);
trace_xen_map_cache(phys_addr);
@@ -237,6 +248,11 @@ uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size,
if(!test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
mapcache->last_address_index = -1;
+ if (!translated && mapcache->phys_offset_to_gaddr) {
+ phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size, mapcache->opaque);
+ translated = true;
+ goto tryagain;
+ }
trace_xen_map_cache_return(NULL);
return NULL;
}
diff --git a/xen-mapcache.h b/xen-mapcache.h
index da874ca23d..70301a57e4 100644
--- a/xen-mapcache.h
+++ b/xen-mapcache.h
@@ -11,9 +11,13 @@
#include <stdlib.h>
+typedef target_phys_addr_t (*phys_offset_to_gaddr_t)(target_phys_addr_t start_addr,
+ ram_addr_t size,
+ void *opaque);
#ifdef CONFIG_XEN
-void xen_map_cache_init(void);
+void xen_map_cache_init(phys_offset_to_gaddr_t f,
+ void *opaque);
uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size,
uint8_t lock);
ram_addr_t xen_ram_addr_from_mapcache(void *ptr);
@@ -22,7 +26,8 @@ void xen_invalidate_map_cache(void);
#else
-static inline void xen_map_cache_init(void)
+static inline void xen_map_cache_init(phys_offset_to_gaddr_t f,
+ void *opaque)
{
}