diff --git a/cpus.c b/cpus.c index 1104d61..03d1277 100644 --- a/cpus.c +++ b/cpus.c @@ -1467,6 +1467,30 @@ exit: fclose(f); } +void qmp_pmemload(int64_t addr, int64_t size, const char *filename, + Error **errp) +{ + FILE *f; + uint32_t l; + uint8_t buf[1024]; + + f = fopen(filename, "rb"); + if (!f) { + error_setg_file_open(errp, errno, filename); + return; + } + + while (size != 0) { + l = fread(buf, 1, sizeof(buf), f); + if (l > size) + l = size; + cpu_physical_memory_rw(addr, buf, l, 1); + addr += l; + size -= l; + } + + fclose(f); +} void qmp_inject_nmi(Error **errp) { #if defined(TARGET_I386) diff --git a/hmp-commands.hx b/hmp-commands.hx index f3fc514..75d162e 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -803,12 +803,25 @@ ETEXI }, STEXI address@hidden pmemsave @var{addr} @var{size} @var{file} address@hidden pmemsave -save to disk physical memory dump starting at @var{addr} of size @var{size}. address@hidden pmemload @var{addr} @var{size} @var{file} address@hidden pmemload +load from disk physical memory dump starting at @var{addr} of size @var{size}. ETEXI { + .name = "pmemload", + .args_type = "val:l,size:i,filename:s", + .params = "addr size file", + .help = "load from disk physical memory dump starting at 'addr' of size 'size'", + .mhandler.cmd = hmp_pmemload, + }, + +STEXI address@hidden pmemload @var{addr} @var{size} @var{file} address@hidden pmemload +save to disk physical memory dump starting at @var{addr} of size @var{size}. +ETEXI + { .name = "boot_set", .args_type = "bootdevice:s", .params = "bootdevice", diff --git a/hmp.c b/hmp.c index 2f279c4..6e932f9 100644 --- a/hmp.c +++ b/hmp.c @@ -767,6 +767,17 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &errp); } +void hmp_pmemload(Monitor *mon, const QDict *qdict) +{ + uint32_t size = qdict_get_int(qdict, "size"); + const char *filename = qdict_get_str(qdict, "filename"); + uint64_t addr = qdict_get_int(qdict, "val"); + Error *errp = NULL; + + qmp_pmemload(addr, size, filename, &errp); + hmp_handle_error(mon, &errp); +} + void hmp_ringbuf_write(Monitor *mon, const QDict *qdict) { const char *chardev = qdict_get_str(qdict, "device"); diff --git a/hmp.h b/hmp.h index ed58f0e..f5f2a16 100644 --- a/hmp.h +++ b/hmp.h @@ -44,6 +44,7 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict); void hmp_cpu(Monitor *mon, const QDict *qdict); void hmp_memsave(Monitor *mon, const QDict *qdict); void hmp_pmemsave(Monitor *mon, const QDict *qdict); +void hmp_pmemload(Monitor *mon, const QDict *qdict); void hmp_ringbuf_write(Monitor *mon, const QDict *qdict); void hmp_ringbuf_read(Monitor *mon, const QDict *qdict); void hmp_cont(Monitor *mon, const QDict *qdict); diff --git a/qapi-schema.json b/qapi-schema.json index 391356f..f511ff3 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1708,6 +1708,26 @@ 'data': {'val': 'int', 'size': 'int', 'filename': 'str'} } ## +# @pmemload: +# +# Load a portion of guest physical memory from a file. +# +# @val: the physical address of the guest to start from +# +# @size: the size of memory region to save +# +# @filename: the file to load the memory from as binary data +# +# Returns: Nothing on success +# +# Since: 2.0 +# +# Notes: Errors were not reliably returned until 1.1 +## +{ 'command': 'pmemload', + 'data': {'val': 'int', 'size': 'int', 'filename': 'str'} } + +## # @cont: # # Resume guest VCPU execution. diff --git a/qmp-commands.hx b/qmp-commands.hx index ed3ab92..584d6cf 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -468,6 +468,33 @@ Example: EQMP { + .name = "pmemload", + .args_type = "val:l,size:i,filename:s", + .mhandler.cmd_new = qmp_marshal_input_pmemload, + }, + +SQMP +pmemload +-------- + +load from disk physical memory dump starting at 'val' of size 'size'. + +Arguments: + +- "val": the starting address (json-int) +- "size": the memory size, in bytes (json-int) +- "filename": file path (json-string) + +Example: + +-> { "execute": "pmemload", + "arguments": { "val": 10, + "size": 100, + "filename": "/tmp/physical-mem-dump" } } +<- { "return": {} } + +EQMP + { .name = "inject-nmi", .args_type = "", .mhandler.cmd_new = qmp_marshal_input_inject_nmi,