@@ -2484,3 +2484,129 @@ void dump_drift_info(void)
qemu_printf("Max guest advance NA\n");
}
}
+
+static Bytes *memread(int64_t addr, int64_t size, CPUState *cpu, Error **errp)
+{
+ uint32_t l = 0;
+ uint8List *prev = NULL;
+ Bytes *res;
+ uint8_t buf[8];
+
+ if (size <= 0 || size > sizeof(buf)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "size",
+ "out of range");
+ return NULL;
+ }
+
+ if (cpu) {
+ if (cpu_memory_rw_debug(cpu, addr, buf, size, 0) != 0) {
+ error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRId64
+ " specified", addr, size);
+ return NULL;
+ }
+ } else {
+ MemTxResult r = address_space_read(&address_space_memory, addr,
+ MEMTXATTRS_UNSPECIFIED, buf, l);
+ if (r != MEMTX_OK) {
+ error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRId64
+ " specified", addr, size);
+ return NULL;
+ }
+ }
+
+ res = g_new0(Bytes, 1);
+ while (l < size) {
+ uint8List *cur = g_new0(uint8List, 1);
+ cur->value = buf[l++];
+ if (!prev) {
+ res->bytes = cur;
+ } else {
+ prev->next = cur;
+ }
+ prev = cur;
+ }
+
+ return res;
+
+}
+
+Bytes *qmp_memread(int64_t addr, int64_t size,
+ bool has_cpu, int64_t cpu_index, Error **errp)
+{
+ CPUState *cpu;
+
+ if (!has_cpu) {
+ cpu_index = 0;
+ }
+
+ cpu = qemu_get_cpu(cpu_index);
+ if (cpu == NULL) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
+ "a CPU number");
+ return NULL;
+ }
+
+ return memread(addr, size, cpu, errp);
+}
+
+Bytes *qmp_pmemread(int64_t addr, int64_t size, Error **errp)
+{
+ return memread(addr, size, NULL, errp);
+}
+
+static void memwrite(int64_t addr, uint8List *bytes, CPUState *cpu,
+ Error **errp)
+{
+ uint32_t l = 0;
+ uint8_t buf[8];
+
+ while (bytes != NULL) {
+ if (l >= sizeof(buf)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "bytes",
+ "too long");
+ return;
+ }
+ buf[l++] = bytes->value;
+ bytes = bytes->next;
+ }
+
+ if (cpu) {
+ if (cpu_memory_rw_debug(cpu, addr, buf, l, 1) != 0) {
+ error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRIu32
+ " specified", addr, l);
+ return;
+ }
+ } else {
+ MemTxResult r = address_space_write(&address_space_memory, addr,
+ MEMTXATTRS_UNSPECIFIED, buf, l);
+ if (r != MEMTX_OK) {
+ error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRId64
+ " specified", addr, size);
+ return;
+ }
+ }
+}
+
+void qmp_memwrite(int64_t addr, uint8List *bytes,
+ bool has_cpu, int64_t cpu_index, Error **errp)
+{
+ CPUState *cpu;
+
+ if (!has_cpu) {
+ cpu_index = 0;
+ }
+
+ cpu = qemu_get_cpu(cpu_index);
+ if (cpu == NULL) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
+ "a CPU number");
+ return;
+ }
+
+ memwrite(addr, bytes, cpu, errp);
+}
+
+void qmp_pmemwrite(int64_t addr, uint8List *bytes, Error **errp)
+{
+ memwrite(addr, bytes, NULL, errp);
+}
@@ -3047,3 +3047,122 @@
'data': 'NumaOptions',
'allow-preconfig': true
}
+
+##
+# @Bytes:
+#
+# An array of bytes.
+#
+# @bytes: the list of bytes
+#
+# Since: 4.1
+##
+{ 'struct': 'Bytes', 'data': {'bytes': ['uint8'] } }
+
+##
+# @memread:
+#
+# Read a portion of guest memory.
+#
+# @addr: the virtual address of the guest to read from
+#
+# @size: the size of memory region to read (max is 8)
+#
+# @cpu-index: the index of the virtual CPU to use for translating the
+# virtual address (defaults to CPU 0)
+#
+# Returns: The read bytes
+#
+# Since: 4.1
+#
+# Example:
+#
+# -> { "execute": "memread",
+# "arguments": { "addr": 10,
+# "size": 4 } }
+# <- { "return": { 'bytes' : [10, 78, 231, 7] } }
+#
+##
+{ 'command': 'memread',
+ 'data': {'addr': 'int', 'size': 'int', '*cpu-index': 'int'},
+ 'returns' : 'Bytes'
+}
+
+##
+# @memwrite:
+#
+# Write a portion of guest memory.
+#
+# @addr: the virtual address of the guest to write to
+#
+# @bytes: the bytes to write into memory region (max length is 8)
+#
+# @cpu-index: the index of the virtual CPU to use for translating the
+# virtual address (defaults to CPU 0)
+#
+# Since: 4.1
+#
+# Returns: nothing on success.
+#
+# Example:
+#
+# -> { "execute": "memread",
+# "arguments": { "addr": 10,
+# "bytes": [10, 78, 231, 7] } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'memwrite',
+ 'data': {'addr': 'int', 'bytes': ['uint8'], '*cpu-index': 'int'}
+}
+
+##
+# @pmemread:
+#
+# Read a portion of guest memory.
+#
+# @addr: the physical address of the guest to read from
+#
+# @size: the size of memory region to read (max is 8)
+#
+# Returns: The read bytes
+#
+# Since: 4.1
+#
+# Example:
+#
+# -> { "execute": "memread",
+# "arguments": { "addr": 10,
+# "size": 4 } }
+# <- { "return": { 'bytes' : [10, 78, 231, 7] } }
+#
+##
+{ 'command': 'pmemread',
+ 'data': {'addr': 'int', 'size': 'int'},
+ 'returns' : 'Bytes'
+}
+
+##
+# @pmemwrite:
+#
+# Write a portion of guest memory.
+#
+# @addr: the physical address of the guest to write to
+#
+# @bytes: the bytes to write into memory region (max length is 8)
+#
+# Since: 4.1
+#
+# Returns: nothing on success.
+#
+# Example:
+#
+# -> { "execute": "memread",
+# "arguments": { "addr": 10,
+# "bytes": [10, 78, 231, 7] } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'pmemwrite',
+ 'data': {'addr': 'int', 'bytes': ['uint8']}
+}
This introduces memread, memwrite, pmemread and pmemwrite qmp commands. The memread and memwrite read virtual memory from a given cpu point of view. If no cpu index is specified, the cpu-id 0 is used. The pmemread and pmemwrite directly read physical memory. The data is passed/returned in a list of bytes. The maximum length is set to 8, they can be used to 64bits. This is based on the work of Frederic Konrad. Signed-off-by: Damien Hedde <damien.hedde@greensocs.com> --- cpus.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++ qapi/misc.json | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+)