[Qemu-devel] [PATCH v8 03/27] gdbstub: Implement thread_alive (T pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 43 ---
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 621d689868..c47ef7dd9c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1498,6 +1498,30 @@ static void handle_detach(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(s, "OK");
 }
 
+static void handle_thread_alive(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+  gdb_ctx->params[0].thread_id.tid);
+if (!cpu) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1798,17 +1822,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'T':
-thread_kind = read_thread_id(p, &p, &pid, &tid);
-if (thread_kind == GDB_READ_THREAD_ERR) {
-put_packet(s, "E22");
-break;
-}
-cpu = gdb_get_cpu(s, pid, tid);
-
-if (cpu != NULL) {
-put_packet(s, "OK");
-} else {
-put_packet(s, "E22");
+{
+static const GdbCmdParseEntry thread_alive_cmd_desc = {
+.handler = handle_thread_alive,
+.cmd = "T",
+.cmd_startswith = 1,
+.schema = "t0"
+};
+cmd_parser = &thread_alive_cmd_desc;
 }
 break;
 case 'q':
-- 
2.20.1




[Qemu-devel] [PATCH v8 01/27] gdbstub: Add infrastructure to parse cmd packets

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 200 ++
 1 file changed, 200 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index d54abd17cc..d5e0f3878a 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1268,6 +1268,206 @@ out:
 return res;
 }
 
+typedef union GdbCmdVariant {
+const char *data;
+uint8_t opcode;
+unsigned long val_ul;
+unsigned long long val_ull;
+struct {
+GDBThreadIdKind kind;
+uint32_t pid;
+uint32_t tid;
+} thread_id;
+} GdbCmdVariant;
+
+static const char *cmd_next_param(const char *param, const char delimiter)
+{
+static const char all_delimiters[] = ",;:=";
+char curr_delimiters[2] = {0};
+const char *delimiters;
+
+if (delimiter == '?') {
+delimiters = all_delimiters;
+} else if (delimiter == '0') {
+return strchr(param, '\0');
+} else if (delimiter == '.' && *param) {
+return param + 1;
+} else {
+curr_delimiters[0] = delimiter;
+delimiters = curr_delimiters;
+}
+
+param += strcspn(param, delimiters);
+if (*param) {
+param++;
+}
+return param;
+}
+
+static int cmd_parse_params(const char *data, const char *schema,
+GdbCmdVariant *params, int *num_params)
+{
+int curr_param;
+const char *curr_schema, *curr_data;
+
+*num_params = 0;
+
+if (!schema) {
+return 0;
+}
+
+curr_schema = schema;
+curr_param = 0;
+curr_data = data;
+while (curr_schema[0] && curr_schema[1] && *curr_data) {
+switch (curr_schema[0]) {
+case 'l':
+if (qemu_strtoul(curr_data, &curr_data, 16,
+ ¶ms[curr_param].val_ul)) {
+return -EINVAL;
+}
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 'L':
+if (qemu_strtou64(curr_data, &curr_data, 16,
+  (uint64_t *)¶ms[curr_param].val_ull)) {
+return -EINVAL;
+}
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 's':
+params[curr_param].data = curr_data;
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 'o':
+params[curr_param].opcode = *(uint8_t *)curr_data;
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 't':
+params[curr_param].thread_id.kind =
+read_thread_id(curr_data, &curr_data,
+   ¶ms[curr_param].thread_id.pid,
+   ¶ms[curr_param].thread_id.tid);
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case '?':
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+default:
+return -EINVAL;
+}
+curr_schema += 2;
+}
+
+*num_params = curr_param;
+return 0;
+}
+
+typedef struct GdbCmdContext {
+GDBState *s;
+GdbCmdVariant *params;
+int num_params;
+uint8_t mem_buf[MAX_PACKET_LENGTH];
+char str_buf[MAX_PACKET_LENGTH + 1];
+} GdbCmdContext;
+
+typedef void (*GdbCmdHandler)(GdbCmdContext *gdb_ctx, void *user_ctx);
+
+/*
+ * cmd_startswith -> cmd is compared using startswith
+ *
+ *
+ * schema definitions:
+ * Each schema parameter entry consists of 2 chars,
+ * the first char represents the parameter type handling
+ * the second char represents the delimiter for the next parameter
+ *
+ * Currently supported schema types:
+ * 'l' -> unsigned long (stored in .val_ul)
+ * 'L' -> unsigned long long (stored in .val_ull)
+ * 's' -> string (stored in .data)
+ * 'o' -> single char (stored in .opcode)
+ * 't' -> thread id (stored in .thread_id)
+ * '?' -> skip according to delimiter
+ *
+ * Currently supported delimiters:
+ * '?' -> Stop at any delimiter (",;:=\0")
+ * '0' -> Stop at "\0"
+ * '.' -> Skip 1 char unless reached "\0"
+ * Any other value is treated as the delimiter value itself
+ */
+typedef struct GdbCmdParseEntry {
+GdbCmdHandler handler;
+const char *cmd;
+union {
+int flags;
+struct {
+int cmd_startswith:1;
+};
+};
+const char *schema;
+} GdbCmdParseEntry;
+
+static inline int startswith(const char *string, const char *pattern)
+{
+  return !strncmp(string, pattern, strlen(pattern));
+}
+
+static int process_string_cmd(

[Qemu-devel] [PATCH v8 09/27] gdbstub: Implement set register (P pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 39 ++-
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index b42425b24c..10e3f12a68 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1634,6 +1634,27 @@ static void handle_remove_bp(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "E22");
 }
 
+static void handle_set_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int reg_size;
+
+if (!gdb_has_xml) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+reg_size = strlen(gdb_ctx->params[1].data) / 2;
+hextomem(gdb_ctx->mem_buf, gdb_ctx->params[1].data, reg_size);
+gdb_write_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+   gdb_ctx->params[0].val_ull);
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1878,15 +1899,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'P':
-if (!gdb_has_xml)
-goto unknown_command;
-addr = strtoull(p, (char **)&p, 16);
-if (*p == '=')
-p++;
-reg_size = strlen(p) / 2;
-hextomem(mem_buf, p, reg_size);
-gdb_write_register(s->g_cpu, mem_buf, addr);
-put_packet(s, "OK");
+{
+static const GdbCmdParseEntry set_reg_cmd_desc = {
+.handler = handle_set_reg,
+.cmd = "P",
+.cmd_startswith = 1,
+.schema = "L?s0"
+};
+cmd_parser = &set_reg_cmd_desc;
+}
 break;
 case 'Z':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v8 00/27] gdbstub: Refactor command packets handler

2019-05-02 Thread Jon Doron
This patch series refactors the old gdbstub command packets handler
with a new infrastructure which should ease extending and adding new
and missing gdb command packets.

version 8 changes:
- Add new command to display the Supported qemu generic query/sets
- kvm: Add API to read/write a MSR
- Add new commands specific for qemu:
  * Command to swap the memory GDB sees to be the physical memory
  * Commands to read and write a MSR

version 7 changes:
- Fixed few checkpatch complaints
- Feedback from Alex Bennee

version 4-6 changes:
- mostly feedback from Richard Henderson

version 3 changes
- Split the single patch to many individual patches for easier reviewing

version 2 changes
- Code convention fixes

Jon Doron (27):
  gdbstub: Add infrastructure to parse cmd packets
  gdbstub: Implement deatch (D pkt) with new infra
  gdbstub: Implement thread_alive (T pkt) with new infra
  gdbstub: Implement continue (c pkt) with new infra
  gdbstub: Implement continue with signal (C pkt) with new infra
  gdbstub: Implement set_thread (H pkt) with new infra
  gdbstub: Implement insert breakpoint (Z pkt) with new infra
  gdbstub: Implement remove breakpoint (z pkt) with new infra
  gdbstub: Implement set register (P pkt) with new infra
  gdbstub: Implement get register (p pkt) with new infra
  gdbstub: Implement write memory (M pkt) with new infra
  gdbstub: Implement read memory (m pkt) with new infra
  gdbstub: Implement write all registers (G pkt) with new infra
  gdbstub: Implement read all registers (g pkt) with new infra
  gdbstub: Implement file io (F pkt) with new infra
  gdbstub: Implement step (s pkt) with new infra
  gdbstub: Implement v commands with new infra
  gdbstub: Implement generic query (q pkt) with new infra
  gdbstub: Implement generic set (Q pkt) with new infra
  gdbstub: Implement target halted (? pkt) with new infra
  gdbstub: Clear unused variables in gdb_handle_packet
  gdbstub: Implement generic query qemu.Supported
  gdbstub: Implement qemu physical memory mode
  gdbstub: Add another handler for setting qemu.sstep
  kvm: Add API to read/write a CPU MSR value
  gdbstub: Add support to read a MSR for KVM target
  gdbstub: Add support to write a MSR for KVM target

 accel/kvm/kvm-all.c  |   39 +
 gdbstub.c| 1807 ++
 include/sysemu/kvm.h |2 +
 3 files changed, 1359 insertions(+), 489 deletions(-)

-- 
2.20.1




[Qemu-devel] [PATCH v8 02/27] gdbstub: Implement deatch (D pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 90 ++-
 1 file changed, 50 insertions(+), 40 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index d5e0f3878a..621d689868 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1418,11 +1418,6 @@ static inline int startswith(const char *string, const 
char *pattern)
   return !strncmp(string, pattern, strlen(pattern));
 }
 
-static int process_string_cmd(
-GDBState *s, void *user_ctx, const char *data,
-const GdbCmdParseEntry *cmds, int num_cmds)
-__attribute__((unused));
-
 static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
   const GdbCmdParseEntry *cmds, int num_cmds)
 {
@@ -1468,6 +1463,41 @@ static int process_string_cmd(GDBState *s, void 
*user_ctx, const char *data,
 return -1;
 }
 
+static void handle_detach(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+GDBProcess *process;
+GDBState *s = gdb_ctx->s;
+uint32_t pid = 1;
+
+if (s->multiprocess) {
+if (!gdb_ctx->num_params) {
+put_packet(s, "E22");
+return;
+}
+
+pid = gdb_ctx->params[0].val_ul;
+}
+
+process = gdb_get_process(s, pid);
+gdb_process_breakpoint_remove_all(s, process);
+process->attached = false;
+
+if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
+s->c_cpu = gdb_first_attached_cpu(s);
+}
+
+if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
+s->g_cpu = gdb_first_attached_cpu(s);
+}
+
+if (!s->c_cpu) {
+/* No more process attached */
+gdb_syscall_mode = GDB_SYS_DISABLED;
+gdb_continue(s);
+}
+put_packet(s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1482,6 +1512,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t *registers;
 target_ulong addr, len;
 GDBThreadIdKind thread_kind;
+const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
 
@@ -1582,42 +1613,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 error_report("QEMU: Terminated via GDBstub");
 exit(0);
 case 'D':
-/* Detach packet */
-pid = 1;
-
-if (s->multiprocess) {
-unsigned long lpid;
-if (*p != ';') {
-put_packet(s, "E22");
-break;
-}
-
-if (qemu_strtoul(p + 1, &p, 16, &lpid)) {
-put_packet(s, "E22");
-break;
-}
-
-pid = lpid;
-}
-
-process = gdb_get_process(s, pid);
-gdb_process_breakpoint_remove_all(s, process);
-process->attached = false;
-
-if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
-s->c_cpu = gdb_first_attached_cpu(s);
-}
-
-if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
-s->g_cpu = gdb_first_attached_cpu(s);
-}
-
-if (s->c_cpu == NULL) {
-/* No more process attached */
-gdb_syscall_mode = GDB_SYS_DISABLED;
-gdb_continue(s);
+{
+static const GdbCmdParseEntry detach_cmd_desc = {
+.handler = handle_detach,
+.cmd = "D",
+.cmd_startswith = 1,
+.schema = "?.l0"
+};
+cmd_parser = &detach_cmd_desc;
 }
-put_packet(s, "OK");
 break;
 case 's':
 if (*p != '\0') {
@@ -1990,6 +1994,12 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, buf);
 break;
 }
+
+if (cmd_parser &&
+process_string_cmd(s, NULL, line_buf, cmd_parser, 1)) {
+put_packet(s, "");
+}
+
 return RS_IDLE;
 }
 
-- 
2.20.1




[Qemu-devel] [PATCH v8 10/27] gdbstub: Implement get register (p pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 50 ++
 1 file changed, 38 insertions(+), 12 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 10e3f12a68..e9a3d0c2bc 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1655,6 +1655,36 @@ static void handle_set_reg(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int reg_size;
+
+/*
+ * Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
+ * This works, but can be very slow.  Anything new enough to
+ * understand XML also knows how to use this properly.
+ */
+if (!gdb_has_xml) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+reg_size = gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+ gdb_ctx->params[0].val_ull);
+if (!reg_size) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, reg_size);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1884,18 +1914,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'p':
-/* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
-   This works, but can be very slow.  Anything new enough to
-   understand XML also knows how to use this properly.  */
-if (!gdb_has_xml)
-goto unknown_command;
-addr = strtoull(p, (char **)&p, 16);
-reg_size = gdb_read_register(s->g_cpu, mem_buf, addr);
-if (reg_size) {
-memtohex(buf, mem_buf, reg_size);
-put_packet(s, buf);
-} else {
-put_packet(s, "E14");
+{
+static const GdbCmdParseEntry get_reg_cmd_desc = {
+.handler = handle_get_reg,
+.cmd = "p",
+.cmd_startswith = 1,
+.schema = "L0"
+};
+cmd_parser = &get_reg_cmd_desc;
 }
 break;
 case 'P':
-- 
2.20.1




[Qemu-devel] [PATCH v8 17/27] gdbstub: Implement v commands with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 170 +++---
 1 file changed, 110 insertions(+), 60 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 9b0556f8be..d56d0fd235 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1815,6 +1815,106 @@ static void handle_step(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_v_cont_query(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+put_packet(gdb_ctx->s, "vCont;c;C;s;S");
+}
+
+static void handle_v_cont(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int res;
+
+if (!gdb_ctx->num_params) {
+return;
+}
+
+res = gdb_handle_vcont(gdb_ctx->s, gdb_ctx->params[0].data);
+if ((res == -EINVAL) || (res == -ERANGE)) {
+put_packet(gdb_ctx->s, "E22");
+} else if (res) {
+put_packet(gdb_ctx->s, "\0");
+}
+}
+
+static void handle_v_attach(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+GDBProcess *process;
+CPUState *cpu;
+char thread_id[16];
+
+strcpy(gdb_ctx->str_buf, "E22");
+if (!gdb_ctx->num_params) {
+goto cleanup;
+}
+
+process = gdb_get_process(gdb_ctx->s, gdb_ctx->params[0].val_ul);
+if (!process) {
+goto cleanup;
+}
+
+cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+if (!cpu) {
+goto cleanup;
+}
+
+process->attached = true;
+gdb_ctx->s->g_cpu = cpu;
+gdb_ctx->s->c_cpu = cpu;
+
+gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
+ GDB_SIGNAL_TRAP, thread_id);
+cleanup:
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+/* Kill the target */
+put_packet(gdb_ctx->s, "OK");
+error_report("QEMU: Terminated via GDBstub");
+exit(0);
+}
+
+static GdbCmdParseEntry gdb_v_commands_table[] = {
+/* Order is important if has same prefix */
+{
+.handler = handle_v_cont_query,
+.cmd = "Cont?",
+.cmd_startswith = 1
+},
+{
+.handler = handle_v_cont,
+.cmd = "Cont",
+.cmd_startswith = 1,
+.schema = "s0"
+},
+{
+.handler = handle_v_attach,
+.cmd = "Attach;",
+.cmd_startswith = 1,
+.schema = "l0"
+},
+{
+.handler = handle_v_kill,
+.cmd = "Kill;",
+.cmd_startswith = 1
+},
+};
+
+static void handle_v_commands(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!gdb_ctx->num_params) {
+return;
+}
+
+if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+   gdb_v_commands_table,
+   ARRAY_SIZE(gdb_v_commands_table))) {
+put_packet(gdb_ctx->s, "");
+}
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1822,7 +1922,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 CPUClass *cc;
 const char *p;
 uint32_t pid, tid;
-int ch, type, res;
+int ch, type;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
@@ -1871,66 +1971,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'v':
-if (strncmp(p, "Cont", 4) == 0) {
-p += 4;
-if (*p == '?') {
-put_packet(s, "vCont;c;C;s;S");
-break;
-}
-
-res = gdb_handle_vcont(s, p);
-
-if (res) {
-if ((res == -EINVAL) || (res == -ERANGE)) {
-put_packet(s, "E22");
-break;
-}
-goto unknown_command;
-}
-break;
-} else if (strncmp(p, "Attach;", 7) == 0) {
-unsigned long pid;
-
-p += 7;
-
-if (qemu_strtoul(p, &p, 16, &pid)) {
-put_packet(s, "E22");
-break;
-}
-
-process = gdb_get_process(s, pid);
-
-if (process == NULL) {
-put_packet(s, "E22");
-break;
-}
-
-cpu = get_first_cpu_in_process(s, process);
-
-if (cpu == NULL) {
-/* Refuse to attach an empty process */
-put_packet(s, "E22");
-break;
-}
-
-process->attached = true;
-
-s->g_cpu = cpu;
-s->c_cpu = cpu;
-
-snprintf(buf, sizeof(buf), "T%02xthread:

[Qemu-devel] [PATCH v8 05/27] gdbstub: Implement continue with signal (C pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 30 +-
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 89f1ab6524..469aaeb875 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1532,6 +1532,21 @@ static void handle_continue(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+unsigned long signal = 0;
+
+if (gdb_ctx->num_params) {
+signal = gdb_ctx->params[0].val_ul;
+}
+
+gdb_ctx->s->signal = gdb_signal_to_target(signal);
+if (gdb_ctx->s->signal == -1) {
+gdb_ctx->s->signal = 0;
+}
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1579,11 +1594,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'C':
-s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
-if (s->signal == -1)
-s->signal = 0;
-gdb_continue(s);
-return RS_IDLE;
+{
+static const GdbCmdParseEntry cont_with_sig_cmd_desc = {
+.handler = handle_cont_with_sig,
+.cmd = "C",
+.cmd_startswith = 1,
+.schema = "l0"
+};
+cmd_parser = &cont_with_sig_cmd_desc;
+}
+break;
 case 'v':
 if (strncmp(p, "Cont", 4) == 0) {
 p += 4;
-- 
2.20.1




[Qemu-devel] [PATCH v8 27/27] gdbstub: Add support to write a MSR for KVM target

2019-05-02 Thread Jon Doron
gdb> maint packet Qqemu.kvm.Wrmsr:MsrIndex,Value

Signed-off-by: Jon Doron 
---
 gdbstub.c | 29 -
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/gdbstub.c b/gdbstub.c
index d5cdda190a..2d9a8e6942 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2145,7 +2145,8 @@ static void handle_query_qemu_supported(GdbCmdContext 
*gdb_ctx, void *user_ctx)
  "sstepbits;sstep;PhyMemMode");
 
 if (kvm_enabled()) {
-pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";kvm.Rdmsr");
+pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+";kvm.Rdmsr;kvm.Wrmsr");
 }
 
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
@@ -2196,6 +2197,26 @@ static void handle_query_kvm_read_msr(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_set_kvm_write_msr(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!kvm_enabled()) {
+return;
+}
+
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (kvm_arch_write_msr(gdbserver_state->c_cpu, gdb_ctx->params[0].val_ul,
+   gdb_ctx->params[1].val_ull)) {
+put_packet(gdb_ctx->s, "E00");
+return;
+}
+
+put_packet(gdb_ctx->s, "OK");
+}
+
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
 /* Order is important if has same prefix */
 {
@@ -2302,6 +2323,12 @@ static GdbCmdParseEntry gdb_gen_set_table[] = {
 .cmd_startswith = 1,
 .schema = "l0"
 },
+{
+.handler = handle_set_kvm_write_msr,
+.cmd = "qemu.kvm.Wrmsr:",
+.cmd_startswith = 1,
+.schema = "l,L0"
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




[Qemu-devel] [PATCH v8 23/27] gdbstub: Implement qemu physical memory mode

2019-05-02 Thread Jon Doron
Add a new query/set which changes the memory GDB sees to physical memory
only.

gdb> maint packet qqemu.PhyMemMode
will reply the current phy_mem_mode state (1 for enabled, 0 for disabled)
gdb> maint packet Qqemu.PhyMemMode:1
Will make GDB read/write only to physical memory, set to 0 to disable

Signed-off-by: Jon Doron 
---
 gdbstub.c | 58 ---
 1 file changed, 55 insertions(+), 3 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 00c07d6ec0..6daf779af4 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -46,11 +46,23 @@
 #define GDB_ATTACHED "1"
 #endif
 
+static int phy_memory_mode = 0;
+
 static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
  uint8_t *buf, int len, bool is_write)
 {
-CPUClass *cc = CPU_GET_CLASS(cpu);
+CPUClass *cc;
 
+if (phy_memory_mode) {
+if (is_write) {
+cpu_physical_memory_write(addr, buf, len);
+} else {
+cpu_physical_memory_read(addr, buf, len);
+}
+return 0;
+}
+
+cc = CPU_GET_CLASS(cpu);
 if (cc->memory_rw_debug) {
 return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
 }
@@ -2129,7 +2141,29 @@ static void handle_query_attached(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 
 static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-put_packet(gdb_ctx->s, "sstepbits;sstep");
+put_packet(gdb_ctx->s, "sstepbits;sstep;PhyMemMode");
+}
+
+static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
+   void *user_ctx)
+{
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "%d", 
phy_memory_mode);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void 
*user_ctx)
+{
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (!gdb_ctx->params[0].val_ul) {
+phy_memory_mode = 0;
+} else {
+phy_memory_mode = 1;
+}
+put_packet(gdb_ctx->s, "OK");
 }
 
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
@@ -2212,6 +2246,20 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
 .handler = handle_query_qemu_supported,
 .cmd = "qemu.Supported",
 },
+{
+.handler = handle_query_qemu_phy_mem_mode,
+.cmd = "qemu.PhyMemMode",
+},
+};
+
+static GdbCmdParseEntry gdb_gen_set_table[] = {
+/* Order is important if has same prefix */
+{
+.handler = handle_set_qemu_phy_mem_mode,
+.cmd = "qemu.PhyMemMode:",
+.cmd_startswith = 1,
+.schema = "l0"
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2245,7 +2293,11 @@ static void handle_gen_set(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 return;
 }
 
-put_packet(gdb_ctx->s, "");
+if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+   gdb_gen_set_table,
+   ARRAY_SIZE(gdb_gen_set_table))) {
+put_packet(gdb_ctx->s, "");
+}
 }
 
 static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




[Qemu-devel] [PATCH v8 13/27] gdbstub: Implement write all registers (G pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 41 +++--
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index daa602edc3..adfe39b3a3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1734,6 +1734,29 @@ static void handle_read_mem(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+target_ulong addr, len;
+uint8_t *registers;
+int reg_size;
+
+if (!gdb_ctx->num_params) {
+return;
+}
+
+cpu_synchronize_state(gdb_ctx->s->g_cpu);
+registers = gdb_ctx->mem_buf;
+len = strlen(gdb_ctx->params[0].data) / 2;
+hextomem(registers, gdb_ctx->params[0].data, len);
+for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs && len > 0;
+ addr++) {
+reg_size = gdb_write_register(gdb_ctx->s->g_cpu, registers, addr);
+len -= reg_size;
+registers += reg_size;
+}
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1745,7 +1768,6 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
-uint8_t *registers;
 target_ulong addr, len;
 const GdbCmdParseEntry *cmd_parser = NULL;
 
@@ -1911,16 +1933,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, buf);
 break;
 case 'G':
-cpu_synchronize_state(s->g_cpu);
-registers = mem_buf;
-len = strlen(p) / 2;
-hextomem((uint8_t *)registers, p, len);
-for (addr = 0; addr < s->g_cpu->gdb_num_g_regs && len > 0; addr++) {
-reg_size = gdb_write_register(s->g_cpu, registers, addr);
-len -= reg_size;
-registers += reg_size;
+{
+static const GdbCmdParseEntry write_all_regs_cmd_desc = {
+.handler = handle_write_all_regs,
+.cmd = "G",
+.cmd_startswith = 1,
+.schema = "s0"
+};
+cmd_parser = &write_all_regs_cmd_desc;
 }
-put_packet(s, "OK");
 break;
 case 'm':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v8 06/27] gdbstub: Implement set_thread (H pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 79 ++-
 1 file changed, 49 insertions(+), 30 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 469aaeb875..21cdaf4678 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1547,6 +1547,47 @@ static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (gdb_ctx->params[1].thread_id.kind == GDB_READ_THREAD_ERR) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (gdb_ctx->params[1].thread_id.kind != GDB_ONE_THREAD) {
+put_packet(gdb_ctx->s, "OK");
+return;
+}
+
+cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[1].thread_id.pid,
+  gdb_ctx->params[1].thread_id.tid);
+if (!cpu) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+switch (gdb_ctx->params[0].opcode) {
+case 'c':
+gdb_ctx->s->c_cpu = cpu;
+put_packet(gdb_ctx->s, "OK");
+break;
+case 'g':
+gdb_ctx->s->g_cpu = cpu;
+put_packet(gdb_ctx->s, "OK");
+break;
+default:
+put_packet(gdb_ctx->s, "E22");
+break;
+}
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1560,7 +1601,6 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 char thread_id[16];
 uint8_t *registers;
 target_ulong addr, len;
-GDBThreadIdKind thread_kind;
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
@@ -1823,35 +1863,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "E22");
 break;
 case 'H':
-type = *p++;
-
-thread_kind = read_thread_id(p, &p, &pid, &tid);
-if (thread_kind == GDB_READ_THREAD_ERR) {
-put_packet(s, "E22");
-break;
-}
-
-if (thread_kind != GDB_ONE_THREAD) {
-put_packet(s, "OK");
-break;
-}
-cpu = gdb_get_cpu(s, pid, tid);
-if (cpu == NULL) {
-put_packet(s, "E22");
-break;
-}
-switch (type) {
-case 'c':
-s->c_cpu = cpu;
-put_packet(s, "OK");
-break;
-case 'g':
-s->g_cpu = cpu;
-put_packet(s, "OK");
-break;
-default:
- put_packet(s, "E22");
- break;
+{
+static const GdbCmdParseEntry set_thread_cmd_desc = {
+.handler = handle_set_thread,
+.cmd = "H",
+.cmd_startswith = 1,
+.schema = "o.t0"
+};
+cmd_parser = &set_thread_cmd_desc;
 }
 break;
 case 'T':
-- 
2.20.1




[Qemu-devel] [PATCH v8 16/27] gdbstub: Implement step (s pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 9fe130f30d..9b0556f8be 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1805,6 +1805,16 @@ static void handle_file_io(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_step(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params) {
+gdb_set_cpu_pc(gdb_ctx->s, (target_ulong)gdb_ctx->params[0].val_ull);
+}
+
+cpu_single_step(gdb_ctx->s->c_cpu, sstep_flags);
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1937,13 +1947,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 's':
-if (*p != '\0') {
-addr = strtoull(p, (char **)&p, 16);
-gdb_set_cpu_pc(s, addr);
+{
+static const GdbCmdParseEntry step_cmd_desc = {
+.handler = handle_step,
+.cmd = "s",
+.cmd_startswith = 1,
+.schema = "L0"
+};
+cmd_parser = &step_cmd_desc;
 }
-cpu_single_step(s->c_cpu, sstep_flags);
-gdb_continue(s);
-return RS_IDLE;
+break;
 case 'F':
 {
 static const GdbCmdParseEntry file_io_cmd_desc = {
-- 
2.20.1




[Qemu-devel] [PATCH v8 24/27] gdbstub: Add another handler for setting qemu.sstep

2019-05-02 Thread Jon Doron
Follow GDB general query/set packet conventions, qemu.sstep can now
be set with the following command as well:
gdb> maint packet Qqemu.sstep:Value

Signed-off-by: Jon Doron 
---
 gdbstub.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index 6daf779af4..bceceeec57 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2260,6 +2260,12 @@ static GdbCmdParseEntry gdb_gen_set_table[] = {
 .cmd_startswith = 1,
 .schema = "l0"
 },
+{
+.handler = handle_set_qemu_sstep,
+.cmd = "qemu.sstep:",
+.cmd_startswith = 1,
+.schema = "l0"
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




[Qemu-devel] [PATCH v8 21/27] gdbstub: Clear unused variables in gdb_handle_packet

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 11 ++-
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index d678191705..8bdfae4b29 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2259,17 +2259,11 @@ static void handle_target_halt(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
-const char *p;
-int ch;
-uint8_t mem_buf[MAX_PACKET_LENGTH];
-char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
 
-p = line_buf;
-ch = *p++;
-switch(ch) {
+switch (line_buf[0]) {
 case '!':
 put_packet(s, "OK");
 break;
@@ -2486,8 +2480,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 break;
 default:
 /* put empty packet */
-buf[0] = '\0';
-put_packet(s, buf);
+put_packet(s, "");
 break;
 }
 
-- 
2.20.1




[Qemu-devel] [PATCH v8 20/27] gdbstub: Implement target halted (? pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 36 ++--
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 2fd0d66f4d..d678191705 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2239,13 +2239,30 @@ static void handle_gen_set(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, "");
 }
 
+static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+char thread_id[16];
+
+/* TODO: Make this return the correct value for user-mode.  */
+gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->c_cpu, thread_id,
+  sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
+ GDB_SIGNAL_TRAP, thread_id);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+/*
+ * Remove all the breakpoints when this query is issued,
+ * because gdb is doing and initial connect and the state
+ * should be cleaned up.
+ */
+gdb_breakpoint_remove_all();
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 const char *p;
 int ch;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
-char thread_id[16];
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
@@ -2257,15 +2274,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "OK");
 break;
 case '?':
-/* TODO: Make this return the correct value for user-mode.  */
-snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
- gdb_fmt_thread_id(s, s->c_cpu, thread_id, sizeof(thread_id)));
-put_packet(s, buf);
-/* Remove all the breakpoints when this query is issued,
- * because gdb is doing and initial connect and the state
- * should be cleaned up.
- */
-gdb_breakpoint_remove_all();
+{
+static const GdbCmdParseEntry target_halted_cmd_desc = {
+.handler = handle_target_halt,
+.cmd = "?",
+.cmd_startswith = 1
+};
+cmd_parser = &target_halted_cmd_desc;
+}
 break;
 case 'c':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v8 22/27] gdbstub: Implement generic query qemu.Supported

2019-05-02 Thread Jon Doron
qemu.Supported query reply back with the supported qemu query/set
commands (commands are seperated with a semicolon from each other).

gdb> maint packet qqemu.Supported

Signed-off-by: Jon Doron 
---
 gdbstub.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index 8bdfae4b29..00c07d6ec0 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2127,6 +2127,11 @@ static void handle_query_attached(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, GDB_ATTACHED);
 }
 
+static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+put_packet(gdb_ctx->s, "sstepbits;sstep");
+}
+
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
 /* Order is important if has same prefix */
 {
@@ -2203,6 +2208,10 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
 .handler = handle_query_attached,
 .cmd = "Attached",
 },
+{
+.handler = handle_query_qemu_supported,
+.cmd = "qemu.Supported",
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




[Qemu-devel] [PATCH v8 25/27] kvm: Add API to read/write a CPU MSR value

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 accel/kvm/kvm-all.c  | 39 +++
 include/sysemu/kvm.h |  2 ++
 2 files changed, 41 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 524c4ddfbd..35207d910b 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2444,6 +2444,45 @@ void kvm_remove_all_breakpoints(CPUState *cpu)
 }
 #endif /* !KVM_CAP_SET_GUEST_DEBUG */
 
+int kvm_arch_read_msr(CPUState *cpu, uint32_t index, uint64_t *value)
+{
+struct {
+struct kvm_msrs info;
+struct kvm_msr_entry entries[1];
+} msr_data;
+int ret;
+
+msr_data.info.nmsrs = 1;
+msr_data.entries[0].index = index;
+ret = kvm_vcpu_ioctl(cpu, KVM_GET_MSRS, &msr_data);
+if (ret < 0) {
+return ret;
+}
+
+*value = msr_data.entries[0].data;
+return 0;
+}
+
+int kvm_arch_write_msr(CPUState *cpu, uint32_t index, uint64_t value)
+{
+struct {
+struct kvm_msrs info;
+struct kvm_msr_entry entries[1];
+} msr_data;
+int ret;
+
+msr_data.info.nmsrs = 1;
+msr_data.entries[0].index = index;
+msr_data.entries[0].reserved = 0;
+msr_data.entries[0].data = value;
+ret = kvm_vcpu_ioctl(cpu, KVM_SET_MSRS, &msr_data);
+if (ret < 0) {
+return ret;
+}
+
+return 0;
+}
+
 static int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset)
 {
 KVMState *s = kvm_state;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index a6d1cd190f..409b1a5444 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -462,6 +462,8 @@ int kvm_vm_check_extension(KVMState *s, unsigned int 
extension);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
   uint32_t index, int reg);
 uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index);
+int kvm_arch_read_msr(CPUState *cpu, uint32_t index, uint64_t *value);
+int kvm_arch_write_msr(CPUState *cpu, uint32_t index, uint64_t value);
 
 
 void kvm_set_sigmask_len(KVMState *s, unsigned int sigmask_len);
-- 
2.20.1




[Qemu-devel] [PATCH v8 15/27] gdbstub: Implement file io (F pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 62 +++
 1 file changed, 40 insertions(+), 22 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 3478ac778d..9fe130f30d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1772,6 +1772,39 @@ static void handle_read_all_regs(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int num_syscall_params;
+GdbCmdVariant syscall_params[3] = {};
+
+if (!gdb_ctx->num_params) {
+return;
+}
+
+if (cmd_parse_params(gdb_ctx->params[0].data, "L,L,o0", syscall_params,
+ &num_syscall_params)) {
+return;
+}
+
+if (!num_syscall_params) {
+return;
+}
+
+if (gdb_ctx->s->current_syscall_cb) {
+gdb_ctx->s->current_syscall_cb(gdb_ctx->s->c_cpu,
+   (target_ulong)syscall_params[0].val_ull,
+   
(target_ulong)syscall_params[1].val_ull);
+gdb_ctx->s->current_syscall_cb = NULL;
+}
+
+if (syscall_params[2].opcode == (uint8_t)'C') {
+put_packet(gdb_ctx->s, "T02");
+return;
+}
+
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1913,28 +1946,13 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 return RS_IDLE;
 case 'F':
 {
-target_ulong ret;
-target_ulong err;
-
-ret = strtoull(p, (char **)&p, 16);
-if (*p == ',') {
-p++;
-err = strtoull(p, (char **)&p, 16);
-} else {
-err = 0;
-}
-if (*p == ',')
-p++;
-type = *p;
-if (s->current_syscall_cb) {
-s->current_syscall_cb(s->c_cpu, ret, err);
-s->current_syscall_cb = NULL;
-}
-if (type == 'C') {
-put_packet(s, "T02");
-} else {
-gdb_continue(s);
-}
+static const GdbCmdParseEntry file_io_cmd_desc = {
+.handler = handle_file_io,
+.cmd = "F",
+.cmd_startswith = 1,
+.schema = "s0"
+};
+cmd_parser = &file_io_cmd_desc;
 }
 break;
 case 'g':
-- 
2.20.1




[Qemu-devel] [PATCH v8 07/27] gdbstub: Implement insert breakpoint (Z pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 33 +
 1 file changed, 33 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index 21cdaf4678..36c7353a22 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1588,6 +1588,29 @@ static void handle_set_thread(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 }
 }
 
+static void handle_insert_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int res;
+
+if (gdb_ctx->num_params < 3) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+res = gdb_breakpoint_insert(gdb_ctx->params[1].val_ull,
+gdb_ctx->params[2].val_ull,
+gdb_ctx->params[0].val_ul);
+if (res >= 0) {
+put_packet(gdb_ctx->s, "OK");
+return;
+} else if (res == -ENOSYS) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+put_packet(gdb_ctx->s, "E22");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1843,6 +1866,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "OK");
 break;
 case 'Z':
+{
+static const GdbCmdParseEntry insert_bp_cmd_desc = {
+.handler = handle_insert_bp,
+.cmd = "Z",
+.cmd_startswith = 1,
+.schema = "l?L?L0"
+};
+cmd_parser = &insert_bp_cmd_desc;
+}
+break;
 case 'z':
 type = strtoul(p, (char **)&p, 16);
 if (*p == ',')
-- 
2.20.1




[Qemu-devel] [PATCH v8 08/27] gdbstub: Implement remove breakpoint (z pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 49 -
 1 file changed, 32 insertions(+), 17 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 36c7353a22..b42425b24c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1611,6 +1611,29 @@ static void handle_insert_bp(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "E22");
 }
 
+static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int res;
+
+if (gdb_ctx->num_params < 3) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+res = gdb_breakpoint_remove(gdb_ctx->params[1].val_ull,
+gdb_ctx->params[2].val_ull,
+gdb_ctx->params[0].val_ul);
+if (res >= 0) {
+put_packet(gdb_ctx->s, "OK");
+return;
+} else if (res == -ENOSYS) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+put_packet(gdb_ctx->s, "E22");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1877,23 +1900,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'z':
-type = strtoul(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-addr = strtoull(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-len = strtoull(p, (char **)&p, 16);
-if (ch == 'Z')
-res = gdb_breakpoint_insert(addr, len, type);
-else
-res = gdb_breakpoint_remove(addr, len, type);
-if (res >= 0)
- put_packet(s, "OK");
-else if (res == -ENOSYS)
-put_packet(s, "");
-else
-put_packet(s, "E22");
+{
+static const GdbCmdParseEntry remove_bp_cmd_desc = {
+.handler = handle_remove_bp,
+.cmd = "z",
+.cmd_startswith = 1,
+.schema = "l?L?L0"
+};
+cmd_parser = &remove_bp_cmd_desc;
+}
 break;
 case 'H':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v8 14/27] gdbstub: Implement read all registers (g pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 31 +++
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index adfe39b3a3..3478ac778d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1757,6 +1757,21 @@ static void handle_write_all_regs(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+target_ulong addr, len;
+
+cpu_synchronize_state(gdb_ctx->s->g_cpu);
+len = 0;
+for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs; addr++) {
+len += gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf + len,
+ addr);
+}
+
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1764,7 +1779,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 CPUClass *cc;
 const char *p;
 uint32_t pid, tid;
-int ch, reg_size, type, res;
+int ch, type, res;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
@@ -1923,14 +1938,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'g':
-cpu_synchronize_state(s->g_cpu);
-len = 0;
-for (addr = 0; addr < s->g_cpu->gdb_num_g_regs; addr++) {
-reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
-len += reg_size;
+{
+static const GdbCmdParseEntry read_all_regs_cmd_desc = {
+.handler = handle_read_all_regs,
+.cmd = "g",
+.cmd_startswith = 1
+};
+cmd_parser = &read_all_regs_cmd_desc;
 }
-memtohex(buf, mem_buf, len);
-put_packet(s, buf);
 break;
 case 'G':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v8 19/27] gdbstub: Implement generic set (Q pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 213 +++---
 1 file changed, 25 insertions(+), 188 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 83ae8738cc..2fd0d66f4d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1130,14 +1130,6 @@ static GDBThreadIdKind read_thread_id(const char *buf, 
const char **end_buf,
 return GDB_ONE_THREAD;
 }
 
-static int is_query_packet(const char *p, const char *query, char separator)
-{
-unsigned int query_len = strlen(query);
-
-return strncmp(p, query, query_len) == 0 &&
-(p[query_len] == '\0' || p[query_len] == separator);
-}
-
 /**
  * gdb_handle_vcont - Parses and handles a vCont packet.
  * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
@@ -2232,18 +2224,28 @@ static void handle_gen_query(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 }
 }
 
+static void handle_gen_set(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!gdb_ctx->num_params) {
+return;
+}
+
+if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+gdb_gen_query_set_common_table,
+ARRAY_SIZE(gdb_gen_query_set_common_table))) {
+return;
+}
+
+put_packet(gdb_ctx->s, "");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
-CPUState *cpu;
-GDBProcess *process;
-CPUClass *cc;
 const char *p;
-uint32_t pid, tid;
-int ch, type;
+int ch;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
-target_ulong addr, len;
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
@@ -2456,182 +2458,17 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'Q':
-/* parse any 'q' packets here */
-if (!strcmp(p,"qemu.sstepbits")) {
-/* Query Breakpoint bit definitions */
-snprintf(buf, sizeof(buf), "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
- SSTEP_ENABLE,
- SSTEP_NOIRQ,
- SSTEP_NOTIMER);
-put_packet(s, buf);
-break;
-} else if (is_query_packet(p, "qemu.sstep", '=')) {
-/* Display or change the sstep_flags */
-p += 10;
-if (*p != '=') {
-/* Display current setting */
-snprintf(buf, sizeof(buf), "0x%x", sstep_flags);
-put_packet(s, buf);
-break;
-}
-p++;
-type = strtoul(p, (char **)&p, 16);
-sstep_flags = type;
-put_packet(s, "OK");
-break;
-} else if (strcmp(p,"C") == 0) {
-/*
- * "Current thread" remains vague in the spec, so always return
- * the first thread of the current process (gdb returns the
- * first thread).
- */
-cpu = get_first_cpu_in_process(s, gdb_get_cpu_process(s, 
s->g_cpu));
-snprintf(buf, sizeof(buf), "QC%s",
- gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id)));
-put_packet(s, buf);
-break;
-} else if (strcmp(p,"fThreadInfo") == 0) {
-s->query_cpu = gdb_first_attached_cpu(s);
-goto report_cpuinfo;
-} else if (strcmp(p,"sThreadInfo") == 0) {
-report_cpuinfo:
-if (s->query_cpu) {
-snprintf(buf, sizeof(buf), "m%s",
- gdb_fmt_thread_id(s, s->query_cpu,
-   thread_id, sizeof(thread_id)));
-put_packet(s, buf);
-s->query_cpu = gdb_next_attached_cpu(s, s->query_cpu);
-} else
-put_packet(s, "l");
-break;
-} else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
-if (read_thread_id(p + 16, &p, &pid, &tid) == GDB_READ_THREAD_ERR) 
{
-put_packet(s, "E22");
-break;
-}
-cpu = gdb_get_cpu(s, pid, tid);
-if (cpu != NULL) {
-cpu_synchronize_state(cpu);
-
-if (s->multiprocess && (s->process_num > 1)) {
-/* Print the CPU model and name in multiprocess mode */
-ObjectClass *oc = object_get_class(OBJECT(cpu));
-const char *cpu_model = object_class_get_name(oc);
-char *cpu_name =
-object_get_canonical_path_component(OBJECT(cpu));
-len = snprintf((char *)mem_buf, sizeof(buf) / 2,

[Qemu-devel] [PATCH v8 26/27] gdbstub: Add support to read a MSR for KVM target

2019-05-02 Thread Jon Doron
gdb> maint packet qqemu.kvm.Rdmsr:MsrIndex

Signed-off-by: Jon Doron 
---
 gdbstub.c | 38 +-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/gdbstub.c b/gdbstub.c
index bceceeec57..d5cdda190a 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2141,7 +2141,14 @@ static void handle_query_attached(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 
 static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-put_packet(gdb_ctx->s, "sstepbits;sstep;PhyMemMode");
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+ "sstepbits;sstep;PhyMemMode");
+
+if (kvm_enabled()) {
+pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";kvm.Rdmsr");
+}
+
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
 static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
@@ -2166,6 +2173,29 @@ static void handle_set_qemu_phy_mem_mode(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_query_kvm_read_msr(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+uint64_t msr_val;
+
+if (!kvm_enabled()) {
+return;
+}
+
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (kvm_arch_read_msr(gdbserver_state->c_cpu, gdb_ctx->params[0].val_ul,
+  &msr_val)) {
+put_packet(gdb_ctx->s, "E00");
+return;
+}
+
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%" PRIx64, 
msr_val);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
 /* Order is important if has same prefix */
 {
@@ -2250,6 +2280,12 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
 .handler = handle_query_qemu_phy_mem_mode,
 .cmd = "qemu.PhyMemMode",
 },
+{
+.handler = handle_query_kvm_read_msr,
+.cmd = "qemu.kvm.Rdmsr:",
+.cmd_startswith = 1,
+.schema = "l0"
+},
 };
 
 static GdbCmdParseEntry gdb_gen_set_table[] = {
-- 
2.20.1




[Qemu-devel] [PATCH v8 11/27] gdbstub: Implement write memory (M pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 51 +--
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index e9a3d0c2bc..8dc2e1d507 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1685,6 +1685,31 @@ static void handle_get_reg(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_write_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params < 3) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+/* hextomem() reads 2*len bytes */
+if (gdb_ctx->params[1].val_ull > strlen(gdb_ctx->params[2].data) / 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+hextomem(gdb_ctx->mem_buf, gdb_ctx->params[2].data,
+ gdb_ctx->params[1].val_ull);
+if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
+   gdb_ctx->mem_buf,
+   gdb_ctx->params[1].val_ull, true)) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1893,24 +1918,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'M':
-addr = strtoull(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-len = strtoull(p, (char **)&p, 16);
-if (*p == ':')
-p++;
-
-/* hextomem() reads 2*len bytes */
-if (len > strlen(p) / 2) {
-put_packet (s, "E22");
-break;
-}
-hextomem(mem_buf, p, len);
-if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len,
-   true) != 0) {
-put_packet(s, "E14");
-} else {
-put_packet(s, "OK");
+{
+static const GdbCmdParseEntry write_mem_cmd_desc = {
+.handler = handle_write_mem,
+.cmd = "M",
+.cmd_startswith = 1,
+.schema = "L,L:s0"
+};
+cmd_parser = &write_mem_cmd_desc;
 }
 break;
 case 'p':
-- 
2.20.1




[Qemu-devel] [PATCH v8 12/27] gdbstub: Implement read memory (m pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 48 
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 8dc2e1d507..daa602edc3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1710,6 +1710,30 @@ static void handle_write_mem(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_read_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+/* memtohex() doubles the required space */
+if (gdb_ctx->params[1].val_ull > MAX_PACKET_LENGTH / 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
+   gdb_ctx->mem_buf,
+   gdb_ctx->params[1].val_ull, false)) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1899,22 +1923,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "OK");
 break;
 case 'm':
-addr = strtoull(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-len = strtoull(p, NULL, 16);
-
-/* memtohex() doubles the required space */
-if (len > MAX_PACKET_LENGTH / 2) {
-put_packet (s, "E22");
-break;
-}
-
-if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, false) != 0) {
-put_packet (s, "E14");
-} else {
-memtohex(buf, mem_buf, len);
-put_packet(s, buf);
+{
+static const GdbCmdParseEntry read_mem_cmd_desc = {
+.handler = handle_read_mem,
+.cmd = "m",
+.cmd_startswith = 1,
+.schema = "L,L0"
+};
+cmd_parser = &read_mem_cmd_desc;
 }
 break;
 case 'M':
-- 
2.20.1




[Qemu-devel] [PATCH v8 18/27] gdbstub: Implement generic query (q pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 327 ++
 1 file changed, 327 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index d56d0fd235..83ae8738cc 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1915,6 +1915,323 @@ static void handle_v_commands(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 }
 }
 
+static void handle_query_qemu_sstepbits(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+ "ENABLE=%x,NOIRQ=%x,NOTIMER=%x", SSTEP_ENABLE,
+ SSTEP_NOIRQ, SSTEP_NOTIMER);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!gdb_ctx->num_params) {
+return;
+}
+
+sstep_flags = gdb_ctx->params[0].val_ul;
+put_packet(gdb_ctx->s, "OK");
+}
+
+static void handle_query_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%x", sstep_flags);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+GDBProcess *process;
+char thread_id[16];
+
+/*
+ * "Current thread" remains vague in the spec, so always return
+ * the first thread of the current process (gdb returns the
+ * first thread).
+ */
+process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
+cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "QC%s", thread_id);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+char thread_id[16];
+
+if (!gdb_ctx->s->query_cpu) {
+put_packet(gdb_ctx->s, "l");
+return;
+}
+
+gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->query_cpu, thread_id,
+  sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "m%s", thread_id);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+gdb_ctx->s->query_cpu =
+gdb_next_attached_cpu(gdb_ctx->s, gdb_ctx->s->query_cpu);
+}
+
+static void handle_query_first_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+gdb_ctx->s->query_cpu = gdb_first_attached_cpu(gdb_ctx->s);
+handle_query_threads(gdb_ctx, user_ctx);
+}
+
+static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+int len;
+
+if (!gdb_ctx->num_params ||
+gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+  gdb_ctx->params[0].thread_id.tid);
+if (!cpu) {
+return;
+}
+
+cpu_synchronize_state(cpu);
+
+if (gdb_ctx->s->multiprocess && (gdb_ctx->s->process_num > 1)) {
+/* Print the CPU model and name in multiprocess mode */
+ObjectClass *oc = object_get_class(OBJECT(cpu));
+const char *cpu_model = object_class_get_name(oc);
+char *cpu_name = object_get_canonical_path_component(OBJECT(cpu));
+len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
+   "%s %s [%s]", cpu_model, cpu_name,
+   cpu->halted ? "halted " : "running");
+g_free(cpu_name);
+} else {
+/* memtohex() doubles the required space */
+len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
+"CPU#%d [%s]", cpu->cpu_index,
+cpu->halted ? "halted " : "running");
+}
+trace_gdbstub_op_extra_info((char *)gdb_ctx->mem_buf);
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+#ifdef CONFIG_USER_ONLY
+static void handle_query_offsets(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+TaskState *ts;
+
+ts = gdb_ctx->s->c_cpu->opaque;
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+ "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
+ ";Bss=" TARGET_ABI_FMT_lx,
+ ts->info->code_offset,
+ ts->info->data_offset,
+ ts->info->data_offset);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+#else
+static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int len;
+
+if (!gdb_ctx->num_params) {
+

[Qemu-devel] [PATCH v8 04/27] gdbstub: Implement continue (c pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index c47ef7dd9c..89f1ab6524 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1522,6 +1522,16 @@ static void handle_thread_alive(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_continue(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params) {
+gdb_set_cpu_pc(gdb_ctx->s, gdb_ctx->params[0].val_ull);
+}
+
+gdb_ctx->s->signal = 0;
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1558,13 +1568,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 gdb_breakpoint_remove_all();
 break;
 case 'c':
-if (*p != '\0') {
-addr = strtoull(p, (char **)&p, 16);
-gdb_set_cpu_pc(s, addr);
+{
+static const GdbCmdParseEntry continue_cmd_desc = {
+.handler = handle_continue,
+.cmd = "c",
+.cmd_startswith = 1,
+.schema = "L0"
+};
+cmd_parser = &continue_cmd_desc;
 }
-s->signal = 0;
-gdb_continue(s);
-return RS_IDLE;
+break;
 case 'C':
 s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
 if (s->signal == -1)
-- 
2.20.1




[Qemu-devel] [PATCH v9 01/27] gdbstub: Add infrastructure to parse cmd packets

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 200 ++
 1 file changed, 200 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index d54abd17cc..d5e0f3878a 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1268,6 +1268,206 @@ out:
 return res;
 }
 
+typedef union GdbCmdVariant {
+const char *data;
+uint8_t opcode;
+unsigned long val_ul;
+unsigned long long val_ull;
+struct {
+GDBThreadIdKind kind;
+uint32_t pid;
+uint32_t tid;
+} thread_id;
+} GdbCmdVariant;
+
+static const char *cmd_next_param(const char *param, const char delimiter)
+{
+static const char all_delimiters[] = ",;:=";
+char curr_delimiters[2] = {0};
+const char *delimiters;
+
+if (delimiter == '?') {
+delimiters = all_delimiters;
+} else if (delimiter == '0') {
+return strchr(param, '\0');
+} else if (delimiter == '.' && *param) {
+return param + 1;
+} else {
+curr_delimiters[0] = delimiter;
+delimiters = curr_delimiters;
+}
+
+param += strcspn(param, delimiters);
+if (*param) {
+param++;
+}
+return param;
+}
+
+static int cmd_parse_params(const char *data, const char *schema,
+GdbCmdVariant *params, int *num_params)
+{
+int curr_param;
+const char *curr_schema, *curr_data;
+
+*num_params = 0;
+
+if (!schema) {
+return 0;
+}
+
+curr_schema = schema;
+curr_param = 0;
+curr_data = data;
+while (curr_schema[0] && curr_schema[1] && *curr_data) {
+switch (curr_schema[0]) {
+case 'l':
+if (qemu_strtoul(curr_data, &curr_data, 16,
+ ¶ms[curr_param].val_ul)) {
+return -EINVAL;
+}
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 'L':
+if (qemu_strtou64(curr_data, &curr_data, 16,
+  (uint64_t *)¶ms[curr_param].val_ull)) {
+return -EINVAL;
+}
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 's':
+params[curr_param].data = curr_data;
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 'o':
+params[curr_param].opcode = *(uint8_t *)curr_data;
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case 't':
+params[curr_param].thread_id.kind =
+read_thread_id(curr_data, &curr_data,
+   ¶ms[curr_param].thread_id.pid,
+   ¶ms[curr_param].thread_id.tid);
+curr_param++;
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+case '?':
+curr_data = cmd_next_param(curr_data, curr_schema[1]);
+break;
+default:
+return -EINVAL;
+}
+curr_schema += 2;
+}
+
+*num_params = curr_param;
+return 0;
+}
+
+typedef struct GdbCmdContext {
+GDBState *s;
+GdbCmdVariant *params;
+int num_params;
+uint8_t mem_buf[MAX_PACKET_LENGTH];
+char str_buf[MAX_PACKET_LENGTH + 1];
+} GdbCmdContext;
+
+typedef void (*GdbCmdHandler)(GdbCmdContext *gdb_ctx, void *user_ctx);
+
+/*
+ * cmd_startswith -> cmd is compared using startswith
+ *
+ *
+ * schema definitions:
+ * Each schema parameter entry consists of 2 chars,
+ * the first char represents the parameter type handling
+ * the second char represents the delimiter for the next parameter
+ *
+ * Currently supported schema types:
+ * 'l' -> unsigned long (stored in .val_ul)
+ * 'L' -> unsigned long long (stored in .val_ull)
+ * 's' -> string (stored in .data)
+ * 'o' -> single char (stored in .opcode)
+ * 't' -> thread id (stored in .thread_id)
+ * '?' -> skip according to delimiter
+ *
+ * Currently supported delimiters:
+ * '?' -> Stop at any delimiter (",;:=\0")
+ * '0' -> Stop at "\0"
+ * '.' -> Skip 1 char unless reached "\0"
+ * Any other value is treated as the delimiter value itself
+ */
+typedef struct GdbCmdParseEntry {
+GdbCmdHandler handler;
+const char *cmd;
+union {
+int flags;
+struct {
+int cmd_startswith:1;
+};
+};
+const char *schema;
+} GdbCmdParseEntry;
+
+static inline int startswith(const char *string, const char *pattern)
+{
+  return !strncmp(string, pattern, strlen(pattern));
+}
+
+static int process_string_cmd(

[Qemu-devel] [PATCH v9 02/27] gdbstub: Implement deatch (D pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 90 ++-
 1 file changed, 50 insertions(+), 40 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index d5e0f3878a..621d689868 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1418,11 +1418,6 @@ static inline int startswith(const char *string, const 
char *pattern)
   return !strncmp(string, pattern, strlen(pattern));
 }
 
-static int process_string_cmd(
-GDBState *s, void *user_ctx, const char *data,
-const GdbCmdParseEntry *cmds, int num_cmds)
-__attribute__((unused));
-
 static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
   const GdbCmdParseEntry *cmds, int num_cmds)
 {
@@ -1468,6 +1463,41 @@ static int process_string_cmd(GDBState *s, void 
*user_ctx, const char *data,
 return -1;
 }
 
+static void handle_detach(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+GDBProcess *process;
+GDBState *s = gdb_ctx->s;
+uint32_t pid = 1;
+
+if (s->multiprocess) {
+if (!gdb_ctx->num_params) {
+put_packet(s, "E22");
+return;
+}
+
+pid = gdb_ctx->params[0].val_ul;
+}
+
+process = gdb_get_process(s, pid);
+gdb_process_breakpoint_remove_all(s, process);
+process->attached = false;
+
+if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
+s->c_cpu = gdb_first_attached_cpu(s);
+}
+
+if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
+s->g_cpu = gdb_first_attached_cpu(s);
+}
+
+if (!s->c_cpu) {
+/* No more process attached */
+gdb_syscall_mode = GDB_SYS_DISABLED;
+gdb_continue(s);
+}
+put_packet(s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1482,6 +1512,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t *registers;
 target_ulong addr, len;
 GDBThreadIdKind thread_kind;
+const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
 
@@ -1582,42 +1613,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 error_report("QEMU: Terminated via GDBstub");
 exit(0);
 case 'D':
-/* Detach packet */
-pid = 1;
-
-if (s->multiprocess) {
-unsigned long lpid;
-if (*p != ';') {
-put_packet(s, "E22");
-break;
-}
-
-if (qemu_strtoul(p + 1, &p, 16, &lpid)) {
-put_packet(s, "E22");
-break;
-}
-
-pid = lpid;
-}
-
-process = gdb_get_process(s, pid);
-gdb_process_breakpoint_remove_all(s, process);
-process->attached = false;
-
-if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
-s->c_cpu = gdb_first_attached_cpu(s);
-}
-
-if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
-s->g_cpu = gdb_first_attached_cpu(s);
-}
-
-if (s->c_cpu == NULL) {
-/* No more process attached */
-gdb_syscall_mode = GDB_SYS_DISABLED;
-gdb_continue(s);
+{
+static const GdbCmdParseEntry detach_cmd_desc = {
+.handler = handle_detach,
+.cmd = "D",
+.cmd_startswith = 1,
+.schema = "?.l0"
+};
+cmd_parser = &detach_cmd_desc;
 }
-put_packet(s, "OK");
 break;
 case 's':
 if (*p != '\0') {
@@ -1990,6 +1994,12 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, buf);
 break;
 }
+
+if (cmd_parser &&
+process_string_cmd(s, NULL, line_buf, cmd_parser, 1)) {
+put_packet(s, "");
+}
+
 return RS_IDLE;
 }
 
-- 
2.20.1




[Qemu-devel] [PATCH v9 00/27] gdbstub: Refactor command packets handler

2019-05-02 Thread Jon Doron
This patch series refactors the old gdbstub command packets handler
with a new infrastructure which should ease extending and adding new
and missing gdb command packets.

version 9 changes:
- checkpatch fixes

version 8 changes:
- Add new command to display the Supported qemu generic query/sets
- kvm: Add API to read/write a MSR
- Add new commands specific for qemu:
  * Command to swap the memory GDB sees to be the physical memory
  * Commands to read and write a MSR

version 7 changes:
- Fixed few checkpatch complaints
- Feedback from Alex Bennee

version 4-6 changes:
- mostly feedback from Richard Henderson

version 3 changes
- Split the single patch to many individual patches for easier reviewing

version 2 changes
- Code convention fixes

Jon Doron (27):
  gdbstub: Add infrastructure to parse cmd packets
  gdbstub: Implement deatch (D pkt) with new infra
  gdbstub: Implement thread_alive (T pkt) with new infra
  gdbstub: Implement continue (c pkt) with new infra
  gdbstub: Implement continue with signal (C pkt) with new infra
  gdbstub: Implement set_thread (H pkt) with new infra
  gdbstub: Implement insert breakpoint (Z pkt) with new infra
  gdbstub: Implement remove breakpoint (z pkt) with new infra
  gdbstub: Implement set register (P pkt) with new infra
  gdbstub: Implement get register (p pkt) with new infra
  gdbstub: Implement write memory (M pkt) with new infra
  gdbstub: Implement read memory (m pkt) with new infra
  gdbstub: Implement write all registers (G pkt) with new infra
  gdbstub: Implement read all registers (g pkt) with new infra
  gdbstub: Implement file io (F pkt) with new infra
  gdbstub: Implement step (s pkt) with new infra
  gdbstub: Implement v commands with new infra
  gdbstub: Implement generic query (q pkt) with new infra
  gdbstub: Implement generic set (Q pkt) with new infra
  gdbstub: Implement target halted (? pkt) with new infra
  gdbstub: Clear unused variables in gdb_handle_packet
  gdbstub: Implement generic query qemu.Supported
  gdbstub: Implement qemu physical memory mode
  gdbstub: Add another handler for setting qemu.sstep
  kvm: Add API to read/write a CPU MSR value
  gdbstub: Add support to read a MSR for KVM target
  gdbstub: Add support to write a MSR for KVM target

 accel/kvm/kvm-all.c  |   39 +
 gdbstub.c| 1807 ++
 include/sysemu/kvm.h |2 +
 3 files changed, 1359 insertions(+), 489 deletions(-)

-- 
2.20.1




[Qemu-devel] [PATCH v9 03/27] gdbstub: Implement thread_alive (T pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 43 ---
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 621d689868..c47ef7dd9c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1498,6 +1498,30 @@ static void handle_detach(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(s, "OK");
 }
 
+static void handle_thread_alive(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+  gdb_ctx->params[0].thread_id.tid);
+if (!cpu) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1798,17 +1822,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'T':
-thread_kind = read_thread_id(p, &p, &pid, &tid);
-if (thread_kind == GDB_READ_THREAD_ERR) {
-put_packet(s, "E22");
-break;
-}
-cpu = gdb_get_cpu(s, pid, tid);
-
-if (cpu != NULL) {
-put_packet(s, "OK");
-} else {
-put_packet(s, "E22");
+{
+static const GdbCmdParseEntry thread_alive_cmd_desc = {
+.handler = handle_thread_alive,
+.cmd = "T",
+.cmd_startswith = 1,
+.schema = "t0"
+};
+cmd_parser = &thread_alive_cmd_desc;
 }
 break;
 case 'q':
-- 
2.20.1




[Qemu-devel] [PATCH v9 09/27] gdbstub: Implement set register (P pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 39 ++-
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index b42425b24c..10e3f12a68 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1634,6 +1634,27 @@ static void handle_remove_bp(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "E22");
 }
 
+static void handle_set_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int reg_size;
+
+if (!gdb_has_xml) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+reg_size = strlen(gdb_ctx->params[1].data) / 2;
+hextomem(gdb_ctx->mem_buf, gdb_ctx->params[1].data, reg_size);
+gdb_write_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+   gdb_ctx->params[0].val_ull);
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1878,15 +1899,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'P':
-if (!gdb_has_xml)
-goto unknown_command;
-addr = strtoull(p, (char **)&p, 16);
-if (*p == '=')
-p++;
-reg_size = strlen(p) / 2;
-hextomem(mem_buf, p, reg_size);
-gdb_write_register(s->g_cpu, mem_buf, addr);
-put_packet(s, "OK");
+{
+static const GdbCmdParseEntry set_reg_cmd_desc = {
+.handler = handle_set_reg,
+.cmd = "P",
+.cmd_startswith = 1,
+.schema = "L?s0"
+};
+cmd_parser = &set_reg_cmd_desc;
+}
 break;
 case 'Z':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v9 04/27] gdbstub: Implement continue (c pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index c47ef7dd9c..89f1ab6524 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1522,6 +1522,16 @@ static void handle_thread_alive(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_continue(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params) {
+gdb_set_cpu_pc(gdb_ctx->s, gdb_ctx->params[0].val_ull);
+}
+
+gdb_ctx->s->signal = 0;
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1558,13 +1568,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 gdb_breakpoint_remove_all();
 break;
 case 'c':
-if (*p != '\0') {
-addr = strtoull(p, (char **)&p, 16);
-gdb_set_cpu_pc(s, addr);
+{
+static const GdbCmdParseEntry continue_cmd_desc = {
+.handler = handle_continue,
+.cmd = "c",
+.cmd_startswith = 1,
+.schema = "L0"
+};
+cmd_parser = &continue_cmd_desc;
 }
-s->signal = 0;
-gdb_continue(s);
-return RS_IDLE;
+break;
 case 'C':
 s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
 if (s->signal == -1)
-- 
2.20.1




[Qemu-devel] [PATCH v9 12/27] gdbstub: Implement read memory (m pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 48 
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 8dc2e1d507..daa602edc3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1710,6 +1710,30 @@ static void handle_write_mem(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_read_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+/* memtohex() doubles the required space */
+if (gdb_ctx->params[1].val_ull > MAX_PACKET_LENGTH / 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
+   gdb_ctx->mem_buf,
+   gdb_ctx->params[1].val_ull, false)) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1899,22 +1923,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "OK");
 break;
 case 'm':
-addr = strtoull(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-len = strtoull(p, NULL, 16);
-
-/* memtohex() doubles the required space */
-if (len > MAX_PACKET_LENGTH / 2) {
-put_packet (s, "E22");
-break;
-}
-
-if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, false) != 0) {
-put_packet (s, "E14");
-} else {
-memtohex(buf, mem_buf, len);
-put_packet(s, buf);
+{
+static const GdbCmdParseEntry read_mem_cmd_desc = {
+.handler = handle_read_mem,
+.cmd = "m",
+.cmd_startswith = 1,
+.schema = "L,L0"
+};
+cmd_parser = &read_mem_cmd_desc;
 }
 break;
 case 'M':
-- 
2.20.1




[Qemu-devel] [PATCH v9 05/27] gdbstub: Implement continue with signal (C pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 30 +-
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 89f1ab6524..469aaeb875 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1532,6 +1532,21 @@ static void handle_continue(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+unsigned long signal = 0;
+
+if (gdb_ctx->num_params) {
+signal = gdb_ctx->params[0].val_ul;
+}
+
+gdb_ctx->s->signal = gdb_signal_to_target(signal);
+if (gdb_ctx->s->signal == -1) {
+gdb_ctx->s->signal = 0;
+}
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1579,11 +1594,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'C':
-s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
-if (s->signal == -1)
-s->signal = 0;
-gdb_continue(s);
-return RS_IDLE;
+{
+static const GdbCmdParseEntry cont_with_sig_cmd_desc = {
+.handler = handle_cont_with_sig,
+.cmd = "C",
+.cmd_startswith = 1,
+.schema = "l0"
+};
+cmd_parser = &cont_with_sig_cmd_desc;
+}
+break;
 case 'v':
 if (strncmp(p, "Cont", 4) == 0) {
 p += 4;
-- 
2.20.1




[Qemu-devel] [PATCH v9 14/27] gdbstub: Implement read all registers (g pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 31 +++
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index adfe39b3a3..3478ac778d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1757,6 +1757,21 @@ static void handle_write_all_regs(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+target_ulong addr, len;
+
+cpu_synchronize_state(gdb_ctx->s->g_cpu);
+len = 0;
+for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs; addr++) {
+len += gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf + len,
+ addr);
+}
+
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1764,7 +1779,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 CPUClass *cc;
 const char *p;
 uint32_t pid, tid;
-int ch, reg_size, type, res;
+int ch, type, res;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
@@ -1923,14 +1938,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'g':
-cpu_synchronize_state(s->g_cpu);
-len = 0;
-for (addr = 0; addr < s->g_cpu->gdb_num_g_regs; addr++) {
-reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
-len += reg_size;
+{
+static const GdbCmdParseEntry read_all_regs_cmd_desc = {
+.handler = handle_read_all_regs,
+.cmd = "g",
+.cmd_startswith = 1
+};
+cmd_parser = &read_all_regs_cmd_desc;
 }
-memtohex(buf, mem_buf, len);
-put_packet(s, buf);
 break;
 case 'G':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v9 07/27] gdbstub: Implement insert breakpoint (Z pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 33 +
 1 file changed, 33 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index 21cdaf4678..36c7353a22 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1588,6 +1588,29 @@ static void handle_set_thread(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 }
 }
 
+static void handle_insert_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int res;
+
+if (gdb_ctx->num_params < 3) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+res = gdb_breakpoint_insert(gdb_ctx->params[1].val_ull,
+gdb_ctx->params[2].val_ull,
+gdb_ctx->params[0].val_ul);
+if (res >= 0) {
+put_packet(gdb_ctx->s, "OK");
+return;
+} else if (res == -ENOSYS) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+put_packet(gdb_ctx->s, "E22");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1843,6 +1866,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "OK");
 break;
 case 'Z':
+{
+static const GdbCmdParseEntry insert_bp_cmd_desc = {
+.handler = handle_insert_bp,
+.cmd = "Z",
+.cmd_startswith = 1,
+.schema = "l?L?L0"
+};
+cmd_parser = &insert_bp_cmd_desc;
+}
+break;
 case 'z':
 type = strtoul(p, (char **)&p, 16);
 if (*p == ',')
-- 
2.20.1




[Qemu-devel] [PATCH v9 16/27] gdbstub: Implement step (s pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 9fe130f30d..9b0556f8be 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1805,6 +1805,16 @@ static void handle_file_io(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_step(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params) {
+gdb_set_cpu_pc(gdb_ctx->s, (target_ulong)gdb_ctx->params[0].val_ull);
+}
+
+cpu_single_step(gdb_ctx->s->c_cpu, sstep_flags);
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1937,13 +1947,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 's':
-if (*p != '\0') {
-addr = strtoull(p, (char **)&p, 16);
-gdb_set_cpu_pc(s, addr);
+{
+static const GdbCmdParseEntry step_cmd_desc = {
+.handler = handle_step,
+.cmd = "s",
+.cmd_startswith = 1,
+.schema = "L0"
+};
+cmd_parser = &step_cmd_desc;
 }
-cpu_single_step(s->c_cpu, sstep_flags);
-gdb_continue(s);
-return RS_IDLE;
+break;
 case 'F':
 {
 static const GdbCmdParseEntry file_io_cmd_desc = {
-- 
2.20.1




[Qemu-devel] [PATCH v9 17/27] gdbstub: Implement v commands with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 170 +++---
 1 file changed, 110 insertions(+), 60 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 9b0556f8be..d56d0fd235 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1815,6 +1815,106 @@ static void handle_step(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_v_cont_query(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+put_packet(gdb_ctx->s, "vCont;c;C;s;S");
+}
+
+static void handle_v_cont(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int res;
+
+if (!gdb_ctx->num_params) {
+return;
+}
+
+res = gdb_handle_vcont(gdb_ctx->s, gdb_ctx->params[0].data);
+if ((res == -EINVAL) || (res == -ERANGE)) {
+put_packet(gdb_ctx->s, "E22");
+} else if (res) {
+put_packet(gdb_ctx->s, "\0");
+}
+}
+
+static void handle_v_attach(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+GDBProcess *process;
+CPUState *cpu;
+char thread_id[16];
+
+strcpy(gdb_ctx->str_buf, "E22");
+if (!gdb_ctx->num_params) {
+goto cleanup;
+}
+
+process = gdb_get_process(gdb_ctx->s, gdb_ctx->params[0].val_ul);
+if (!process) {
+goto cleanup;
+}
+
+cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+if (!cpu) {
+goto cleanup;
+}
+
+process->attached = true;
+gdb_ctx->s->g_cpu = cpu;
+gdb_ctx->s->c_cpu = cpu;
+
+gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
+ GDB_SIGNAL_TRAP, thread_id);
+cleanup:
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+/* Kill the target */
+put_packet(gdb_ctx->s, "OK");
+error_report("QEMU: Terminated via GDBstub");
+exit(0);
+}
+
+static GdbCmdParseEntry gdb_v_commands_table[] = {
+/* Order is important if has same prefix */
+{
+.handler = handle_v_cont_query,
+.cmd = "Cont?",
+.cmd_startswith = 1
+},
+{
+.handler = handle_v_cont,
+.cmd = "Cont",
+.cmd_startswith = 1,
+.schema = "s0"
+},
+{
+.handler = handle_v_attach,
+.cmd = "Attach;",
+.cmd_startswith = 1,
+.schema = "l0"
+},
+{
+.handler = handle_v_kill,
+.cmd = "Kill;",
+.cmd_startswith = 1
+},
+};
+
+static void handle_v_commands(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!gdb_ctx->num_params) {
+return;
+}
+
+if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+   gdb_v_commands_table,
+   ARRAY_SIZE(gdb_v_commands_table))) {
+put_packet(gdb_ctx->s, "");
+}
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1822,7 +1922,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 CPUClass *cc;
 const char *p;
 uint32_t pid, tid;
-int ch, type, res;
+int ch, type;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
@@ -1871,66 +1971,16 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'v':
-if (strncmp(p, "Cont", 4) == 0) {
-p += 4;
-if (*p == '?') {
-put_packet(s, "vCont;c;C;s;S");
-break;
-}
-
-res = gdb_handle_vcont(s, p);
-
-if (res) {
-if ((res == -EINVAL) || (res == -ERANGE)) {
-put_packet(s, "E22");
-break;
-}
-goto unknown_command;
-}
-break;
-} else if (strncmp(p, "Attach;", 7) == 0) {
-unsigned long pid;
-
-p += 7;
-
-if (qemu_strtoul(p, &p, 16, &pid)) {
-put_packet(s, "E22");
-break;
-}
-
-process = gdb_get_process(s, pid);
-
-if (process == NULL) {
-put_packet(s, "E22");
-break;
-}
-
-cpu = get_first_cpu_in_process(s, process);
-
-if (cpu == NULL) {
-/* Refuse to attach an empty process */
-put_packet(s, "E22");
-break;
-}
-
-process->attached = true;
-
-s->g_cpu = cpu;
-s->c_cpu = cpu;
-
-snprintf(buf, sizeof(buf), "T%02xthread:

[Qemu-devel] [PATCH v9 10/27] gdbstub: Implement get register (p pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 50 ++
 1 file changed, 38 insertions(+), 12 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 10e3f12a68..e9a3d0c2bc 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1655,6 +1655,36 @@ static void handle_set_reg(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int reg_size;
+
+/*
+ * Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
+ * This works, but can be very slow.  Anything new enough to
+ * understand XML also knows how to use this properly.
+ */
+if (!gdb_has_xml) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+reg_size = gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+ gdb_ctx->params[0].val_ull);
+if (!reg_size) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, reg_size);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1884,18 +1914,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'p':
-/* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
-   This works, but can be very slow.  Anything new enough to
-   understand XML also knows how to use this properly.  */
-if (!gdb_has_xml)
-goto unknown_command;
-addr = strtoull(p, (char **)&p, 16);
-reg_size = gdb_read_register(s->g_cpu, mem_buf, addr);
-if (reg_size) {
-memtohex(buf, mem_buf, reg_size);
-put_packet(s, buf);
-} else {
-put_packet(s, "E14");
+{
+static const GdbCmdParseEntry get_reg_cmd_desc = {
+.handler = handle_get_reg,
+.cmd = "p",
+.cmd_startswith = 1,
+.schema = "L0"
+};
+cmd_parser = &get_reg_cmd_desc;
 }
 break;
 case 'P':
-- 
2.20.1




[Qemu-devel] [PATCH v9 22/27] gdbstub: Implement generic query qemu.Supported

2019-05-02 Thread Jon Doron
qemu.Supported query reply back with the supported qemu query/set
commands (commands are seperated with a semicolon from each other).

gdb> maint packet qqemu.Supported

Signed-off-by: Jon Doron 
---
 gdbstub.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index 8bdfae4b29..00c07d6ec0 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2127,6 +2127,11 @@ static void handle_query_attached(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, GDB_ATTACHED);
 }
 
+static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+put_packet(gdb_ctx->s, "sstepbits;sstep");
+}
+
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
 /* Order is important if has same prefix */
 {
@@ -2203,6 +2208,10 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
 .handler = handle_query_attached,
 .cmd = "Attached",
 },
+{
+.handler = handle_query_qemu_supported,
+.cmd = "qemu.Supported",
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




[Qemu-devel] [PATCH v9 08/27] gdbstub: Implement remove breakpoint (z pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 49 -
 1 file changed, 32 insertions(+), 17 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 36c7353a22..b42425b24c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1611,6 +1611,29 @@ static void handle_insert_bp(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, "E22");
 }
 
+static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int res;
+
+if (gdb_ctx->num_params < 3) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+res = gdb_breakpoint_remove(gdb_ctx->params[1].val_ull,
+gdb_ctx->params[2].val_ull,
+gdb_ctx->params[0].val_ul);
+if (res >= 0) {
+put_packet(gdb_ctx->s, "OK");
+return;
+} else if (res == -ENOSYS) {
+put_packet(gdb_ctx->s, "");
+return;
+}
+
+put_packet(gdb_ctx->s, "E22");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1877,23 +1900,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'z':
-type = strtoul(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-addr = strtoull(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-len = strtoull(p, (char **)&p, 16);
-if (ch == 'Z')
-res = gdb_breakpoint_insert(addr, len, type);
-else
-res = gdb_breakpoint_remove(addr, len, type);
-if (res >= 0)
- put_packet(s, "OK");
-else if (res == -ENOSYS)
-put_packet(s, "");
-else
-put_packet(s, "E22");
+{
+static const GdbCmdParseEntry remove_bp_cmd_desc = {
+.handler = handle_remove_bp,
+.cmd = "z",
+.cmd_startswith = 1,
+.schema = "l?L?L0"
+};
+cmd_parser = &remove_bp_cmd_desc;
+}
 break;
 case 'H':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v9 11/27] gdbstub: Implement write memory (M pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 51 +--
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index e9a3d0c2bc..8dc2e1d507 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1685,6 +1685,31 @@ static void handle_get_reg(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_write_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (gdb_ctx->num_params < 3) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+/* hextomem() reads 2*len bytes */
+if (gdb_ctx->params[1].val_ull > strlen(gdb_ctx->params[2].data) / 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+hextomem(gdb_ctx->mem_buf, gdb_ctx->params[2].data,
+ gdb_ctx->params[1].val_ull);
+if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
+   gdb_ctx->mem_buf,
+   gdb_ctx->params[1].val_ull, true)) {
+put_packet(gdb_ctx->s, "E14");
+return;
+}
+
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1893,24 +1918,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'M':
-addr = strtoull(p, (char **)&p, 16);
-if (*p == ',')
-p++;
-len = strtoull(p, (char **)&p, 16);
-if (*p == ':')
-p++;
-
-/* hextomem() reads 2*len bytes */
-if (len > strlen(p) / 2) {
-put_packet (s, "E22");
-break;
-}
-hextomem(mem_buf, p, len);
-if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len,
-   true) != 0) {
-put_packet(s, "E14");
-} else {
-put_packet(s, "OK");
+{
+static const GdbCmdParseEntry write_mem_cmd_desc = {
+.handler = handle_write_mem,
+.cmd = "M",
+.cmd_startswith = 1,
+.schema = "L,L:s0"
+};
+cmd_parser = &write_mem_cmd_desc;
 }
 break;
 case 'p':
-- 
2.20.1




[Qemu-devel] [PATCH v9 20/27] gdbstub: Implement target halted (? pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 36 ++--
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 2fd0d66f4d..d678191705 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2239,13 +2239,30 @@ static void handle_gen_set(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, "");
 }
 
+static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+char thread_id[16];
+
+/* TODO: Make this return the correct value for user-mode.  */
+gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->c_cpu, thread_id,
+  sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
+ GDB_SIGNAL_TRAP, thread_id);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+/*
+ * Remove all the breakpoints when this query is issued,
+ * because gdb is doing and initial connect and the state
+ * should be cleaned up.
+ */
+gdb_breakpoint_remove_all();
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 const char *p;
 int ch;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
-char thread_id[16];
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
@@ -2257,15 +2274,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "OK");
 break;
 case '?':
-/* TODO: Make this return the correct value for user-mode.  */
-snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
- gdb_fmt_thread_id(s, s->c_cpu, thread_id, sizeof(thread_id)));
-put_packet(s, buf);
-/* Remove all the breakpoints when this query is issued,
- * because gdb is doing and initial connect and the state
- * should be cleaned up.
- */
-gdb_breakpoint_remove_all();
+{
+static const GdbCmdParseEntry target_halted_cmd_desc = {
+.handler = handle_target_halt,
+.cmd = "?",
+.cmd_startswith = 1
+};
+cmd_parser = &target_halted_cmd_desc;
+}
 break;
 case 'c':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v9 06/27] gdbstub: Implement set_thread (H pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 79 ++-
 1 file changed, 49 insertions(+), 30 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 469aaeb875..21cdaf4678 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1547,6 +1547,47 @@ static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 gdb_continue(gdb_ctx->s);
 }
 
+static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (gdb_ctx->params[1].thread_id.kind == GDB_READ_THREAD_ERR) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (gdb_ctx->params[1].thread_id.kind != GDB_ONE_THREAD) {
+put_packet(gdb_ctx->s, "OK");
+return;
+}
+
+cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[1].thread_id.pid,
+  gdb_ctx->params[1].thread_id.tid);
+if (!cpu) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+switch (gdb_ctx->params[0].opcode) {
+case 'c':
+gdb_ctx->s->c_cpu = cpu;
+put_packet(gdb_ctx->s, "OK");
+break;
+case 'g':
+gdb_ctx->s->g_cpu = cpu;
+put_packet(gdb_ctx->s, "OK");
+break;
+default:
+put_packet(gdb_ctx->s, "E22");
+break;
+}
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1560,7 +1601,6 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 char thread_id[16];
 uint8_t *registers;
 target_ulong addr, len;
-GDBThreadIdKind thread_kind;
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
@@ -1823,35 +1863,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "E22");
 break;
 case 'H':
-type = *p++;
-
-thread_kind = read_thread_id(p, &p, &pid, &tid);
-if (thread_kind == GDB_READ_THREAD_ERR) {
-put_packet(s, "E22");
-break;
-}
-
-if (thread_kind != GDB_ONE_THREAD) {
-put_packet(s, "OK");
-break;
-}
-cpu = gdb_get_cpu(s, pid, tid);
-if (cpu == NULL) {
-put_packet(s, "E22");
-break;
-}
-switch (type) {
-case 'c':
-s->c_cpu = cpu;
-put_packet(s, "OK");
-break;
-case 'g':
-s->g_cpu = cpu;
-put_packet(s, "OK");
-break;
-default:
- put_packet(s, "E22");
- break;
+{
+static const GdbCmdParseEntry set_thread_cmd_desc = {
+.handler = handle_set_thread,
+.cmd = "H",
+.cmd_startswith = 1,
+.schema = "o.t0"
+};
+cmd_parser = &set_thread_cmd_desc;
 }
 break;
 case 'T':
-- 
2.20.1




[Qemu-devel] [PATCH v9 15/27] gdbstub: Implement file io (F pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 62 +++
 1 file changed, 40 insertions(+), 22 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 3478ac778d..9fe130f30d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1772,6 +1772,39 @@ static void handle_read_all_regs(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int num_syscall_params;
+GdbCmdVariant syscall_params[3] = {};
+
+if (!gdb_ctx->num_params) {
+return;
+}
+
+if (cmd_parse_params(gdb_ctx->params[0].data, "L,L,o0", syscall_params,
+ &num_syscall_params)) {
+return;
+}
+
+if (!num_syscall_params) {
+return;
+}
+
+if (gdb_ctx->s->current_syscall_cb) {
+gdb_ctx->s->current_syscall_cb(gdb_ctx->s->c_cpu,
+   (target_ulong)syscall_params[0].val_ull,
+   
(target_ulong)syscall_params[1].val_ull);
+gdb_ctx->s->current_syscall_cb = NULL;
+}
+
+if (syscall_params[2].opcode == (uint8_t)'C') {
+put_packet(gdb_ctx->s, "T02");
+return;
+}
+
+gdb_continue(gdb_ctx->s);
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1913,28 +1946,13 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 return RS_IDLE;
 case 'F':
 {
-target_ulong ret;
-target_ulong err;
-
-ret = strtoull(p, (char **)&p, 16);
-if (*p == ',') {
-p++;
-err = strtoull(p, (char **)&p, 16);
-} else {
-err = 0;
-}
-if (*p == ',')
-p++;
-type = *p;
-if (s->current_syscall_cb) {
-s->current_syscall_cb(s->c_cpu, ret, err);
-s->current_syscall_cb = NULL;
-}
-if (type == 'C') {
-put_packet(s, "T02");
-} else {
-gdb_continue(s);
-}
+static const GdbCmdParseEntry file_io_cmd_desc = {
+.handler = handle_file_io,
+.cmd = "F",
+.cmd_startswith = 1,
+.schema = "s0"
+};
+cmd_parser = &file_io_cmd_desc;
 }
 break;
 case 'g':
-- 
2.20.1




[Qemu-devel] [PATCH v9 23/27] gdbstub: Implement qemu physical memory mode

2019-05-02 Thread Jon Doron
Add a new query/set which changes the memory GDB sees to physical memory
only.

gdb> maint packet qqemu.PhyMemMode
will reply the current phy_mem_mode state (1 for enabled, 0 for disabled)
gdb> maint packet Qqemu.PhyMemMode:1
Will make GDB read/write only to physical memory, set to 0 to disable

Signed-off-by: Jon Doron 
---
 gdbstub.c | 58 ---
 1 file changed, 55 insertions(+), 3 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 00c07d6ec0..88ff6224e6 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -46,11 +46,23 @@
 #define GDB_ATTACHED "1"
 #endif
 
+static int phy_memory_mode;
+
 static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
  uint8_t *buf, int len, bool is_write)
 {
-CPUClass *cc = CPU_GET_CLASS(cpu);
+CPUClass *cc;
 
+if (phy_memory_mode) {
+if (is_write) {
+cpu_physical_memory_write(addr, buf, len);
+} else {
+cpu_physical_memory_read(addr, buf, len);
+}
+return 0;
+}
+
+cc = CPU_GET_CLASS(cpu);
 if (cc->memory_rw_debug) {
 return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
 }
@@ -2129,7 +2141,29 @@ static void handle_query_attached(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 
 static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-put_packet(gdb_ctx->s, "sstepbits;sstep");
+put_packet(gdb_ctx->s, "sstepbits;sstep;PhyMemMode");
+}
+
+static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
+   void *user_ctx)
+{
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "%d", 
phy_memory_mode);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void 
*user_ctx)
+{
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (!gdb_ctx->params[0].val_ul) {
+phy_memory_mode = 0;
+} else {
+phy_memory_mode = 1;
+}
+put_packet(gdb_ctx->s, "OK");
 }
 
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
@@ -2212,6 +2246,20 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
 .handler = handle_query_qemu_supported,
 .cmd = "qemu.Supported",
 },
+{
+.handler = handle_query_qemu_phy_mem_mode,
+.cmd = "qemu.PhyMemMode",
+},
+};
+
+static GdbCmdParseEntry gdb_gen_set_table[] = {
+/* Order is important if has same prefix */
+{
+.handler = handle_set_qemu_phy_mem_mode,
+.cmd = "qemu.PhyMemMode:",
+.cmd_startswith = 1,
+.schema = "l0"
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2245,7 +2293,11 @@ static void handle_gen_set(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 return;
 }
 
-put_packet(gdb_ctx->s, "");
+if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+   gdb_gen_set_table,
+   ARRAY_SIZE(gdb_gen_set_table))) {
+put_packet(gdb_ctx->s, "");
+}
 }
 
 static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




[Qemu-devel] [PATCH v9 18/27] gdbstub: Implement generic query (q pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 327 ++
 1 file changed, 327 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index d56d0fd235..83ae8738cc 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1915,6 +1915,323 @@ static void handle_v_commands(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 }
 }
 
+static void handle_query_qemu_sstepbits(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+ "ENABLE=%x,NOIRQ=%x,NOTIMER=%x", SSTEP_ENABLE,
+ SSTEP_NOIRQ, SSTEP_NOTIMER);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!gdb_ctx->num_params) {
+return;
+}
+
+sstep_flags = gdb_ctx->params[0].val_ul;
+put_packet(gdb_ctx->s, "OK");
+}
+
+static void handle_query_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%x", sstep_flags);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+GDBProcess *process;
+char thread_id[16];
+
+/*
+ * "Current thread" remains vague in the spec, so always return
+ * the first thread of the current process (gdb returns the
+ * first thread).
+ */
+process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
+cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "QC%s", thread_id);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+char thread_id[16];
+
+if (!gdb_ctx->s->query_cpu) {
+put_packet(gdb_ctx->s, "l");
+return;
+}
+
+gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->query_cpu, thread_id,
+  sizeof(thread_id));
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "m%s", thread_id);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+gdb_ctx->s->query_cpu =
+gdb_next_attached_cpu(gdb_ctx->s, gdb_ctx->s->query_cpu);
+}
+
+static void handle_query_first_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+gdb_ctx->s->query_cpu = gdb_first_attached_cpu(gdb_ctx->s);
+handle_query_threads(gdb_ctx, user_ctx);
+}
+
+static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+CPUState *cpu;
+int len;
+
+if (!gdb_ctx->num_params ||
+gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+  gdb_ctx->params[0].thread_id.tid);
+if (!cpu) {
+return;
+}
+
+cpu_synchronize_state(cpu);
+
+if (gdb_ctx->s->multiprocess && (gdb_ctx->s->process_num > 1)) {
+/* Print the CPU model and name in multiprocess mode */
+ObjectClass *oc = object_get_class(OBJECT(cpu));
+const char *cpu_model = object_class_get_name(oc);
+char *cpu_name = object_get_canonical_path_component(OBJECT(cpu));
+len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
+   "%s %s [%s]", cpu_model, cpu_name,
+   cpu->halted ? "halted " : "running");
+g_free(cpu_name);
+} else {
+/* memtohex() doubles the required space */
+len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
+"CPU#%d [%s]", cpu->cpu_index,
+cpu->halted ? "halted " : "running");
+}
+trace_gdbstub_op_extra_info((char *)gdb_ctx->mem_buf);
+memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+#ifdef CONFIG_USER_ONLY
+static void handle_query_offsets(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+TaskState *ts;
+
+ts = gdb_ctx->s->c_cpu->opaque;
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+ "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
+ ";Bss=" TARGET_ABI_FMT_lx,
+ ts->info->code_offset,
+ ts->info->data_offset,
+ ts->info->data_offset);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+#else
+static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+int len;
+
+if (!gdb_ctx->num_params) {
+

[Qemu-devel] [PATCH v9 13/27] gdbstub: Implement write all registers (G pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 41 +++--
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index daa602edc3..adfe39b3a3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1734,6 +1734,29 @@ static void handle_read_mem(GdbCmdContext *gdb_ctx, void 
*user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+target_ulong addr, len;
+uint8_t *registers;
+int reg_size;
+
+if (!gdb_ctx->num_params) {
+return;
+}
+
+cpu_synchronize_state(gdb_ctx->s->g_cpu);
+registers = gdb_ctx->mem_buf;
+len = strlen(gdb_ctx->params[0].data) / 2;
+hextomem(registers, gdb_ctx->params[0].data, len);
+for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs && len > 0;
+ addr++) {
+reg_size = gdb_write_register(gdb_ctx->s->g_cpu, registers, addr);
+len -= reg_size;
+registers += reg_size;
+}
+put_packet(gdb_ctx->s, "OK");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
 CPUState *cpu;
@@ -1745,7 +1768,6 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
-uint8_t *registers;
 target_ulong addr, len;
 const GdbCmdParseEntry *cmd_parser = NULL;
 
@@ -1911,16 +1933,15 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, buf);
 break;
 case 'G':
-cpu_synchronize_state(s->g_cpu);
-registers = mem_buf;
-len = strlen(p) / 2;
-hextomem((uint8_t *)registers, p, len);
-for (addr = 0; addr < s->g_cpu->gdb_num_g_regs && len > 0; addr++) {
-reg_size = gdb_write_register(s->g_cpu, registers, addr);
-len -= reg_size;
-registers += reg_size;
+{
+static const GdbCmdParseEntry write_all_regs_cmd_desc = {
+.handler = handle_write_all_regs,
+.cmd = "G",
+.cmd_startswith = 1,
+.schema = "s0"
+};
+cmd_parser = &write_all_regs_cmd_desc;
 }
-put_packet(s, "OK");
 break;
 case 'm':
 {
-- 
2.20.1




[Qemu-devel] [PATCH v9 25/27] kvm: Add API to read/write a CPU MSR value

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 accel/kvm/kvm-all.c  | 39 +++
 include/sysemu/kvm.h |  2 ++
 2 files changed, 41 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 524c4ddfbd..35207d910b 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2444,6 +2444,45 @@ void kvm_remove_all_breakpoints(CPUState *cpu)
 }
 #endif /* !KVM_CAP_SET_GUEST_DEBUG */
 
+int kvm_arch_read_msr(CPUState *cpu, uint32_t index, uint64_t *value)
+{
+struct {
+struct kvm_msrs info;
+struct kvm_msr_entry entries[1];
+} msr_data;
+int ret;
+
+msr_data.info.nmsrs = 1;
+msr_data.entries[0].index = index;
+ret = kvm_vcpu_ioctl(cpu, KVM_GET_MSRS, &msr_data);
+if (ret < 0) {
+return ret;
+}
+
+*value = msr_data.entries[0].data;
+return 0;
+}
+
+int kvm_arch_write_msr(CPUState *cpu, uint32_t index, uint64_t value)
+{
+struct {
+struct kvm_msrs info;
+struct kvm_msr_entry entries[1];
+} msr_data;
+int ret;
+
+msr_data.info.nmsrs = 1;
+msr_data.entries[0].index = index;
+msr_data.entries[0].reserved = 0;
+msr_data.entries[0].data = value;
+ret = kvm_vcpu_ioctl(cpu, KVM_SET_MSRS, &msr_data);
+if (ret < 0) {
+return ret;
+}
+
+return 0;
+}
+
 static int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset)
 {
 KVMState *s = kvm_state;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index a6d1cd190f..409b1a5444 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -462,6 +462,8 @@ int kvm_vm_check_extension(KVMState *s, unsigned int 
extension);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
   uint32_t index, int reg);
 uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index);
+int kvm_arch_read_msr(CPUState *cpu, uint32_t index, uint64_t *value);
+int kvm_arch_write_msr(CPUState *cpu, uint32_t index, uint64_t value);
 
 
 void kvm_set_sigmask_len(KVMState *s, unsigned int sigmask_len);
-- 
2.20.1




[Qemu-devel] [PATCH v9 24/27] gdbstub: Add another handler for setting qemu.sstep

2019-05-02 Thread Jon Doron
Follow GDB general query/set packet conventions, qemu.sstep can now
be set with the following command as well:
gdb> maint packet Qqemu.sstep:Value

Signed-off-by: Jon Doron 
---
 gdbstub.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index 88ff6224e6..34da10260d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2260,6 +2260,12 @@ static GdbCmdParseEntry gdb_gen_set_table[] = {
 .cmd_startswith = 1,
 .schema = "l0"
 },
+{
+.handler = handle_set_qemu_sstep,
+.cmd = "qemu.sstep:",
+.cmd_startswith = 1,
+.schema = "l0"
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




[Qemu-devel] [PATCH v9 21/27] gdbstub: Clear unused variables in gdb_handle_packet

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 11 ++-
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index d678191705..8bdfae4b29 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2259,17 +2259,11 @@ static void handle_target_halt(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
-const char *p;
-int ch;
-uint8_t mem_buf[MAX_PACKET_LENGTH];
-char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
 
-p = line_buf;
-ch = *p++;
-switch(ch) {
+switch (line_buf[0]) {
 case '!':
 put_packet(s, "OK");
 break;
@@ -2486,8 +2480,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 break;
 default:
 /* put empty packet */
-buf[0] = '\0';
-put_packet(s, buf);
+put_packet(s, "");
 break;
 }
 
-- 
2.20.1




[Qemu-devel] [PATCH v9 26/27] gdbstub: Add support to read a MSR for KVM target

2019-05-02 Thread Jon Doron
gdb> maint packet qqemu.kvm.Rdmsr:MsrIndex

Signed-off-by: Jon Doron 
---
 gdbstub.c | 38 +-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/gdbstub.c b/gdbstub.c
index 34da10260d..f48c3a2b5f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2141,7 +2141,14 @@ static void handle_query_attached(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 
 static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-put_packet(gdb_ctx->s, "sstepbits;sstep;PhyMemMode");
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+ "sstepbits;sstep;PhyMemMode");
+
+if (kvm_enabled()) {
+pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";kvm.Rdmsr");
+}
+
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
 static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
@@ -2166,6 +2173,29 @@ static void handle_set_qemu_phy_mem_mode(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, "OK");
 }
 
+static void handle_query_kvm_read_msr(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+uint64_t msr_val;
+
+if (!kvm_enabled()) {
+return;
+}
+
+if (!gdb_ctx->num_params) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (kvm_arch_read_msr(gdbserver_state->c_cpu, gdb_ctx->params[0].val_ul,
+  &msr_val)) {
+put_packet(gdb_ctx->s, "E00");
+return;
+}
+
+snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%" PRIx64, 
msr_val);
+put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
 /* Order is important if has same prefix */
 {
@@ -2250,6 +2280,12 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
 .handler = handle_query_qemu_phy_mem_mode,
 .cmd = "qemu.PhyMemMode",
 },
+{
+.handler = handle_query_kvm_read_msr,
+.cmd = "qemu.kvm.Rdmsr:",
+.cmd_startswith = 1,
+.schema = "l0"
+},
 };
 
 static GdbCmdParseEntry gdb_gen_set_table[] = {
-- 
2.20.1




[Qemu-devel] [PATCH v9 19/27] gdbstub: Implement generic set (Q pkt) with new infra

2019-05-02 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 gdbstub.c | 213 +++---
 1 file changed, 25 insertions(+), 188 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 83ae8738cc..2fd0d66f4d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1130,14 +1130,6 @@ static GDBThreadIdKind read_thread_id(const char *buf, 
const char **end_buf,
 return GDB_ONE_THREAD;
 }
 
-static int is_query_packet(const char *p, const char *query, char separator)
-{
-unsigned int query_len = strlen(query);
-
-return strncmp(p, query, query_len) == 0 &&
-(p[query_len] == '\0' || p[query_len] == separator);
-}
-
 /**
  * gdb_handle_vcont - Parses and handles a vCont packet.
  * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
@@ -2232,18 +2224,28 @@ static void handle_gen_query(GdbCmdContext *gdb_ctx, 
void *user_ctx)
 }
 }
 
+static void handle_gen_set(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!gdb_ctx->num_params) {
+return;
+}
+
+if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+gdb_gen_query_set_common_table,
+ARRAY_SIZE(gdb_gen_query_set_common_table))) {
+return;
+}
+
+put_packet(gdb_ctx->s, "");
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
-CPUState *cpu;
-GDBProcess *process;
-CPUClass *cc;
 const char *p;
-uint32_t pid, tid;
-int ch, type;
+int ch;
 uint8_t mem_buf[MAX_PACKET_LENGTH];
 char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 char thread_id[16];
-target_ulong addr, len;
 const GdbCmdParseEntry *cmd_parser = NULL;
 
 trace_gdbstub_io_command(line_buf);
@@ -2456,182 +2458,17 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 break;
 case 'Q':
-/* parse any 'q' packets here */
-if (!strcmp(p,"qemu.sstepbits")) {
-/* Query Breakpoint bit definitions */
-snprintf(buf, sizeof(buf), "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
- SSTEP_ENABLE,
- SSTEP_NOIRQ,
- SSTEP_NOTIMER);
-put_packet(s, buf);
-break;
-} else if (is_query_packet(p, "qemu.sstep", '=')) {
-/* Display or change the sstep_flags */
-p += 10;
-if (*p != '=') {
-/* Display current setting */
-snprintf(buf, sizeof(buf), "0x%x", sstep_flags);
-put_packet(s, buf);
-break;
-}
-p++;
-type = strtoul(p, (char **)&p, 16);
-sstep_flags = type;
-put_packet(s, "OK");
-break;
-} else if (strcmp(p,"C") == 0) {
-/*
- * "Current thread" remains vague in the spec, so always return
- * the first thread of the current process (gdb returns the
- * first thread).
- */
-cpu = get_first_cpu_in_process(s, gdb_get_cpu_process(s, 
s->g_cpu));
-snprintf(buf, sizeof(buf), "QC%s",
- gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id)));
-put_packet(s, buf);
-break;
-} else if (strcmp(p,"fThreadInfo") == 0) {
-s->query_cpu = gdb_first_attached_cpu(s);
-goto report_cpuinfo;
-} else if (strcmp(p,"sThreadInfo") == 0) {
-report_cpuinfo:
-if (s->query_cpu) {
-snprintf(buf, sizeof(buf), "m%s",
- gdb_fmt_thread_id(s, s->query_cpu,
-   thread_id, sizeof(thread_id)));
-put_packet(s, buf);
-s->query_cpu = gdb_next_attached_cpu(s, s->query_cpu);
-} else
-put_packet(s, "l");
-break;
-} else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
-if (read_thread_id(p + 16, &p, &pid, &tid) == GDB_READ_THREAD_ERR) 
{
-put_packet(s, "E22");
-break;
-}
-cpu = gdb_get_cpu(s, pid, tid);
-if (cpu != NULL) {
-cpu_synchronize_state(cpu);
-
-if (s->multiprocess && (s->process_num > 1)) {
-/* Print the CPU model and name in multiprocess mode */
-ObjectClass *oc = object_get_class(OBJECT(cpu));
-const char *cpu_model = object_class_get_name(oc);
-char *cpu_name =
-object_get_canonical_path_component(OBJECT(cpu));
-len = snprintf((char *)mem_buf, sizeof(buf) / 2,

[Qemu-devel] [PATCH v9 27/27] gdbstub: Add support to write a MSR for KVM target

2019-05-02 Thread Jon Doron
gdb> maint packet Qqemu.kvm.Wrmsr:MsrIndex,Value

Signed-off-by: Jon Doron 
---
 gdbstub.c | 29 -
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/gdbstub.c b/gdbstub.c
index f48c3a2b5f..a434a3749e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2145,7 +2145,8 @@ static void handle_query_qemu_supported(GdbCmdContext 
*gdb_ctx, void *user_ctx)
  "sstepbits;sstep;PhyMemMode");
 
 if (kvm_enabled()) {
-pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";kvm.Rdmsr");
+pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
+";kvm.Rdmsr;kvm.Wrmsr");
 }
 
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
@@ -2196,6 +2197,26 @@ static void handle_query_kvm_read_msr(GdbCmdContext 
*gdb_ctx, void *user_ctx)
 put_packet(gdb_ctx->s, gdb_ctx->str_buf);
 }
 
+static void handle_set_kvm_write_msr(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+if (!kvm_enabled()) {
+return;
+}
+
+if (gdb_ctx->num_params < 2) {
+put_packet(gdb_ctx->s, "E22");
+return;
+}
+
+if (kvm_arch_write_msr(gdbserver_state->c_cpu, gdb_ctx->params[0].val_ul,
+   gdb_ctx->params[1].val_ull)) {
+put_packet(gdb_ctx->s, "E00");
+return;
+}
+
+put_packet(gdb_ctx->s, "OK");
+}
+
 static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
 /* Order is important if has same prefix */
 {
@@ -2302,6 +2323,12 @@ static GdbCmdParseEntry gdb_gen_set_table[] = {
 .cmd_startswith = 1,
 .schema = "l0"
 },
+{
+.handler = handle_set_kvm_write_msr,
+.cmd = "qemu.kvm.Wrmsr:",
+.cmd_startswith = 1,
+.schema = "l,L0"
+},
 };
 
 static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
-- 
2.20.1




Re: [PATCH v4 0/1] hw/hyperv/vmbus: Is it maintained?

2021-11-16 Thread Jon Doron

On 13/11/2021, Maciej S. Szmigiero wrote:

On 12.11.2021 21:39, Roman Kagan wrote:

On Fri, Nov 12, 2021 at 09:32:31PM +0300, Vladimir Sementsov-Ogievskiy wrote:

Add Den and Roman (his new address)


Thanks, I missed it on the list indeed.


06.11.2021 16:41, Philippe Mathieu-Daudé wrote:

This is the 4th time I send this patch. Is the VMBus infrastructure
used / maintained? Should we deprecate & remove?


I think it's fair to say it's not maintained.  The whole
hw/hyperv/vmbus.c was submitted as a part of the work by Jon to enable
some obscure windows debugging feature which only worked in presence of
VMBus.  It was mostly taken from the respective branch of the (now
effectively abandoned) downstream tree with an implementation of the
core VMBus infrastructure and the devices using it; however, none of the
actual VMBus devices ever made it into the mainline tree.



The VMBus code works fine, is mostly self-contained and by being a part
of the upstream QEMU it does benefit from any improvements done there and
so it is much less likely to bit-rot with time.

I am still committed to upstreaming a Hyper-V Dynamic Memory Protocol
driver (which uses VMBus), however had been preempted by higher-priority
work for now.

Thanks,
Maciej


Hi guys,

Sorry for the late reply, like Roman I also never got to submit the RFC 
for the Synth debugger device which requires the VMBus, I do hope to get 
to it at some point and VMBus is a required part for it.


In the last year or so I have not had much time to spend on this but I 
do hope to get back to finishing what I have started.


I'm not really sure I have the time or knowledge to maintain VMBus :( 
but I'll do my best to answer any questions as well.


-- Jon.



Re: [PATCH v2 4/4] hw: hyperv: Initial commit for Synthetic Debugging device

2022-02-23 Thread Jon Doron
ping

On Wed, Feb 16, 2022, 12:25 Jon Doron  wrote:

> Signed-off-by: Jon Doron 
> ---
>  hw/hyperv/Kconfig |   5 +
>  hw/hyperv/meson.build |   1 +
>  hw/hyperv/syndbg.c| 402 ++
>  3 files changed, 408 insertions(+)
>  create mode 100644 hw/hyperv/syndbg.c
>
> diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig
> index 3fbfe41c9e..fcf65903bd 100644
> --- a/hw/hyperv/Kconfig
> +++ b/hw/hyperv/Kconfig
> @@ -11,3 +11,8 @@ config VMBUS
>  bool
>  default y
>  depends on HYPERV
> +
> +config SYNDBG
> +bool
> +default y
> +depends on VMBUS
> diff --git a/hw/hyperv/meson.build b/hw/hyperv/meson.build
> index 1367e2994f..b43f119ea5 100644
> --- a/hw/hyperv/meson.build
> +++ b/hw/hyperv/meson.build
> @@ -1,3 +1,4 @@
>  specific_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'))
>  specific_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true:
> files('hyperv_testdev.c'))
>  specific_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c'))
> +specific_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c'))
> diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c
> new file mode 100644
> index 00..8816bc4082
> --- /dev/null
> +++ b/hw/hyperv/syndbg.c
> @@ -0,0 +1,402 @@
> +/*
> + * QEMU Hyper-V Synthetic Debugging device
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/ctype.h"
> +#include "qemu/osdep.h"
> +#include "qemu/error-report.h"
> +#include "qemu/main-loop.h"
> +#include "qemu/sockets.h"
> +#include "qemu-common.h"
> +#include "qapi/error.h"
> +#include "migration/vmstate.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/loader.h"
> +#include "cpu.h"
> +#include "hw/hyperv/hyperv.h"
> +#include "hw/hyperv/vmbus-bridge.h"
> +#include "hw/hyperv/hyperv-proto.h"
> +#include "net/net.h"
> +#include "net/eth.h"
> +#include "net/checksum.h"
> +#include "trace.h"
> +
> +#define TYPE_HV_SYNDBG   "hv-syndbg"
> +
> +typedef struct HvSynDbg {
> +DeviceState parent_obj;
> +
> +char *host_ip;
> +uint16_t host_port;
> +bool use_hcalls;
> +
> +uint32_t target_ip;
> +struct sockaddr_in servaddr;
> +int socket;
> +bool has_data_pending;
> +uint64_t pending_page_gpa;
> +} HvSynDbg;
> +
> +#define HVSYNDBG(obj) OBJECT_CHECK(HvSynDbg, (obj), TYPE_HV_SYNDBG)
> +
> +/* returns NULL unless there is exactly one HV Synth debug device */
> +static HvSynDbg *hv_syndbg_find(void)
> +{
> +/* Returns NULL unless there is exactly one hvsd device */
> +return HVSYNDBG(object_resolve_path_type("", TYPE_HV_SYNDBG, NULL));
> +}
> +
> +static void set_pending_state(HvSynDbg *syndbg, bool has_pending)
> +{
> +hwaddr out_len;
> +void *out_data;
> +
> +syndbg->has_data_pending = has_pending;
> +
> +if (!syndbg->pending_page_gpa) {
> +return;
> +}
> +
> +out_len = 1;
> +out_data = cpu_physical_memory_map(syndbg->pending_page_gpa,
> &out_len, 1);
> +if (out_data) {
> +*(uint8_t *)out_data = !!has_pending;
> +cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
> +}
> +}
> +
> +static bool get_udb_pkt_data(void *p, uint32_t len, uint32_t *data_ofs,
> + uint32_t *src_ip)
> +{
> +uint32_t offset, curr_len = len;
> +
> +if (curr_len < sizeof(struct eth_header) ||
> +(be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto) != ETH_P_IP)) {
> +return false;
> +}
> +offset = sizeof(struct eth_header);
> +curr_len -= sizeof(struct eth_header);
> +
> +if (curr_len < sizeof(struct ip_header) ||
> +PKT_GET_IP_HDR(p)->ip_p != IP_PROTO_UDP) {
> +return false;
> +}
> +offset += PKT_GET_IP_HDR_LEN(p);
> +curr_len -= PKT_GET_IP_HDR_LEN(p);
> +
> +if (curr_len < sizeof(struct udp_header)) {
> +return false;
> +}
> +
> +offset += sizeof(struct udp_header);
> +*data_ofs = offset;
> +*src_ip = PKT_GET_IP_HDR(p)->ip_src;
> +return true;
> +}
> +
> +static uint16_t handle_send_msg(HvSynDbg *syndbg, uint64_t ingpa,
> +uint32_t count, bool is_raw,
> +uint32_t *pend

[PATCH v1 0/4] HyperV: Synthetic Debugging device

2022-02-04 Thread Jon Doron
This patchset adds support for the synthetic debugging device.

HyperV supports a special transport layer for the kernel debugger when
running in HyperV.

This patchset add supports for this device so you could have a setup
fast windows kernel debugging.

At this point of time, DHCP is not implmeneted so to set this up few
things need to be noted.

The scenario I used to test is having 2 VMs in the same virtual network
i.e a Debugger VM with the NIC:
-nic tap,model=virtio,mac=02:ca:01:01:01:01,script=/etc/qemu-ifup
And it's IP is going to be static 192.168.53.12
And the VM we want to debug, to which we need to have the englightments
and vmbus configured:
 -cpu 
host,hv-relaxed,hv_spinlocks=0x1fff,hv_time,+vmx,invtsc,hv-vapic,hv-vpindex,hv-synic,hv-syndbg
 \
 -device vmbus-bridge \
 -device hv-syndbg,host_ip=192.168.53.12,host_port=5,use_hcalls=false \
 -nic tap,model=virtio,mac=02:ca:01:01:01:02,script=/etc/qemu-ifup \

Then in the debuggee VM we would setup the kernel debugging in the
following way:

If the VM is older than Win8:
* Copy the proper platform kdvm.dll (make sure it's called kdvm.dll even if 
platform is 32bit)
bcdedit /set {GUID} dbgtransport kdvm.dll
bcdedit /set {GUID} loadoptions host_ip="1.2.3.4",host_port="5",nodhcp
bcdedit /set {GUID} debug on
bcdedit /set {GUID} halbreakpoint on

Win8 and late:
bcdedit /dbgsettings net hostip:7.7.7.7 port:5 nodhcp

This is all the setup that is required to get the synthetic debugger
configured correctly.

Jon Doron (4):
  hyperv: SControl is optional to enable SynIc
  hyperv: Add definitions for syndbg
  hyperv: Add support to process syndbg commands
  hw: hyperv: Initial commit for Synthetic Debugging device

 docs/hyperv.txt  |  15 +
 hw/hyperv/Kconfig|   5 +
 hw/hyperv/hyperv.c   | 475 +--
 hw/hyperv/meson.build|   1 +
 hw/hyperv/syndbg.c   | 407 ++
 include/hw/hyperv/hyperv-proto.h |  52 
 include/hw/hyperv/hyperv.h   |  60 
 target/i386/cpu.c|   2 +
 target/i386/cpu.h|   7 +
 target/i386/kvm/hyperv-proto.h   |  37 +++
 target/i386/kvm/hyperv-stub.c|   6 +
 target/i386/kvm/hyperv.c |  52 +++-
 target/i386/kvm/kvm.c|  76 -
 13 files changed, 1105 insertions(+), 90 deletions(-)
 create mode 100644 hw/hyperv/syndbg.c

-- 
2.34.1




[PATCH v1 3/4] hyperv: Add support to process syndbg commands

2022-02-04 Thread Jon Doron
SynDbg commands can come from two different flows:
1. Hypercalls, in this mode the data being sent is fully
   encapsulated network packets.
2. SynDbg specific MSRs, in this mode only the data that needs to be
   transfered is passed.

Signed-off-by: Jon Doron 
---
 docs/hyperv.txt   |  15 +++
 hw/hyperv/hyperv.c| 242 ++
 include/hw/hyperv/hyperv.h|  58 
 target/i386/cpu.c |   2 +
 target/i386/cpu.h |   7 +
 target/i386/kvm/hyperv-stub.c |   6 +
 target/i386/kvm/hyperv.c  |  52 +++-
 target/i386/kvm/kvm.c |  76 ++-
 8 files changed, 450 insertions(+), 8 deletions(-)

diff --git a/docs/hyperv.txt b/docs/hyperv.txt
index 0417c183a3..7abc1b2d89 100644
--- a/docs/hyperv.txt
+++ b/docs/hyperv.txt
@@ -225,6 +225,21 @@ default (WS2016).
 Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V
 identification when specified without any other enlightenments.
 
+3.21. hv-syndbg
+===
+Enables Hyper-V synthetic debugger interface, this is a special interface used
+by Windows Kernel debugger to send the packets through, rather than sending
+them via serial/network .
+Whe enabled, this enlightenment provides additional communication facilities
+to the guest: SynDbg messages.
+This new communication is used by Windows Kernel debugger rather than sending
+packets via serial/network, adding significant performance boost over the other
+comm channels.
+This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15)
+and the follow enlightenments to work:
+hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer
+
+
 4. Supplementary features
 =
 
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 88c9cc1334..c86e2aa02e 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -730,3 +730,245 @@ uint16_t hyperv_hcall_signal_event(uint64_t param, bool 
fast)
 }
 return HV_STATUS_INVALID_CONNECTION_ID;
 }
+
+static HvSynDbgHandler hv_syndbg_handler;
+static void *hv_syndbg_context;
+void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context)
+{
+assert(!hv_syndbg_handler);
+hv_syndbg_handler = handler;
+hv_syndbg_context = context;
+}
+
+uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa)
+{
+uint16_t ret;
+HvSynDbgMsg msg;
+struct hyperv_reset_debug_session_output *reset_dbg_session = NULL;
+hwaddr len;
+
+if (!hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+len = sizeof(*reset_dbg_session);
+reset_dbg_session = cpu_physical_memory_map(outgpa, &len, 1);
+if (!reset_dbg_session || len < sizeof(*reset_dbg_session)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_CONNECTION_INFO;
+ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+if (ret) {
+goto cleanup;
+}
+
+reset_dbg_session->host_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->host_port = msg.u.connection_info.host_port;
+/* The following fields are only used as validation for KDVM */
+memset(&reset_dbg_session->host_mac, 0,
+   sizeof(reset_dbg_session->host_mac));
+reset_dbg_session->target_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->target_port = msg.u.connection_info.host_port;
+memset(&reset_dbg_session->target_mac, 0,
+   sizeof(reset_dbg_session->target_mac));
+cleanup:
+if (reset_dbg_session) {
+cpu_physical_memory_unmap(reset_dbg_session,
+  sizeof(*reset_dbg_session), 1, len);
+}
+
+return ret;
+}
+
+uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa,
+bool fast)
+{
+uint16_t ret;
+struct hyperv_retrieve_debug_data_input *debug_data_in = NULL;
+struct hyperv_retrieve_debug_data_output *debug_data_out = NULL;
+hwaddr in_len, out_len;
+HvSynDbgMsg msg;
+
+if (fast || !hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+in_len = sizeof(*debug_data_in);
+debug_data_in = cpu_physical_memory_map(ingpa, &in_len, 0);
+if (!debug_data_in || in_len < sizeof(*debug_data_in)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+out_len = sizeof(*debug_data_out);
+debug_data_out = cpu_physical_memory_map(outgpa, &out_len, 1);
+if (!debug_data_out || out_len < sizeof(*debug_data_out)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_RECV;
+msg.u.recv.buf_gpa = outgpa + sizeof(*debug_data_out);
+msg.u.recv.count = TARGET_PAGE_SIZE - sizeof(*debug_data_out);
+msg.u.recv.options = debug_data_in->options;
+msg.u.recv.timeout 

[PATCH v1 1/4] hyperv: SControl is optional to enable SynIc

2022-02-04 Thread Jon Doron
SynIc can be enabled regardless of the SControl mechanisim which can
register a GSI for a given SintRoute.

This behaviour can achived by setting enabling SIMP and then the guest
will poll on the message slot.

Once there is another message pending the host will set the message slot
with the pending flag.
When the guest polls from the message slot, incase the pending flag is
set it will write to the HV_X64_MSR_EOM indicating it has cleared the
slow and we can try and push our message again.

Signed-off-by: Jon Doron 
---
 hw/hyperv/hyperv.c | 233 -
 include/hw/hyperv/hyperv.h |   2 +
 2 files changed, 153 insertions(+), 82 deletions(-)

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index cb1074f234..88c9cc1334 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -27,18 +27,70 @@ struct SynICState {
 
 CPUState *cs;
 
-bool enabled;
+bool sctl_enabled;
 hwaddr msg_page_addr;
 hwaddr event_page_addr;
 MemoryRegion msg_page_mr;
 MemoryRegion event_page_mr;
 struct hyperv_message_page *msg_page;
 struct hyperv_event_flags_page *event_page;
+
+QemuMutex sint_routes_mutex;
+QLIST_HEAD(, HvSintRoute) sint_routes;
 };
 
 #define TYPE_SYNIC "hyperv-synic"
 OBJECT_DECLARE_SIMPLE_TYPE(SynICState, SYNIC)
 
+/*
+ * KVM has its own message producers (SynIC timers).  To guarantee
+ * serialization with both KVM vcpu and the guest cpu, the messages are first
+ * staged in an intermediate area and then posted to the SynIC message page in
+ * the vcpu thread.
+ */
+typedef struct HvSintStagedMessage {
+/* message content staged by hyperv_post_msg */
+struct hyperv_message msg;
+/* callback + data (r/o) to complete the processing in a BH */
+HvSintMsgCb cb;
+void *cb_data;
+/* message posting status filled by cpu_post_msg */
+int status;
+/* passing the buck: */
+enum {
+/* initial state */
+HV_STAGED_MSG_FREE,
+/*
+ * hyperv_post_msg (e.g. in main loop) grabs the staged area (FREE ->
+ * BUSY), copies msg, and schedules cpu_post_msg on the assigned cpu
+ */
+HV_STAGED_MSG_BUSY,
+/*
+ * cpu_post_msg (vcpu thread) tries to copy staged msg to msg slot,
+ * notify the guest, records the status, marks the posting done (BUSY
+ * -> POSTED), and schedules sint_msg_bh BH
+ */
+HV_STAGED_MSG_POSTED,
+/*
+ * sint_msg_bh (BH) verifies that the posting is done, runs the
+ * callback, and starts over (POSTED -> FREE)
+ */
+} state;
+} HvSintStagedMessage;
+
+struct HvSintRoute {
+uint32_t sint;
+SynICState *synic;
+int gsi;
+EventNotifier sint_set_notifier;
+EventNotifier sint_ack_notifier;
+
+HvSintStagedMessage *staged_msg;
+
+unsigned refcount;
+QLIST_ENTRY(HvSintRoute) link;
+};
+
 static bool synic_enabled;
 
 bool hyperv_is_synic_enabled(void)
@@ -51,11 +103,11 @@ static SynICState *get_synic(CPUState *cs)
 return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
 }
 
-static void synic_update(SynICState *synic, bool enable,
+static void synic_update(SynICState *synic, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 
-synic->enabled = enable;
+synic->sctl_enabled = sctl_enable;
 if (synic->msg_page_addr != msg_page_addr) {
 if (synic->msg_page_addr) {
 memory_region_del_subregion(get_system_memory(),
@@ -80,7 +132,7 @@ static void synic_update(SynICState *synic, bool enable,
 }
 }
 
-void hyperv_synic_update(CPUState *cs, bool enable,
+void hyperv_synic_update(CPUState *cs, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 SynICState *synic = get_synic(cs);
@@ -89,7 +141,7 @@ void hyperv_synic_update(CPUState *cs, bool enable,
 return;
 }
 
-synic_update(synic, enable, msg_page_addr, event_page_addr);
+synic_update(synic, sctl_enable, msg_page_addr, event_page_addr);
 }
 
 static void synic_realize(DeviceState *dev, Error **errp)
@@ -110,16 +162,20 @@ static void synic_realize(DeviceState *dev, Error **errp)
sizeof(*synic->event_page), &error_abort);
 synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr);
 synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr);
+qemu_mutex_init(&synic->sint_routes_mutex);
+QLIST_INIT(&synic->sint_routes);
 
 g_free(msgp_name);
 g_free(eventp_name);
 }
+
 static void synic_reset(DeviceState *dev)
 {
 SynICState *synic = SYNIC(dev);
 memset(synic->msg_page, 0, sizeof(*synic->msg_page));
 memset(synic->event_page, 0, sizeof(*synic->event_page));
 synic_update(synic, false, 0, 0);
+assert(QLIST_EMPTY(&synic->sint_routes));
 }
 
 static void s

[PATCH v1 2/4] hyperv: Add definitions for syndbg

2022-02-04 Thread Jon Doron
Add all required definitions for hyperv synthetic debugger interface.

Signed-off-by: Jon Doron 
---
 include/hw/hyperv/hyperv-proto.h | 52 
 target/i386/kvm/hyperv-proto.h   | 37 +++
 2 files changed, 89 insertions(+)

diff --git a/include/hw/hyperv/hyperv-proto.h b/include/hw/hyperv/hyperv-proto.h
index 21dc28aee9..94c9658eb0 100644
--- a/include/hw/hyperv/hyperv-proto.h
+++ b/include/hw/hyperv/hyperv-proto.h
@@ -24,12 +24,17 @@
 #define HV_STATUS_INVALID_PORT_ID 17
 #define HV_STATUS_INVALID_CONNECTION_ID   18
 #define HV_STATUS_INSUFFICIENT_BUFFERS19
+#define HV_STATUS_NOT_ACKNOWLEDGED20
+#define HV_STATUS_NO_DATA 27
 
 /*
  * Hypercall numbers
  */
 #define HV_POST_MESSAGE   0x005c
 #define HV_SIGNAL_EVENT   0x005d
+#define HV_POST_DEBUG_DATA0x0069
+#define HV_RETREIVE_DEBUG_DATA0x006a
+#define HV_RESET_DEBUG_SESSION0x006b
 #define HV_HYPERCALL_FAST (1u << 16)
 
 /*
@@ -127,4 +132,51 @@ struct hyperv_event_flags_page {
 struct hyperv_event_flags slot[HV_SINT_COUNT];
 };
 
+/*
+ * Kernel debugger structures
+ */
+
+/* Options flags for hyperv_reset_debug_session */
+#define HV_DEBUG_PURGE_INCOMING_DATA0x0001
+#define HV_DEBUG_PURGE_OUTGOING_DATA0x0002
+struct hyperv_reset_debug_session_input {
+uint32_t options;
+} __attribute__ ((__packed__));
+
+struct hyperv_reset_debug_session_output {
+uint32_t host_ip;
+uint32_t target_ip;
+uint16_t host_port;
+uint16_t target_port;
+uint8_t host_mac[6];
+uint8_t target_mac[6];
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_post_debug_data */
+#define HV_DEBUG_POST_LOOP  0x0001
+
+struct hyperv_post_debug_data_input {
+uint32_t count;
+uint32_t options;
+/*uint8_t data[HV_HYP_PAGE_SIZE - 2 * sizeof(uint32_t)];*/
+} __attribute__ ((__packed__));
+
+struct hyperv_post_debug_data_output {
+uint32_t pending_count;
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_retrieve_debug_data */
+#define HV_DEBUG_RETRIEVE_LOOP  0x0001
+#define HV_DEBUG_RETRIEVE_TEST_ACTIVITY 0x0002
+
+struct hyperv_retrieve_debug_data_input {
+uint32_t count;
+uint32_t options;
+uint64_t timeout;
+} __attribute__ ((__packed__));
+
+struct hyperv_retrieve_debug_data_output {
+uint32_t retrieved_count;
+uint32_t remaining_count;
+} __attribute__ ((__packed__));
 #endif
diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h
index 89f81afda7..9480bcdf04 100644
--- a/target/i386/kvm/hyperv-proto.h
+++ b/target/i386/kvm/hyperv-proto.h
@@ -19,6 +19,9 @@
 #define HV_CPUID_ENLIGHTMENT_INFO 0x4004
 #define HV_CPUID_IMPLEMENT_LIMITS 0x4005
 #define HV_CPUID_NESTED_FEATURES  0x400A
+#define HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS0x4080
+#define HV_CPUID_SYNDBG_INTERFACE   0x4081
+#define HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES   0x4082
 #define HV_CPUID_MIN  0x4005
 #define HV_CPUID_MAX  0x4000
 #define HV_HYPERVISOR_PRESENT_BIT 0x8000
@@ -55,8 +58,14 @@
 #define HV_GUEST_IDLE_STATE_AVAILABLE   (1u << 5)
 #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8)
 #define HV_GUEST_CRASH_MSR_AVAILABLE(1u << 10)
+#define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11)
 #define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19)
 
+/*
+ * HV_CPUID_FEATURES.EBX bits
+ */
+#define HV_PARTITION_DEUBGGING_ALLOWED  (1u << 12)
+
 /*
  * HV_CPUID_ENLIGHTMENT_INFO.EAX bits
  */
@@ -72,6 +81,11 @@
 #define HV_ENLIGHTENED_VMCS_RECOMMENDED (1u << 14)
 #define HV_NO_NONARCH_CORESHARING   (1u << 18)
 
+/*
+ * HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX bits
+ */
+#define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING(1u << 1)
+
 /*
  * Basic virtualized MSRs
  */
@@ -130,6 +144,18 @@
 #define HV_X64_MSR_STIMER3_CONFIG   0x40B6
 #define HV_X64_MSR_STIMER3_COUNT0x40B7
 
+/*
+ * Hyper-V Synthetic debug options MSR
+ */
+#define HV_X64_MSR_SYNDBG_CONTROL   0x40F1
+#define HV_X64_MSR_SYNDBG_STATUS0x40F2
+#define HV_X64_MSR_SYNDBG_SEND_BUFFER   0x40F3
+#define HV_X64_MSR_SYNDBG_RECV_BUFFER   0x40F4
+#define HV_X64_MSR_SYNDBG_PENDING_BUFFER0x40F5
+#define HV_X64_MSR_SYNDBG_OPTIONS   0x40FF
+
+#define HV_X64_SYNDBG_OPTION_USE_HCALLS BIT(2)
+
 /*
  * Guest crash notification MSRs
  */
@@ -168,5 +194,16 @@
 
 #define HV_STIMER_COUNT   4
 
+/*
+ * Synthetic debugger control definitions
+ */
+#define HV_SYNDBG_CONTROL_SEND  (1u << 

[PATCH v1 4/4] hw: hyperv: Initial commit for Synthetic Debugging device

2022-02-04 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 hw/hyperv/Kconfig |   5 +
 hw/hyperv/meson.build |   1 +
 hw/hyperv/syndbg.c| 407 ++
 3 files changed, 413 insertions(+)
 create mode 100644 hw/hyperv/syndbg.c

diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig
index 3fbfe41c9e..fcf65903bd 100644
--- a/hw/hyperv/Kconfig
+++ b/hw/hyperv/Kconfig
@@ -11,3 +11,8 @@ config VMBUS
 bool
 default y
 depends on HYPERV
+
+config SYNDBG
+bool
+default y
+depends on VMBUS
diff --git a/hw/hyperv/meson.build b/hw/hyperv/meson.build
index 1367e2994f..b43f119ea5 100644
--- a/hw/hyperv/meson.build
+++ b/hw/hyperv/meson.build
@@ -1,3 +1,4 @@
 specific_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'))
 specific_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true: 
files('hyperv_testdev.c'))
 specific_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c'))
+specific_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c'))
diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c
new file mode 100644
index 00..837eb33458
--- /dev/null
+++ b/hw/hyperv/syndbg.c
@@ -0,0 +1,407 @@
+/*
+ * QEMU Hyper-V Synthetic Debugging device
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/ctype.h"
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+#include "qemu/sockets.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/loader.h"
+#include "cpu.h"
+#include "hw/hyperv/hyperv.h"
+#include "hw/hyperv/vmbus-bridge.h"
+#include "hw/hyperv/hyperv-proto.h"
+#include "net/net.h"
+#include "net/eth.h"
+#include "net/checksum.h"
+#include "trace.h"
+
+#define TYPE_HV_SYNDBG   "hv-syndbg"
+
+typedef struct HvSynDbg {
+DeviceState parent_obj;
+
+char *host_ip;
+uint16_t host_port;
+bool use_hcalls;
+
+uint32_t target_ip;
+struct sockaddr_in servaddr;
+int socket;
+bool has_data_pending;
+uint64_t pending_page_gpa;
+} HvSynDbg;
+
+#define HVSYNDBG(obj) OBJECT_CHECK(HvSynDbg, (obj), TYPE_HV_SYNDBG)
+
+/* returns NULL unless there is exactly one HV Synth debug device */
+static HvSynDbg *hv_syndbg_find(void)
+{
+/* Returns NULL unless there is exactly one hvsd device */
+return HVSYNDBG(object_resolve_path_type("", TYPE_HV_SYNDBG, NULL));
+}
+
+static void set_pending_state(HvSynDbg *syndbg, bool has_pending)
+{
+hwaddr out_len;
+void *out_data;
+
+syndbg->has_data_pending = has_pending;
+
+if (!syndbg->pending_page_gpa) {
+return;
+}
+
+out_len = 1;
+out_data = cpu_physical_memory_map(syndbg->pending_page_gpa, &out_len, 1);
+if (out_data) {
+*(uint8_t *)out_data = !!has_pending;
+cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
+}
+}
+
+static bool get_udb_pkt_data(void *p, uint32_t len, uint32_t *data_ofs,
+ uint32_t *src_ip)
+{
+uint32_t offset, curr_len = len;
+
+if (curr_len < sizeof(struct eth_header) ||
+(be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto) != ETH_P_IP)) {
+return false;
+}
+offset = sizeof(struct eth_header);
+curr_len -= sizeof(struct eth_header);
+
+if (curr_len < sizeof(struct ip_header) ||
+PKT_GET_IP_HDR(p)->ip_p != IP_PROTO_UDP) {
+return false;
+}
+offset += PKT_GET_IP_HDR_LEN(p);
+curr_len -= PKT_GET_IP_HDR_LEN(p);
+
+if (curr_len < sizeof(struct udp_header)) {
+return false;
+}
+
+offset += sizeof(struct udp_header);
+*data_ofs = offset;
+*src_ip = PKT_GET_IP_HDR(p)->ip_src;
+return true;
+}
+
+static uint16_t handle_send_msg(HvSynDbg *syndbg, uint64_t ingpa,
+uint32_t count, bool is_raw,
+uint32_t *pending_count)
+{
+uint16_t ret;
+hwaddr data_len;
+void *debug_data = NULL;
+uint32_t udp_data_ofs = 0;
+const void *pkt_data;
+int sent_count;
+
+data_len = count;
+debug_data = cpu_physical_memory_map(ingpa, &data_len, 0);
+if (!debug_data || data_len < count) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+if (is_raw &&
+!get_udb_pkt_data(debug_data, count, &udp_data_ofs,
+  &syndbg->target_ip)) {
+ret = HV_STATUS_SUCCESS;
+goto cleanup;
+}
+
+pkt_data = (const void *)((uintptr_t)debug_data + udp_data_ofs);
+sent_count = qemu_sendto(syndbg->socket, pkt_data, count - udp_data_ofs,
+   

Re: [PATCH v1 0/4] HyperV: Synthetic Debugging device

2022-02-12 Thread Jon Doron

On 04/02/2022, Jon Doron wrote:

Ping


This patchset adds support for the synthetic debugging device.

HyperV supports a special transport layer for the kernel debugger when
running in HyperV.

This patchset add supports for this device so you could have a setup
fast windows kernel debugging.

At this point of time, DHCP is not implmeneted so to set this up few
things need to be noted.

The scenario I used to test is having 2 VMs in the same virtual network
i.e a Debugger VM with the NIC:
-nic tap,model=virtio,mac=02:ca:01:01:01:01,script=/etc/qemu-ifup
And it's IP is going to be static 192.168.53.12
And the VM we want to debug, to which we need to have the englightments
and vmbus configured:
-cpu 
host,hv-relaxed,hv_spinlocks=0x1fff,hv_time,+vmx,invtsc,hv-vapic,hv-vpindex,hv-synic,hv-syndbg
 \
-device vmbus-bridge \
-device hv-syndbg,host_ip=192.168.53.12,host_port=5,use_hcalls=false \
-nic tap,model=virtio,mac=02:ca:01:01:01:02,script=/etc/qemu-ifup \

Then in the debuggee VM we would setup the kernel debugging in the
following way:

If the VM is older than Win8:
* Copy the proper platform kdvm.dll (make sure it's called kdvm.dll even if 
platform is 32bit)
bcdedit /set {GUID} dbgtransport kdvm.dll
bcdedit /set {GUID} loadoptions host_ip="1.2.3.4",host_port="5",nodhcp
bcdedit /set {GUID} debug on
bcdedit /set {GUID} halbreakpoint on

Win8 and late:
bcdedit /dbgsettings net hostip:7.7.7.7 port:5 nodhcp

This is all the setup that is required to get the synthetic debugger
configured correctly.

Jon Doron (4):
 hyperv: SControl is optional to enable SynIc
 hyperv: Add definitions for syndbg
 hyperv: Add support to process syndbg commands
 hw: hyperv: Initial commit for Synthetic Debugging device

docs/hyperv.txt  |  15 +
hw/hyperv/Kconfig|   5 +
hw/hyperv/hyperv.c   | 475 +--
hw/hyperv/meson.build|   1 +
hw/hyperv/syndbg.c   | 407 ++
include/hw/hyperv/hyperv-proto.h |  52 
include/hw/hyperv/hyperv.h   |  60 
target/i386/cpu.c|   2 +
target/i386/cpu.h|   7 +
target/i386/kvm/hyperv-proto.h   |  37 +++
target/i386/kvm/hyperv-stub.c|   6 +
target/i386/kvm/hyperv.c |  52 +++-
target/i386/kvm/kvm.c|  76 -
13 files changed, 1105 insertions(+), 90 deletions(-)
create mode 100644 hw/hyperv/syndbg.c

--
2.34.1





[PATCH v2 2/4] hyperv: Add definitions for syndbg

2022-02-16 Thread Jon Doron
Add all required definitions for hyperv synthetic debugger interface.

Signed-off-by: Jon Doron 
---
 include/hw/hyperv/hyperv-proto.h | 52 
 target/i386/kvm/hyperv-proto.h   | 37 +++
 2 files changed, 89 insertions(+)

diff --git a/include/hw/hyperv/hyperv-proto.h b/include/hw/hyperv/hyperv-proto.h
index 21dc28aee9..4a2297307b 100644
--- a/include/hw/hyperv/hyperv-proto.h
+++ b/include/hw/hyperv/hyperv-proto.h
@@ -24,12 +24,17 @@
 #define HV_STATUS_INVALID_PORT_ID 17
 #define HV_STATUS_INVALID_CONNECTION_ID   18
 #define HV_STATUS_INSUFFICIENT_BUFFERS19
+#define HV_STATUS_NOT_ACKNOWLEDGED20
+#define HV_STATUS_NO_DATA 27
 
 /*
  * Hypercall numbers
  */
 #define HV_POST_MESSAGE   0x005c
 #define HV_SIGNAL_EVENT   0x005d
+#define HV_POST_DEBUG_DATA0x0069
+#define HV_RETRIEVE_DEBUG_DATA0x006a
+#define HV_RESET_DEBUG_SESSION0x006b
 #define HV_HYPERCALL_FAST (1u << 16)
 
 /*
@@ -127,4 +132,51 @@ struct hyperv_event_flags_page {
 struct hyperv_event_flags slot[HV_SINT_COUNT];
 };
 
+/*
+ * Kernel debugger structures
+ */
+
+/* Options flags for hyperv_reset_debug_session */
+#define HV_DEBUG_PURGE_INCOMING_DATA0x0001
+#define HV_DEBUG_PURGE_OUTGOING_DATA0x0002
+struct hyperv_reset_debug_session_input {
+uint32_t options;
+} __attribute__ ((__packed__));
+
+struct hyperv_reset_debug_session_output {
+uint32_t host_ip;
+uint32_t target_ip;
+uint16_t host_port;
+uint16_t target_port;
+uint8_t host_mac[6];
+uint8_t target_mac[6];
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_post_debug_data */
+#define HV_DEBUG_POST_LOOP  0x0001
+
+struct hyperv_post_debug_data_input {
+uint32_t count;
+uint32_t options;
+/*uint8_t data[HV_HYP_PAGE_SIZE - 2 * sizeof(uint32_t)];*/
+} __attribute__ ((__packed__));
+
+struct hyperv_post_debug_data_output {
+uint32_t pending_count;
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_retrieve_debug_data */
+#define HV_DEBUG_RETRIEVE_LOOP  0x0001
+#define HV_DEBUG_RETRIEVE_TEST_ACTIVITY 0x0002
+
+struct hyperv_retrieve_debug_data_input {
+uint32_t count;
+uint32_t options;
+uint64_t timeout;
+} __attribute__ ((__packed__));
+
+struct hyperv_retrieve_debug_data_output {
+uint32_t retrieved_count;
+uint32_t remaining_count;
+} __attribute__ ((__packed__));
 #endif
diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h
index 89f81afda7..e40e59411c 100644
--- a/target/i386/kvm/hyperv-proto.h
+++ b/target/i386/kvm/hyperv-proto.h
@@ -19,6 +19,9 @@
 #define HV_CPUID_ENLIGHTMENT_INFO 0x4004
 #define HV_CPUID_IMPLEMENT_LIMITS 0x4005
 #define HV_CPUID_NESTED_FEATURES  0x400A
+#define HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS0x4080
+#define HV_CPUID_SYNDBG_INTERFACE   0x4081
+#define HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES   0x4082
 #define HV_CPUID_MIN  0x4005
 #define HV_CPUID_MAX  0x4000
 #define HV_HYPERVISOR_PRESENT_BIT 0x8000
@@ -55,8 +58,14 @@
 #define HV_GUEST_IDLE_STATE_AVAILABLE   (1u << 5)
 #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8)
 #define HV_GUEST_CRASH_MSR_AVAILABLE(1u << 10)
+#define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11)
 #define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19)
 
+/*
+ * HV_CPUID_FEATURES.EBX bits
+ */
+#define HV_PARTITION_DEBUGGING_ALLOWED  (1u << 12)
+
 /*
  * HV_CPUID_ENLIGHTMENT_INFO.EAX bits
  */
@@ -72,6 +81,11 @@
 #define HV_ENLIGHTENED_VMCS_RECOMMENDED (1u << 14)
 #define HV_NO_NONARCH_CORESHARING   (1u << 18)
 
+/*
+ * HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX bits
+ */
+#define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING(1u << 1)
+
 /*
  * Basic virtualized MSRs
  */
@@ -130,6 +144,18 @@
 #define HV_X64_MSR_STIMER3_CONFIG   0x40B6
 #define HV_X64_MSR_STIMER3_COUNT0x40B7
 
+/*
+ * Hyper-V Synthetic debug options MSR
+ */
+#define HV_X64_MSR_SYNDBG_CONTROL   0x40F1
+#define HV_X64_MSR_SYNDBG_STATUS0x40F2
+#define HV_X64_MSR_SYNDBG_SEND_BUFFER   0x40F3
+#define HV_X64_MSR_SYNDBG_RECV_BUFFER   0x40F4
+#define HV_X64_MSR_SYNDBG_PENDING_BUFFER0x40F5
+#define HV_X64_MSR_SYNDBG_OPTIONS   0x40FF
+
+#define HV_X64_SYNDBG_OPTION_USE_HCALLS BIT(2)
+
 /*
  * Guest crash notification MSRs
  */
@@ -168,5 +194,16 @@
 
 #define HV_STIMER_COUNT   4
 
+/*
+ * Synthetic debugger control definitions
+ */
+#define HV_SYNDBG_CONTROL_SEND  (1u << 

[PATCH v2 4/4] hw: hyperv: Initial commit for Synthetic Debugging device

2022-02-16 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 hw/hyperv/Kconfig |   5 +
 hw/hyperv/meson.build |   1 +
 hw/hyperv/syndbg.c| 402 ++
 3 files changed, 408 insertions(+)
 create mode 100644 hw/hyperv/syndbg.c

diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig
index 3fbfe41c9e..fcf65903bd 100644
--- a/hw/hyperv/Kconfig
+++ b/hw/hyperv/Kconfig
@@ -11,3 +11,8 @@ config VMBUS
 bool
 default y
 depends on HYPERV
+
+config SYNDBG
+bool
+default y
+depends on VMBUS
diff --git a/hw/hyperv/meson.build b/hw/hyperv/meson.build
index 1367e2994f..b43f119ea5 100644
--- a/hw/hyperv/meson.build
+++ b/hw/hyperv/meson.build
@@ -1,3 +1,4 @@
 specific_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'))
 specific_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true: 
files('hyperv_testdev.c'))
 specific_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c'))
+specific_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c'))
diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c
new file mode 100644
index 00..8816bc4082
--- /dev/null
+++ b/hw/hyperv/syndbg.c
@@ -0,0 +1,402 @@
+/*
+ * QEMU Hyper-V Synthetic Debugging device
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/ctype.h"
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+#include "qemu/sockets.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/loader.h"
+#include "cpu.h"
+#include "hw/hyperv/hyperv.h"
+#include "hw/hyperv/vmbus-bridge.h"
+#include "hw/hyperv/hyperv-proto.h"
+#include "net/net.h"
+#include "net/eth.h"
+#include "net/checksum.h"
+#include "trace.h"
+
+#define TYPE_HV_SYNDBG   "hv-syndbg"
+
+typedef struct HvSynDbg {
+DeviceState parent_obj;
+
+char *host_ip;
+uint16_t host_port;
+bool use_hcalls;
+
+uint32_t target_ip;
+struct sockaddr_in servaddr;
+int socket;
+bool has_data_pending;
+uint64_t pending_page_gpa;
+} HvSynDbg;
+
+#define HVSYNDBG(obj) OBJECT_CHECK(HvSynDbg, (obj), TYPE_HV_SYNDBG)
+
+/* returns NULL unless there is exactly one HV Synth debug device */
+static HvSynDbg *hv_syndbg_find(void)
+{
+/* Returns NULL unless there is exactly one hvsd device */
+return HVSYNDBG(object_resolve_path_type("", TYPE_HV_SYNDBG, NULL));
+}
+
+static void set_pending_state(HvSynDbg *syndbg, bool has_pending)
+{
+hwaddr out_len;
+void *out_data;
+
+syndbg->has_data_pending = has_pending;
+
+if (!syndbg->pending_page_gpa) {
+return;
+}
+
+out_len = 1;
+out_data = cpu_physical_memory_map(syndbg->pending_page_gpa, &out_len, 1);
+if (out_data) {
+*(uint8_t *)out_data = !!has_pending;
+cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
+}
+}
+
+static bool get_udb_pkt_data(void *p, uint32_t len, uint32_t *data_ofs,
+ uint32_t *src_ip)
+{
+uint32_t offset, curr_len = len;
+
+if (curr_len < sizeof(struct eth_header) ||
+(be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto) != ETH_P_IP)) {
+return false;
+}
+offset = sizeof(struct eth_header);
+curr_len -= sizeof(struct eth_header);
+
+if (curr_len < sizeof(struct ip_header) ||
+PKT_GET_IP_HDR(p)->ip_p != IP_PROTO_UDP) {
+return false;
+}
+offset += PKT_GET_IP_HDR_LEN(p);
+curr_len -= PKT_GET_IP_HDR_LEN(p);
+
+if (curr_len < sizeof(struct udp_header)) {
+return false;
+}
+
+offset += sizeof(struct udp_header);
+*data_ofs = offset;
+*src_ip = PKT_GET_IP_HDR(p)->ip_src;
+return true;
+}
+
+static uint16_t handle_send_msg(HvSynDbg *syndbg, uint64_t ingpa,
+uint32_t count, bool is_raw,
+uint32_t *pending_count)
+{
+uint16_t ret;
+hwaddr data_len;
+void *debug_data = NULL;
+uint32_t udp_data_ofs = 0;
+const void *pkt_data;
+int sent_count;
+
+data_len = count;
+debug_data = cpu_physical_memory_map(ingpa, &data_len, 0);
+if (!debug_data || data_len < count) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+if (is_raw &&
+!get_udb_pkt_data(debug_data, count, &udp_data_ofs,
+  &syndbg->target_ip)) {
+ret = HV_STATUS_SUCCESS;
+goto cleanup;
+}
+
+pkt_data = (const void *)((uintptr_t)debug_data + udp_data_ofs);
+sent_count = qemu_sendto(syndbg->socket, pkt_data, count - udp_data_ofs,
+   

[PATCH v2 1/4] hyperv: SControl is optional to enable SynIc

2022-02-16 Thread Jon Doron
SynIc can be enabled regardless of the SControl mechanisim which can
register a GSI for a given SintRoute.

This behaviour can achived by setting enabling SIMP and then the guest
will poll on the message slot.

Once there is another message pending the host will set the message slot
with the pending flag.
When the guest polls from the message slot, in case the pending flag is
set it will write to the HV_X64_MSR_EOM indicating it has cleared the
slot and we can try and push our message again.

Signed-off-by: Jon Doron 
---
 hw/hyperv/hyperv.c | 109 +++--
 1 file changed, 76 insertions(+), 33 deletions(-)

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index cb1074f234..aaba6b4901 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -27,13 +27,16 @@ struct SynICState {
 
 CPUState *cs;
 
-bool enabled;
+bool sctl_enabled;
 hwaddr msg_page_addr;
 hwaddr event_page_addr;
 MemoryRegion msg_page_mr;
 MemoryRegion event_page_mr;
 struct hyperv_message_page *msg_page;
 struct hyperv_event_flags_page *event_page;
+
+QemuMutex sint_routes_mutex;
+QLIST_HEAD(, HvSintRoute) sint_routes;
 };
 
 #define TYPE_SYNIC "hyperv-synic"
@@ -51,11 +54,11 @@ static SynICState *get_synic(CPUState *cs)
 return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
 }
 
-static void synic_update(SynICState *synic, bool enable,
+static void synic_update(SynICState *synic, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 
-synic->enabled = enable;
+synic->sctl_enabled = sctl_enable;
 if (synic->msg_page_addr != msg_page_addr) {
 if (synic->msg_page_addr) {
 memory_region_del_subregion(get_system_memory(),
@@ -80,7 +83,7 @@ static void synic_update(SynICState *synic, bool enable,
 }
 }
 
-void hyperv_synic_update(CPUState *cs, bool enable,
+void hyperv_synic_update(CPUState *cs, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 SynICState *synic = get_synic(cs);
@@ -89,7 +92,7 @@ void hyperv_synic_update(CPUState *cs, bool enable,
 return;
 }
 
-synic_update(synic, enable, msg_page_addr, event_page_addr);
+synic_update(synic, sctl_enable, msg_page_addr, event_page_addr);
 }
 
 static void synic_realize(DeviceState *dev, Error **errp)
@@ -110,16 +113,20 @@ static void synic_realize(DeviceState *dev, Error **errp)
sizeof(*synic->event_page), &error_abort);
 synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr);
 synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr);
+qemu_mutex_init(&synic->sint_routes_mutex);
+QLIST_INIT(&synic->sint_routes);
 
 g_free(msgp_name);
 g_free(eventp_name);
 }
+
 static void synic_reset(DeviceState *dev)
 {
 SynICState *synic = SYNIC(dev);
 memset(synic->msg_page, 0, sizeof(*synic->msg_page));
 memset(synic->event_page, 0, sizeof(*synic->event_page));
 synic_update(synic, false, 0, 0);
+assert(QLIST_EMPTY(&synic->sint_routes));
 }
 
 static void synic_class_init(ObjectClass *klass, void *data)
@@ -214,6 +221,7 @@ struct HvSintRoute {
 HvSintStagedMessage *staged_msg;
 
 unsigned refcount;
+QLIST_ENTRY(HvSintRoute) link;
 };
 
 static CPUState *hyperv_find_vcpu(uint32_t vp_index)
@@ -259,7 +267,7 @@ static void cpu_post_msg(CPUState *cs, run_on_cpu_data data)
 
 assert(staged_msg->state == HV_STAGED_MSG_BUSY);
 
-if (!synic->enabled || !synic->msg_page_addr) {
+if (!synic->msg_page_addr) {
 staged_msg->status = -ENXIO;
 goto posted;
 }
@@ -343,7 +351,7 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned 
eventno)
 if (eventno > HV_EVENT_FLAGS_COUNT) {
 return -EINVAL;
 }
-if (!synic->enabled || !synic->event_page_addr) {
+if (!synic->sctl_enabled || !synic->event_page_addr) {
 return -ENXIO;
 }
 
@@ -364,11 +372,12 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, 
unsigned eventno)
 HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
HvSintMsgCb cb, void *cb_data)
 {
-HvSintRoute *sint_route;
-EventNotifier *ack_notifier;
+HvSintRoute *sint_route = NULL;
+EventNotifier *ack_notifier = NULL;
 int r, gsi;
 CPUState *cs;
 SynICState *synic;
+bool ack_event_initialized = false;
 
 cs = hyperv_find_vcpu(vp_index);
 if (!cs) {
@@ -381,57 +390,77 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, 
uint32_t sint,
 }
 
 sint_route = g_new0(HvSintRoute, 1);
-r = event_notifier_init(&sint_route->sint_set_notifier, false);
-if (r) {
-goto err;
+if (!sint_route) {
+return NULL;
 }
 
+sint_route->synic = 

[PATCH v2 0/4] HyperV: Synthetic Debugging device

2022-02-16 Thread Jon Doron
This patchset adds support for the synthetic debugging device.

HyperV supports a special transport layer for the kernel debugger when
running in HyperV.

This patchset add supports for this device so you could have a setup
fast windows kernel debugging.

At this point of time, DHCP is not implmeneted so to set this up few
things need to be noted.

The scenario I used to test is having 2 VMs in the same virtual network
i.e a Debugger VM with the NIC:
-nic tap,model=virtio,mac=02:ca:01:01:01:01,script=/etc/qemu-ifup
And it's IP is going to be static 192.168.53.12
And the VM we want to debug, to which we need to have the englightments
and vmbus configured:
 -cpu 
host,hv-relaxed,hv_spinlocks=0x1fff,hv_time,+vmx,invtsc,hv-vapic,hv-vpindex,hv-synic,hv-syndbg
 \
 -device vmbus-bridge \
 -device hv-syndbg,host_ip=192.168.53.12,host_port=5,use_hcalls=false \
 -nic tap,model=virtio,mac=02:ca:01:01:01:02,script=/etc/qemu-ifup \

Then in the debuggee VM we would setup the kernel debugging in the
following way:

If the VM is older than Win8:
* Copy the proper platform kdvm.dll (make sure it's called kdvm.dll even if 
platform is 32bit)
bcdedit /set {GUID} dbgtransport kdvm.dll
bcdedit /set {GUID} loadoptions host_ip="1.2.3.4",host_port="5",nodhcp
bcdedit /set {GUID} debug on
bcdedit /set {GUID} halbreakpoint on

Win8 and late:
bcdedit /dbgsettings net hostip:7.7.7.7 port:5 nodhcp

This is all the setup that is required to get the synthetic debugger
configured correctly.

Jon Doron (4):
  hyperv: SControl is optional to enable SynIc
  hyperv: Add definitions for syndbg
  hyperv: Add support to process syndbg commands
  hw: hyperv: Initial commit for Synthetic Debugging device

 docs/hyperv.txt  |  15 ++
 hw/hyperv/Kconfig|   5 +
 hw/hyperv/hyperv.c   | 352 ---
 hw/hyperv/meson.build|   1 +
 hw/hyperv/syndbg.c   | 402 +++
 include/hw/hyperv/hyperv-proto.h |  52 
 include/hw/hyperv/hyperv.h   |  58 +
 target/i386/cpu.c|   2 +
 target/i386/cpu.h|   7 +
 target/i386/kvm/hyperv-proto.h   |  37 +++
 target/i386/kvm/hyperv-stub.c|   6 +
 target/i386/kvm/hyperv.c |  52 +++-
 target/i386/kvm/kvm.c|  76 +-
 13 files changed, 1024 insertions(+), 41 deletions(-)
 create mode 100644 hw/hyperv/syndbg.c

-- 
2.35.1




[PATCH v2 3/4] hyperv: Add support to process syndbg commands

2022-02-16 Thread Jon Doron
SynDbg commands can come from two different flows:
1. Hypercalls, in this mode the data being sent is fully
   encapsulated network packets.
2. SynDbg specific MSRs, in this mode only the data that needs to be
   transfered is passed.

Signed-off-by: Jon Doron 
---
 docs/hyperv.txt   |  15 +++
 hw/hyperv/hyperv.c| 243 ++
 include/hw/hyperv/hyperv.h|  58 
 target/i386/cpu.c |   2 +
 target/i386/cpu.h |   7 +
 target/i386/kvm/hyperv-stub.c |   6 +
 target/i386/kvm/hyperv.c  |  52 +++-
 target/i386/kvm/kvm.c |  76 ++-
 8 files changed, 451 insertions(+), 8 deletions(-)

diff --git a/docs/hyperv.txt b/docs/hyperv.txt
index 0417c183a3..33588a0396 100644
--- a/docs/hyperv.txt
+++ b/docs/hyperv.txt
@@ -225,6 +225,21 @@ default (WS2016).
 Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V
 identification when specified without any other enlightenments.
 
+3.21. hv-syndbg
+===
+Enables Hyper-V synthetic debugger interface, this is a special interface used
+by Windows Kernel debugger to send the packets through, rather than sending
+them via serial/network .
+When enabled, this enlightenment provides additional communication facilities
+to the guest: SynDbg messages.
+This new communication is used by Windows Kernel debugger rather than sending
+packets via serial/network, adding significant performance boost over the other
+comm channels.
+This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15)
+and the follow enlightenments to work:
+hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer
+
+
 4. Supplementary features
 =
 
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index aaba6b4901..86d295395e 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -704,3 +704,246 @@ uint16_t hyperv_hcall_signal_event(uint64_t param, bool 
fast)
 }
 return HV_STATUS_INVALID_CONNECTION_ID;
 }
+
+static HvSynDbgHandler hv_syndbg_handler;
+static void *hv_syndbg_context;
+
+void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context)
+{
+assert(!hv_syndbg_handler);
+hv_syndbg_handler = handler;
+hv_syndbg_context = context;
+}
+
+uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa)
+{
+uint16_t ret;
+HvSynDbgMsg msg;
+struct hyperv_reset_debug_session_output *reset_dbg_session = NULL;
+hwaddr len;
+
+if (!hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+len = sizeof(*reset_dbg_session);
+reset_dbg_session = cpu_physical_memory_map(outgpa, &len, 1);
+if (!reset_dbg_session || len < sizeof(*reset_dbg_session)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_CONNECTION_INFO;
+ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+if (ret) {
+goto cleanup;
+}
+
+reset_dbg_session->host_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->host_port = msg.u.connection_info.host_port;
+/* The following fields are only used as validation for KDVM */
+memset(&reset_dbg_session->host_mac, 0,
+   sizeof(reset_dbg_session->host_mac));
+reset_dbg_session->target_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->target_port = msg.u.connection_info.host_port;
+memset(&reset_dbg_session->target_mac, 0,
+   sizeof(reset_dbg_session->target_mac));
+cleanup:
+if (reset_dbg_session) {
+cpu_physical_memory_unmap(reset_dbg_session,
+  sizeof(*reset_dbg_session), 1, len);
+}
+
+return ret;
+}
+
+uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa,
+bool fast)
+{
+uint16_t ret;
+struct hyperv_retrieve_debug_data_input *debug_data_in = NULL;
+struct hyperv_retrieve_debug_data_output *debug_data_out = NULL;
+hwaddr in_len, out_len;
+HvSynDbgMsg msg;
+
+if (fast || !hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+in_len = sizeof(*debug_data_in);
+debug_data_in = cpu_physical_memory_map(ingpa, &in_len, 0);
+if (!debug_data_in || in_len < sizeof(*debug_data_in)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+out_len = sizeof(*debug_data_out);
+debug_data_out = cpu_physical_memory_map(outgpa, &out_len, 1);
+if (!debug_data_out || out_len < sizeof(*debug_data_out)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_RECV;
+msg.u.recv.buf_gpa = outgpa + sizeof(*debug_data_out);
+msg.u.recv.count = TARGET_PAGE_SIZE - sizeof(*debug_data_out);
+msg.u.recv.options = debug_data_in->options;
+msg.u.recv.timeout 

Re: [PATCH v1 3/4] hyperv: Add support to process syndbg commands

2022-02-16 Thread Jon Doron

On 16/02/2022, Emanuele Giuseppe Esposito wrote:



On 04/02/2022 11:07, Jon Doron wrote:

SynDbg commands can come from two different flows:
1. Hypercalls, in this mode the data being sent is fully
   encapsulated network packets.
2. SynDbg specific MSRs, in this mode only the data that needs to be
   transfered is passed.

Signed-off-by: Jon Doron 
---
 docs/hyperv.txt   |  15 +++
 hw/hyperv/hyperv.c| 242 ++
 include/hw/hyperv/hyperv.h|  58 
 target/i386/cpu.c |   2 +
 target/i386/cpu.h |   7 +
 target/i386/kvm/hyperv-stub.c |   6 +
 target/i386/kvm/hyperv.c  |  52 +++-
 target/i386/kvm/kvm.c |  76 ++-
 8 files changed, 450 insertions(+), 8 deletions(-)

diff --git a/docs/hyperv.txt b/docs/hyperv.txt
index 0417c183a3..7abc1b2d89 100644
--- a/docs/hyperv.txt
+++ b/docs/hyperv.txt
@@ -225,6 +225,21 @@ default (WS2016).
 Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V
 identification when specified without any other enlightenments.

+3.21. hv-syndbg
+===
+Enables Hyper-V synthetic debugger interface, this is a special interface used
+by Windows Kernel debugger to send the packets through, rather than sending
+them via serial/network .
+Whe enabled, this enlightenment provides additional communication facilities


When


Done

+to the guest: SynDbg messages.
+This new communication is used by Windows Kernel debugger rather than sending
+packets via serial/network, adding significant performance boost over the other
+comm channels.
+This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15)
+and the follow enlightenments to work:
+hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer
+
+
 4. Supplementary features
 =

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 88c9cc1334..c86e2aa02e 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -730,3 +730,245 @@ uint16_t hyperv_hcall_signal_event(uint64_t param, bool 
fast)
 }
 return HV_STATUS_INVALID_CONNECTION_ID;
 }
+
+static HvSynDbgHandler hv_syndbg_handler;
+static void *hv_syndbg_context;


Add a line here between field and function definition.


Done

+void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context)
+{
+assert(!hv_syndbg_handler);
+hv_syndbg_handler = handler;
+hv_syndbg_context = context;
+}
+
+uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa)
+{
+uint16_t ret;
+HvSynDbgMsg msg;
+struct hyperv_reset_debug_session_output *reset_dbg_session = NULL;
+hwaddr len;
+
+if (!hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+len = sizeof(*reset_dbg_session);
+reset_dbg_session = cpu_physical_memory_map(outgpa, &len, 1);
+if (!reset_dbg_session || len < sizeof(*reset_dbg_session)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_CONNECTION_INFO;
+ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+if (ret) {
+goto cleanup;
+}
+
+reset_dbg_session->host_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->host_port = msg.u.connection_info.host_port;
+/* The following fields are only used as validation for KDVM */
+memset(&reset_dbg_session->host_mac, 0,
+   sizeof(reset_dbg_session->host_mac));
+reset_dbg_session->target_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->target_port = msg.u.connection_info.host_port;
+memset(&reset_dbg_session->target_mac, 0,
+   sizeof(reset_dbg_session->target_mac));
+cleanup:
+if (reset_dbg_session) {
+cpu_physical_memory_unmap(reset_dbg_session,
+  sizeof(*reset_dbg_session), 1, len);
+}
+
+return ret;
+}
+
+uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa,
+bool fast)
+{
+uint16_t ret;
+struct hyperv_retrieve_debug_data_input *debug_data_in = NULL;
+struct hyperv_retrieve_debug_data_output *debug_data_out = NULL;
+hwaddr in_len, out_len;
+HvSynDbgMsg msg;
+
+if (fast || !hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+in_len = sizeof(*debug_data_in);
+debug_data_in = cpu_physical_memory_map(ingpa, &in_len, 0);
+if (!debug_data_in || in_len < sizeof(*debug_data_in)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+out_len = sizeof(*debug_data_out);
+debug_data_out = cpu_physical_memory_map(outgpa, &out_len, 1);
+if (!debug_data_out || out_len < sizeof(*debug_data_out)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_RECV;
+msg.u.recv.buf_gpa = outgpa + sizeof(*debu

Re: [PATCH v1 1/4] hyperv: SControl is optional to enable SynIc

2022-02-16 Thread Jon Doron

On 16/02/2022, Emanuele Giuseppe Esposito wrote:



On 04/02/2022 11:07, Jon Doron wrote:

SynIc can be enabled regardless of the SControl mechanisim which can
register a GSI for a given SintRoute.

This behaviour can achived by setting enabling SIMP and then the guest
will poll on the message slot.

Once there is another message pending the host will set the message slot
with the pending flag.
When the guest polls from the message slot, incase the pending flag is


s/incase/in case

Done

set it will write to the HV_X64_MSR_EOM indicating it has cleared the
slow and we can try and push our message again.


what do you mean by "the slow"?

Just a typo to slot :) fixed


Signed-off-by: Jon Doron 
---
 hw/hyperv/hyperv.c | 233 -
 include/hw/hyperv/hyperv.h |   2 +
 2 files changed, 153 insertions(+), 82 deletions(-)

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index cb1074f234..88c9cc1334 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -27,18 +27,70 @@ struct SynICState {

 CPUState *cs;

-bool enabled;
+bool sctl_enabled;
 hwaddr msg_page_addr;
 hwaddr event_page_addr;
 MemoryRegion msg_page_mr;
 MemoryRegion event_page_mr;
 struct hyperv_message_page *msg_page;
 struct hyperv_event_flags_page *event_page;
+
+QemuMutex sint_routes_mutex;
+QLIST_HEAD(, HvSintRoute) sint_routes;
 };

 #define TYPE_SYNIC "hyperv-synic"
 OBJECT_DECLARE_SIMPLE_TYPE(SynICState, SYNIC)

+/*
+ * KVM has its own message producers (SynIC timers).  To guarantee
+ * serialization with both KVM vcpu and the guest cpu, the messages are first
+ * staged in an intermediate area and then posted to the SynIC message page in
+ * the vcpu thread.
+ */
+typedef struct HvSintStagedMessage {
+/* message content staged by hyperv_post_msg */
+struct hyperv_message msg;
+/* callback + data (r/o) to complete the processing in a BH */
+HvSintMsgCb cb;
+void *cb_data;
+/* message posting status filled by cpu_post_msg */
+int status;
+/* passing the buck: */
+enum {
+/* initial state */
+HV_STAGED_MSG_FREE,
+/*
+ * hyperv_post_msg (e.g. in main loop) grabs the staged area (FREE ->
+ * BUSY), copies msg, and schedules cpu_post_msg on the assigned cpu
+ */
+HV_STAGED_MSG_BUSY,
+/*
+ * cpu_post_msg (vcpu thread) tries to copy staged msg to msg slot,
+ * notify the guest, records the status, marks the posting done (BUSY
+ * -> POSTED), and schedules sint_msg_bh BH
+ */
+HV_STAGED_MSG_POSTED,
+/*
+ * sint_msg_bh (BH) verifies that the posting is done, runs the
+ * callback, and starts over (POSTED -> FREE)
+ */
+} state;
+} HvSintStagedMessage;
+
+struct HvSintRoute {
+uint32_t sint;
+SynICState *synic;
+int gsi;
+EventNotifier sint_set_notifier;
+EventNotifier sint_ack_notifier;
+
+HvSintStagedMessage *staged_msg;
+
+unsigned refcount;
+QLIST_ENTRY(HvSintRoute) link;
+};
+
 static bool synic_enabled;


Why did you move this struct above?
I think it was done purposefully to separate synic_* functions from the
others below (sint_*).

Done


 bool hyperv_is_synic_enabled(void)
@@ -51,11 +103,11 @@ static SynICState *get_synic(CPUState *cs)
 return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
 }

-static void synic_update(SynICState *synic, bool enable,
+static void synic_update(SynICState *synic, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {

-synic->enabled = enable;
+synic->sctl_enabled = sctl_enable;
 if (synic->msg_page_addr != msg_page_addr) {
 if (synic->msg_page_addr) {
 memory_region_del_subregion(get_system_memory(),
@@ -80,7 +132,7 @@ static void synic_update(SynICState *synic, bool enable,
 }
 }

-void hyperv_synic_update(CPUState *cs, bool enable,
+void hyperv_synic_update(CPUState *cs, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 SynICState *synic = get_synic(cs);
@@ -89,7 +141,7 @@ void hyperv_synic_update(CPUState *cs, bool enable,
 return;
 }

-synic_update(synic, enable, msg_page_addr, event_page_addr);
+synic_update(synic, sctl_enable, msg_page_addr, event_page_addr);
 }

 static void synic_realize(DeviceState *dev, Error **errp)
@@ -110,16 +162,20 @@ static void synic_realize(DeviceState *dev, Error **errp)
sizeof(*synic->event_page), &error_abort);
 synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr);
 synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr);
+qemu_mutex_init(&synic->sint_routes_mutex);
+QLIST_INIT(&synic->sint_routes);

 g_free(msgp_name);
 g_free(eventp_name);
 }
+
 s

Re: [PATCH v1 4/4] hw: hyperv: Initial commit for Synthetic Debugging device

2022-02-16 Thread Jon Doron

On 16/02/2022, Emanuele Giuseppe Esposito wrote:



+
+static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa,
+uint32_t count, bool is_raw, uint32_t options,
+uint64_t timeout, uint32_t *retrieved_count)
+{
+uint16_t ret;
+uint8_t data_buf[TARGET_PAGE_SIZE - UDP_PKT_HEADER_SIZE];
+hwaddr out_len;
+void *out_data = NULL;
+ssize_t recv_byte_count;
+
+/* TODO: Handle options and timeout */
+(void)options;
+(void)timeout;
+
+if (!syndbg->has_data_pending) {
+recv_byte_count = 0;
+} else {
+recv_byte_count = qemu_recv(syndbg->socket, data_buf,
+MIN(sizeof(data_buf), count), MSG_WAITALL);
+if (recv_byte_count == -1) {
+ret = HV_STATUS_INVALID_PARAMETER;
+goto cleanup;
+}
+}
+
+if (!recv_byte_count) {
+*retrieved_count = 0;
+ret = HV_STATUS_NO_DATA;
+goto cleanup;
+}
+
+set_pending_state(syndbg, false);
+
+out_len = recv_byte_count;
+if (is_raw) {
+out_len += UDP_PKT_HEADER_SIZE;
+}
+out_data = cpu_physical_memory_map(outgpa, &out_len, 1);
+if (!out_data) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+if (is_raw &&
+!create_udp_pkt(syndbg, out_data,
+recv_byte_count + UDP_PKT_HEADER_SIZE,
+data_buf, recv_byte_count)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+} else if (!is_raw) {
+memcpy(out_data, data_buf, recv_byte_count);
+}
+
+*retrieved_count = recv_byte_count;
+if (is_raw) {
+*retrieved_count += UDP_PKT_HEADER_SIZE;
+}
+ret = HV_STATUS_SUCCESS;
+cleanup:
+if (out_data) {
+cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
+}


Same nitpick as done in patch 1, I think you can use more gotos labels
instead of adding if statements.


Done

+
+return ret;
+}
+






Re: [PATCH v1 2/4] hyperv: Add definitions for syndbg

2022-02-16 Thread Jon Doron

On 16/02/2022, Emanuele Giuseppe Esposito wrote:



On 04/02/2022 11:07, Jon Doron wrote:

Add all required definitions for hyperv synthetic debugger interface.

Signed-off-by: Jon Doron 
---
 include/hw/hyperv/hyperv-proto.h | 52 
 target/i386/kvm/hyperv-proto.h   | 37 +++
 2 files changed, 89 insertions(+)

diff --git a/include/hw/hyperv/hyperv-proto.h b/include/hw/hyperv/hyperv-proto.h
index 21dc28aee9..94c9658eb0 100644
--- a/include/hw/hyperv/hyperv-proto.h
+++ b/include/hw/hyperv/hyperv-proto.h
@@ -24,12 +24,17 @@
 #define HV_STATUS_INVALID_PORT_ID 17
 #define HV_STATUS_INVALID_CONNECTION_ID   18
 #define HV_STATUS_INSUFFICIENT_BUFFERS19
+#define HV_STATUS_NOT_ACKNOWLEDGED20
+#define HV_STATUS_NO_DATA 27

 /*
  * Hypercall numbers
  */
 #define HV_POST_MESSAGE   0x005c
 #define HV_SIGNAL_EVENT   0x005d
+#define HV_POST_DEBUG_DATA0x0069
+#define HV_RETREIVE_DEBUG_DATA0x006a


s/RETREIVE/RETRIEVE?


Done

+#define HV_RESET_DEBUG_SESSION0x006b
 #define HV_HYPERCALL_FAST (1u << 16)

 /*
@@ -127,4 +132,51 @@ struct hyperv_event_flags_page {
 struct hyperv_event_flags slot[HV_SINT_COUNT];
 };

+/*
+ * Kernel debugger structures
+ */
+
+/* Options flags for hyperv_reset_debug_session */
+#define HV_DEBUG_PURGE_INCOMING_DATA0x0001
+#define HV_DEBUG_PURGE_OUTGOING_DATA0x0002
+struct hyperv_reset_debug_session_input {
+uint32_t options;
+} __attribute__ ((__packed__));
+
+struct hyperv_reset_debug_session_output {
+uint32_t host_ip;
+uint32_t target_ip;
+uint16_t host_port;
+uint16_t target_port;
+uint8_t host_mac[6];
+uint8_t target_mac[6];
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_post_debug_data */
+#define HV_DEBUG_POST_LOOP  0x0001
+
+struct hyperv_post_debug_data_input {
+uint32_t count;
+uint32_t options;



+/*uint8_t data[HV_HYP_PAGE_SIZE - 2 * sizeof(uint32_t)];*/


What is this comment for?


It's a reference how the data really looks like.

+} __attribute__ ((__packed__));
+
+struct hyperv_post_debug_data_output {
+uint32_t pending_count;
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_retrieve_debug_data */
+#define HV_DEBUG_RETRIEVE_LOOP  0x0001
+#define HV_DEBUG_RETRIEVE_TEST_ACTIVITY 0x0002
+
+struct hyperv_retrieve_debug_data_input {
+uint32_t count;
+uint32_t options;
+uint64_t timeout;
+} __attribute__ ((__packed__));
+
+struct hyperv_retrieve_debug_data_output {
+uint32_t retrieved_count;
+uint32_t remaining_count;
+} __attribute__ ((__packed__));
 #endif
diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h
index 89f81afda7..9480bcdf04 100644
--- a/target/i386/kvm/hyperv-proto.h
+++ b/target/i386/kvm/hyperv-proto.h
@@ -19,6 +19,9 @@
 #define HV_CPUID_ENLIGHTMENT_INFO 0x4004
 #define HV_CPUID_IMPLEMENT_LIMITS 0x4005
 #define HV_CPUID_NESTED_FEATURES  0x400A
+#define HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS0x4080
+#define HV_CPUID_SYNDBG_INTERFACE   0x4081
+#define HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES   0x4082
 #define HV_CPUID_MIN  0x4005
 #define HV_CPUID_MAX  0x4000
 #define HV_HYPERVISOR_PRESENT_BIT 0x8000
@@ -55,8 +58,14 @@
 #define HV_GUEST_IDLE_STATE_AVAILABLE   (1u << 5)
 #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8)
 #define HV_GUEST_CRASH_MSR_AVAILABLE(1u << 10)
+#define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11)
 #define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19)

+/*
+ * HV_CPUID_FEATURES.EBX bits
+ */
+#define HV_PARTITION_DEUBGGING_ALLOWED  (1u << 12)

s/DEUBGGING/DEBUGGING

Done

+
 /*
  * HV_CPUID_ENLIGHTMENT_INFO.EAX bits
  */
@@ -72,6 +81,11 @@
 #define HV_ENLIGHTENED_VMCS_RECOMMENDED (1u << 14)
 #define HV_NO_NONARCH_CORESHARING   (1u << 18)

+/*
+ * HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX bits
+ */
+#define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING(1u << 1)
+
 /*
  * Basic virtualized MSRs
  */
@@ -130,6 +144,18 @@
 #define HV_X64_MSR_STIMER3_CONFIG   0x40B6
 #define HV_X64_MSR_STIMER3_COUNT0x40B7

+/*
+ * Hyper-V Synthetic debug options MSR
+ */
+#define HV_X64_MSR_SYNDBG_CONTROL   0x40F1
+#define HV_X64_MSR_SYNDBG_STATUS0x40F2
+#define HV_X64_MSR_SYNDBG_SEND_BUFFER   0x40F3
+#define HV_X64_MSR_SYNDBG_RECV_BUFFER   0x40F4
+#define HV_X64_MSR_SYNDBG_PENDING_BUFFER0x40F5
+#define HV_X64_MSR_SYNDBG_OPTIONS   0x40FF
+
+#define HV_X64_SYNDBG_OPTION_USE_HCALLS 

Re: [PATCH v2 1/4] hyperv: SControl is optional to enable SynIc

2022-03-06 Thread Jon Doron
Thanks! is there an estimate when will this patchset be merged?

On Thu, Feb 24, 2022, 18:36 Emanuele Giuseppe Esposito 
wrote:

>
>
> On 16/02/2022 11:24, Jon Doron wrote:
> > SynIc can be enabled regardless of the SControl mechanisim which can
> > register a GSI for a given SintRoute.
> >
> > This behaviour can achived by setting enabling SIMP and then the guest
> > will poll on the message slot.
> >
> > Once there is another message pending the host will set the message slot
> > with the pending flag.
> > When the guest polls from the message slot, in case the pending flag is
> > set it will write to the HV_X64_MSR_EOM indicating it has cleared the
> > slot and we can try and push our message again.
> >
> > Signed-off-by: Jon Doron 
> > ---
> >  hw/hyperv/hyperv.c | 109 +++--
> >  1 file changed, 76 insertions(+), 33 deletions(-)
> >
> > diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
> > index cb1074f234..aaba6b4901 100644
> > --- a/hw/hyperv/hyperv.c
> > +++ b/hw/hyperv/hyperv.c
> > @@ -27,13 +27,16 @@ struct SynICState {
> >
> >  CPUState *cs;
> >
> > -bool enabled;
> > +bool sctl_enabled;
> >  hwaddr msg_page_addr;
> >  hwaddr event_page_addr;
> >  MemoryRegion msg_page_mr;
> >  MemoryRegion event_page_mr;
> >  struct hyperv_message_page *msg_page;
> >  struct hyperv_event_flags_page *event_page;
> > +
> > +QemuMutex sint_routes_mutex;
> > +QLIST_HEAD(, HvSintRoute) sint_routes;
> >  };
> >
> >  #define TYPE_SYNIC "hyperv-synic"
> > @@ -51,11 +54,11 @@ static SynICState *get_synic(CPUState *cs)
> >  return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
> >  }
> >
> > -static void synic_update(SynICState *synic, bool enable,
> > +static void synic_update(SynICState *synic, bool sctl_enable,
> >   hwaddr msg_page_addr, hwaddr event_page_addr)
> >  {
> >
> > -synic->enabled = enable;
> > +synic->sctl_enabled = sctl_enable;
> >  if (synic->msg_page_addr != msg_page_addr) {
> >  if (synic->msg_page_addr) {
> >  memory_region_del_subregion(get_system_memory(),
> > @@ -80,7 +83,7 @@ static void synic_update(SynICState *synic, bool
> enable,
> >  }
> >  }
> >
> > -void hyperv_synic_update(CPUState *cs, bool enable,
> > +void hyperv_synic_update(CPUState *cs, bool sctl_enable,
> >   hwaddr msg_page_addr, hwaddr event_page_addr)
> >  {
> >  SynICState *synic = get_synic(cs);
> > @@ -89,7 +92,7 @@ void hyperv_synic_update(CPUState *cs, bool enable,
> >  return;
> >  }
> >
> > -synic_update(synic, enable, msg_page_addr, event_page_addr);
> > +synic_update(synic, sctl_enable, msg_page_addr, event_page_addr);
> >  }
> >
> >  static void synic_realize(DeviceState *dev, Error **errp)
> > @@ -110,16 +113,20 @@ static void synic_realize(DeviceState *dev, Error
> **errp)
> > sizeof(*synic->event_page), &error_abort);
> >  synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr);
> >  synic->event_page =
> memory_region_get_ram_ptr(&synic->event_page_mr);
> > +qemu_mutex_init(&synic->sint_routes_mutex);
> > +QLIST_INIT(&synic->sint_routes);
> >
> >  g_free(msgp_name);
> >  g_free(eventp_name);
> >  }
> > +
> >  static void synic_reset(DeviceState *dev)
> >  {
> >  SynICState *synic = SYNIC(dev);
> >  memset(synic->msg_page, 0, sizeof(*synic->msg_page));
> >  memset(synic->event_page, 0, sizeof(*synic->event_page));
> >  synic_update(synic, false, 0, 0);
> > +assert(QLIST_EMPTY(&synic->sint_routes));
> >  }
> >
> >  static void synic_class_init(ObjectClass *klass, void *data)
> > @@ -214,6 +221,7 @@ struct HvSintRoute {
> >  HvSintStagedMessage *staged_msg;
> >
> >  unsigned refcount;
> > +QLIST_ENTRY(HvSintRoute) link;
> >  };
> >
> >  static CPUState *hyperv_find_vcpu(uint32_t vp_index)
> > @@ -259,7 +267,7 @@ static void cpu_post_msg(CPUState *cs,
> run_on_cpu_data data)
> >
> >  assert(staged_msg->state == HV_STAGED_MSG_BUSY);
> >
> > -if (!synic->enabled || !synic->msg_page_addr) {
> > +if (!synic->msg_page_addr) {
> >  staged_

[PATCH v3 2/4] hyperv: Add definitions for syndbg

2022-03-15 Thread Jon Doron
Add all required definitions for hyperv synthetic debugger interface.

Signed-off-by: Jon Doron 
---
 include/hw/hyperv/hyperv-proto.h | 52 
 target/i386/kvm/hyperv-proto.h   | 37 +++
 2 files changed, 89 insertions(+)

diff --git a/include/hw/hyperv/hyperv-proto.h b/include/hw/hyperv/hyperv-proto.h
index 21dc28aee9..4a2297307b 100644
--- a/include/hw/hyperv/hyperv-proto.h
+++ b/include/hw/hyperv/hyperv-proto.h
@@ -24,12 +24,17 @@
 #define HV_STATUS_INVALID_PORT_ID 17
 #define HV_STATUS_INVALID_CONNECTION_ID   18
 #define HV_STATUS_INSUFFICIENT_BUFFERS19
+#define HV_STATUS_NOT_ACKNOWLEDGED20
+#define HV_STATUS_NO_DATA 27
 
 /*
  * Hypercall numbers
  */
 #define HV_POST_MESSAGE   0x005c
 #define HV_SIGNAL_EVENT   0x005d
+#define HV_POST_DEBUG_DATA0x0069
+#define HV_RETRIEVE_DEBUG_DATA0x006a
+#define HV_RESET_DEBUG_SESSION0x006b
 #define HV_HYPERCALL_FAST (1u << 16)
 
 /*
@@ -127,4 +132,51 @@ struct hyperv_event_flags_page {
 struct hyperv_event_flags slot[HV_SINT_COUNT];
 };
 
+/*
+ * Kernel debugger structures
+ */
+
+/* Options flags for hyperv_reset_debug_session */
+#define HV_DEBUG_PURGE_INCOMING_DATA0x0001
+#define HV_DEBUG_PURGE_OUTGOING_DATA0x0002
+struct hyperv_reset_debug_session_input {
+uint32_t options;
+} __attribute__ ((__packed__));
+
+struct hyperv_reset_debug_session_output {
+uint32_t host_ip;
+uint32_t target_ip;
+uint16_t host_port;
+uint16_t target_port;
+uint8_t host_mac[6];
+uint8_t target_mac[6];
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_post_debug_data */
+#define HV_DEBUG_POST_LOOP  0x0001
+
+struct hyperv_post_debug_data_input {
+uint32_t count;
+uint32_t options;
+/*uint8_t data[HV_HYP_PAGE_SIZE - 2 * sizeof(uint32_t)];*/
+} __attribute__ ((__packed__));
+
+struct hyperv_post_debug_data_output {
+uint32_t pending_count;
+} __attribute__ ((__packed__));
+
+/* Options for hyperv_retrieve_debug_data */
+#define HV_DEBUG_RETRIEVE_LOOP  0x0001
+#define HV_DEBUG_RETRIEVE_TEST_ACTIVITY 0x0002
+
+struct hyperv_retrieve_debug_data_input {
+uint32_t count;
+uint32_t options;
+uint64_t timeout;
+} __attribute__ ((__packed__));
+
+struct hyperv_retrieve_debug_data_output {
+uint32_t retrieved_count;
+uint32_t remaining_count;
+} __attribute__ ((__packed__));
 #endif
diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h
index 89f81afda7..e40e59411c 100644
--- a/target/i386/kvm/hyperv-proto.h
+++ b/target/i386/kvm/hyperv-proto.h
@@ -19,6 +19,9 @@
 #define HV_CPUID_ENLIGHTMENT_INFO 0x4004
 #define HV_CPUID_IMPLEMENT_LIMITS 0x4005
 #define HV_CPUID_NESTED_FEATURES  0x400A
+#define HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS0x4080
+#define HV_CPUID_SYNDBG_INTERFACE   0x4081
+#define HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES   0x4082
 #define HV_CPUID_MIN  0x4005
 #define HV_CPUID_MAX  0x4000
 #define HV_HYPERVISOR_PRESENT_BIT 0x8000
@@ -55,8 +58,14 @@
 #define HV_GUEST_IDLE_STATE_AVAILABLE   (1u << 5)
 #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8)
 #define HV_GUEST_CRASH_MSR_AVAILABLE(1u << 10)
+#define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11)
 #define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19)
 
+/*
+ * HV_CPUID_FEATURES.EBX bits
+ */
+#define HV_PARTITION_DEBUGGING_ALLOWED  (1u << 12)
+
 /*
  * HV_CPUID_ENLIGHTMENT_INFO.EAX bits
  */
@@ -72,6 +81,11 @@
 #define HV_ENLIGHTENED_VMCS_RECOMMENDED (1u << 14)
 #define HV_NO_NONARCH_CORESHARING   (1u << 18)
 
+/*
+ * HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX bits
+ */
+#define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING(1u << 1)
+
 /*
  * Basic virtualized MSRs
  */
@@ -130,6 +144,18 @@
 #define HV_X64_MSR_STIMER3_CONFIG   0x40B6
 #define HV_X64_MSR_STIMER3_COUNT0x40B7
 
+/*
+ * Hyper-V Synthetic debug options MSR
+ */
+#define HV_X64_MSR_SYNDBG_CONTROL   0x40F1
+#define HV_X64_MSR_SYNDBG_STATUS0x40F2
+#define HV_X64_MSR_SYNDBG_SEND_BUFFER   0x40F3
+#define HV_X64_MSR_SYNDBG_RECV_BUFFER   0x40F4
+#define HV_X64_MSR_SYNDBG_PENDING_BUFFER0x40F5
+#define HV_X64_MSR_SYNDBG_OPTIONS   0x40FF
+
+#define HV_X64_SYNDBG_OPTION_USE_HCALLS BIT(2)
+
 /*
  * Guest crash notification MSRs
  */
@@ -168,5 +194,16 @@
 
 #define HV_STIMER_COUNT   4
 
+/*
+ * Synthetic debugger control definitions
+ */
+#define HV_SYNDBG_CONTROL_SEND  (1u << 

[PATCH v3 4/4] hw: hyperv: Initial commit for Synthetic Debugging device

2022-03-15 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 hw/hyperv/Kconfig |   5 +
 hw/hyperv/meson.build |   1 +
 hw/hyperv/syndbg.c| 402 ++
 3 files changed, 408 insertions(+)
 create mode 100644 hw/hyperv/syndbg.c

diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig
index 3fbfe41c9e..fcf65903bd 100644
--- a/hw/hyperv/Kconfig
+++ b/hw/hyperv/Kconfig
@@ -11,3 +11,8 @@ config VMBUS
 bool
 default y
 depends on HYPERV
+
+config SYNDBG
+bool
+default y
+depends on VMBUS
diff --git a/hw/hyperv/meson.build b/hw/hyperv/meson.build
index 1367e2994f..b43f119ea5 100644
--- a/hw/hyperv/meson.build
+++ b/hw/hyperv/meson.build
@@ -1,3 +1,4 @@
 specific_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'))
 specific_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true: 
files('hyperv_testdev.c'))
 specific_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c'))
+specific_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c'))
diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c
new file mode 100644
index 00..8816bc4082
--- /dev/null
+++ b/hw/hyperv/syndbg.c
@@ -0,0 +1,402 @@
+/*
+ * QEMU Hyper-V Synthetic Debugging device
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/ctype.h"
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+#include "qemu/sockets.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/loader.h"
+#include "cpu.h"
+#include "hw/hyperv/hyperv.h"
+#include "hw/hyperv/vmbus-bridge.h"
+#include "hw/hyperv/hyperv-proto.h"
+#include "net/net.h"
+#include "net/eth.h"
+#include "net/checksum.h"
+#include "trace.h"
+
+#define TYPE_HV_SYNDBG   "hv-syndbg"
+
+typedef struct HvSynDbg {
+DeviceState parent_obj;
+
+char *host_ip;
+uint16_t host_port;
+bool use_hcalls;
+
+uint32_t target_ip;
+struct sockaddr_in servaddr;
+int socket;
+bool has_data_pending;
+uint64_t pending_page_gpa;
+} HvSynDbg;
+
+#define HVSYNDBG(obj) OBJECT_CHECK(HvSynDbg, (obj), TYPE_HV_SYNDBG)
+
+/* returns NULL unless there is exactly one HV Synth debug device */
+static HvSynDbg *hv_syndbg_find(void)
+{
+/* Returns NULL unless there is exactly one hvsd device */
+return HVSYNDBG(object_resolve_path_type("", TYPE_HV_SYNDBG, NULL));
+}
+
+static void set_pending_state(HvSynDbg *syndbg, bool has_pending)
+{
+hwaddr out_len;
+void *out_data;
+
+syndbg->has_data_pending = has_pending;
+
+if (!syndbg->pending_page_gpa) {
+return;
+}
+
+out_len = 1;
+out_data = cpu_physical_memory_map(syndbg->pending_page_gpa, &out_len, 1);
+if (out_data) {
+*(uint8_t *)out_data = !!has_pending;
+cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
+}
+}
+
+static bool get_udb_pkt_data(void *p, uint32_t len, uint32_t *data_ofs,
+ uint32_t *src_ip)
+{
+uint32_t offset, curr_len = len;
+
+if (curr_len < sizeof(struct eth_header) ||
+(be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto) != ETH_P_IP)) {
+return false;
+}
+offset = sizeof(struct eth_header);
+curr_len -= sizeof(struct eth_header);
+
+if (curr_len < sizeof(struct ip_header) ||
+PKT_GET_IP_HDR(p)->ip_p != IP_PROTO_UDP) {
+return false;
+}
+offset += PKT_GET_IP_HDR_LEN(p);
+curr_len -= PKT_GET_IP_HDR_LEN(p);
+
+if (curr_len < sizeof(struct udp_header)) {
+return false;
+}
+
+offset += sizeof(struct udp_header);
+*data_ofs = offset;
+*src_ip = PKT_GET_IP_HDR(p)->ip_src;
+return true;
+}
+
+static uint16_t handle_send_msg(HvSynDbg *syndbg, uint64_t ingpa,
+uint32_t count, bool is_raw,
+uint32_t *pending_count)
+{
+uint16_t ret;
+hwaddr data_len;
+void *debug_data = NULL;
+uint32_t udp_data_ofs = 0;
+const void *pkt_data;
+int sent_count;
+
+data_len = count;
+debug_data = cpu_physical_memory_map(ingpa, &data_len, 0);
+if (!debug_data || data_len < count) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+if (is_raw &&
+!get_udb_pkt_data(debug_data, count, &udp_data_ofs,
+  &syndbg->target_ip)) {
+ret = HV_STATUS_SUCCESS;
+goto cleanup;
+}
+
+pkt_data = (const void *)((uintptr_t)debug_data + udp_data_ofs);
+sent_count = qemu_sendto(syndbg->socket, pkt_data, count - udp_data_ofs,
+   

[PATCH v3 0/4] HyperV: Synthetic Debugging device

2022-03-15 Thread Jon Doron
This patchset adds support for the synthetic debugging device.

HyperV supports a special transport layer for the kernel debugger when
running in HyperV.

This patchset add supports for this device so you could have a setup
fast windows kernel debugging.

At this point of time, DHCP is not implmeneted so to set this up few
things need to be noted.

The scenario I used to test is having 2 VMs in the same virtual network
i.e a Debugger VM with the NIC:
-nic tap,model=virtio,mac=02:ca:01:01:01:01,script=/etc/qemu-ifup
And it's IP is going to be static 192.168.53.12
And the VM we want to debug, to which we need to have the englightments
and vmbus configured:
 -cpu 
host,hv-relaxed,hv_spinlocks=0x1fff,hv_time,+vmx,invtsc,hv-vapic,hv-vpindex,hv-synic,hv-syndbg
 \
 -device vmbus-bridge \
 -device hv-syndbg,host_ip=192.168.53.12,host_port=5,use_hcalls=false \
 -nic tap,model=virtio,mac=02:ca:01:01:01:02,script=/etc/qemu-ifup \

Then in the debuggee VM we would setup the kernel debugging in the
following way:

If the VM is older than Win8:
* Copy the proper platform kdvm.dll (make sure it's called kdvm.dll even if 
platform is 32bit)
bcdedit /set {GUID} dbgtransport kdvm.dll
bcdedit /set {GUID} loadoptions host_ip="1.2.3.4",host_port="5",nodhcp
bcdedit /set {GUID} debug on
bcdedit /set {GUID} halbreakpoint on

Win8 and late:
bcdedit /dbgsettings net hostip:7.7.7.7 port:5 nodhcp

This is all the setup that is required to get the synthetic debugger
configured correctly.

v3:
Fixed review from Paolo changes from QLIST*RCU to non RCU

Jon Doron (4):
  hyperv: SControl is optional to enable SynIc
  hyperv: Add definitions for syndbg
  hyperv: Add support to process syndbg commands
  hw: hyperv: Initial commit for Synthetic Debugging device

 docs/hyperv.txt  |  15 ++
 hw/hyperv/Kconfig|   5 +
 hw/hyperv/hyperv.c   | 352 ---
 hw/hyperv/meson.build|   1 +
 hw/hyperv/syndbg.c   | 402 +++
 include/hw/hyperv/hyperv-proto.h |  52 
 include/hw/hyperv/hyperv.h   |  58 +
 target/i386/cpu.c|   2 +
 target/i386/cpu.h|   7 +
 target/i386/kvm/hyperv-proto.h   |  37 +++
 target/i386/kvm/hyperv-stub.c|   6 +
 target/i386/kvm/hyperv.c |  52 +++-
 target/i386/kvm/kvm.c|  76 +-
 13 files changed, 1024 insertions(+), 41 deletions(-)
 create mode 100644 hw/hyperv/syndbg.c

-- 
2.35.1




[PATCH v3 3/4] hyperv: Add support to process syndbg commands

2022-03-15 Thread Jon Doron
SynDbg commands can come from two different flows:
1. Hypercalls, in this mode the data being sent is fully
   encapsulated network packets.
2. SynDbg specific MSRs, in this mode only the data that needs to be
   transfered is passed.

Signed-off-by: Jon Doron 
---
 docs/hyperv.txt   |  15 +++
 hw/hyperv/hyperv.c| 243 ++
 include/hw/hyperv/hyperv.h|  58 
 target/i386/cpu.c |   2 +
 target/i386/cpu.h |   7 +
 target/i386/kvm/hyperv-stub.c |   6 +
 target/i386/kvm/hyperv.c  |  52 +++-
 target/i386/kvm/kvm.c |  76 ++-
 8 files changed, 451 insertions(+), 8 deletions(-)

diff --git a/docs/hyperv.txt b/docs/hyperv.txt
index 0417c183a3..33588a0396 100644
--- a/docs/hyperv.txt
+++ b/docs/hyperv.txt
@@ -225,6 +225,21 @@ default (WS2016).
 Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V
 identification when specified without any other enlightenments.
 
+3.21. hv-syndbg
+===
+Enables Hyper-V synthetic debugger interface, this is a special interface used
+by Windows Kernel debugger to send the packets through, rather than sending
+them via serial/network .
+When enabled, this enlightenment provides additional communication facilities
+to the guest: SynDbg messages.
+This new communication is used by Windows Kernel debugger rather than sending
+packets via serial/network, adding significant performance boost over the other
+comm channels.
+This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15)
+and the follow enlightenments to work:
+hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer
+
+
 4. Supplementary features
 =
 
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 8b832566c1..4a1b59cb9d 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -704,3 +704,246 @@ uint16_t hyperv_hcall_signal_event(uint64_t param, bool 
fast)
 }
 return HV_STATUS_INVALID_CONNECTION_ID;
 }
+
+static HvSynDbgHandler hv_syndbg_handler;
+static void *hv_syndbg_context;
+
+void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context)
+{
+assert(!hv_syndbg_handler);
+hv_syndbg_handler = handler;
+hv_syndbg_context = context;
+}
+
+uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa)
+{
+uint16_t ret;
+HvSynDbgMsg msg;
+struct hyperv_reset_debug_session_output *reset_dbg_session = NULL;
+hwaddr len;
+
+if (!hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+len = sizeof(*reset_dbg_session);
+reset_dbg_session = cpu_physical_memory_map(outgpa, &len, 1);
+if (!reset_dbg_session || len < sizeof(*reset_dbg_session)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_CONNECTION_INFO;
+ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+if (ret) {
+goto cleanup;
+}
+
+reset_dbg_session->host_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->host_port = msg.u.connection_info.host_port;
+/* The following fields are only used as validation for KDVM */
+memset(&reset_dbg_session->host_mac, 0,
+   sizeof(reset_dbg_session->host_mac));
+reset_dbg_session->target_ip = msg.u.connection_info.host_ip;
+reset_dbg_session->target_port = msg.u.connection_info.host_port;
+memset(&reset_dbg_session->target_mac, 0,
+   sizeof(reset_dbg_session->target_mac));
+cleanup:
+if (reset_dbg_session) {
+cpu_physical_memory_unmap(reset_dbg_session,
+  sizeof(*reset_dbg_session), 1, len);
+}
+
+return ret;
+}
+
+uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa,
+bool fast)
+{
+uint16_t ret;
+struct hyperv_retrieve_debug_data_input *debug_data_in = NULL;
+struct hyperv_retrieve_debug_data_output *debug_data_out = NULL;
+hwaddr in_len, out_len;
+HvSynDbgMsg msg;
+
+if (fast || !hv_syndbg_handler) {
+ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+goto cleanup;
+}
+
+in_len = sizeof(*debug_data_in);
+debug_data_in = cpu_physical_memory_map(ingpa, &in_len, 0);
+if (!debug_data_in || in_len < sizeof(*debug_data_in)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+out_len = sizeof(*debug_data_out);
+debug_data_out = cpu_physical_memory_map(outgpa, &out_len, 1);
+if (!debug_data_out || out_len < sizeof(*debug_data_out)) {
+ret = HV_STATUS_INSUFFICIENT_MEMORY;
+goto cleanup;
+}
+
+msg.type = HV_SYNDBG_MSG_RECV;
+msg.u.recv.buf_gpa = outgpa + sizeof(*debug_data_out);
+msg.u.recv.count = TARGET_PAGE_SIZE - sizeof(*debug_data_out);
+msg.u.recv.options = debug_data_in->options;
+msg.u.recv.timeout 

[PATCH v3 1/4] hyperv: SControl is optional to enable SynIc

2022-03-15 Thread Jon Doron
SynIc can be enabled regardless of the SControl mechanisim which can
register a GSI for a given SintRoute.

This behaviour can achived by setting enabling SIMP and then the guest
will poll on the message slot.

Once there is another message pending the host will set the message slot
with the pending flag.
When the guest polls from the message slot, in case the pending flag is
set it will write to the HV_X64_MSR_EOM indicating it has cleared the
slot and we can try and push our message again.

Signed-off-by: Jon Doron 
---
 hw/hyperv/hyperv.c | 109 +++--
 1 file changed, 76 insertions(+), 33 deletions(-)

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index cb1074f234..8b832566c1 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -27,13 +27,16 @@ struct SynICState {
 
 CPUState *cs;
 
-bool enabled;
+bool sctl_enabled;
 hwaddr msg_page_addr;
 hwaddr event_page_addr;
 MemoryRegion msg_page_mr;
 MemoryRegion event_page_mr;
 struct hyperv_message_page *msg_page;
 struct hyperv_event_flags_page *event_page;
+
+QemuMutex sint_routes_mutex;
+QLIST_HEAD(, HvSintRoute) sint_routes;
 };
 
 #define TYPE_SYNIC "hyperv-synic"
@@ -51,11 +54,11 @@ static SynICState *get_synic(CPUState *cs)
 return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
 }
 
-static void synic_update(SynICState *synic, bool enable,
+static void synic_update(SynICState *synic, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 
-synic->enabled = enable;
+synic->sctl_enabled = sctl_enable;
 if (synic->msg_page_addr != msg_page_addr) {
 if (synic->msg_page_addr) {
 memory_region_del_subregion(get_system_memory(),
@@ -80,7 +83,7 @@ static void synic_update(SynICState *synic, bool enable,
 }
 }
 
-void hyperv_synic_update(CPUState *cs, bool enable,
+void hyperv_synic_update(CPUState *cs, bool sctl_enable,
  hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 SynICState *synic = get_synic(cs);
@@ -89,7 +92,7 @@ void hyperv_synic_update(CPUState *cs, bool enable,
 return;
 }
 
-synic_update(synic, enable, msg_page_addr, event_page_addr);
+synic_update(synic, sctl_enable, msg_page_addr, event_page_addr);
 }
 
 static void synic_realize(DeviceState *dev, Error **errp)
@@ -110,16 +113,20 @@ static void synic_realize(DeviceState *dev, Error **errp)
sizeof(*synic->event_page), &error_abort);
 synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr);
 synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr);
+qemu_mutex_init(&synic->sint_routes_mutex);
+QLIST_INIT(&synic->sint_routes);
 
 g_free(msgp_name);
 g_free(eventp_name);
 }
+
 static void synic_reset(DeviceState *dev)
 {
 SynICState *synic = SYNIC(dev);
 memset(synic->msg_page, 0, sizeof(*synic->msg_page));
 memset(synic->event_page, 0, sizeof(*synic->event_page));
 synic_update(synic, false, 0, 0);
+assert(QLIST_EMPTY(&synic->sint_routes));
 }
 
 static void synic_class_init(ObjectClass *klass, void *data)
@@ -214,6 +221,7 @@ struct HvSintRoute {
 HvSintStagedMessage *staged_msg;
 
 unsigned refcount;
+QLIST_ENTRY(HvSintRoute) link;
 };
 
 static CPUState *hyperv_find_vcpu(uint32_t vp_index)
@@ -259,7 +267,7 @@ static void cpu_post_msg(CPUState *cs, run_on_cpu_data data)
 
 assert(staged_msg->state == HV_STAGED_MSG_BUSY);
 
-if (!synic->enabled || !synic->msg_page_addr) {
+if (!synic->msg_page_addr) {
 staged_msg->status = -ENXIO;
 goto posted;
 }
@@ -343,7 +351,7 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned 
eventno)
 if (eventno > HV_EVENT_FLAGS_COUNT) {
 return -EINVAL;
 }
-if (!synic->enabled || !synic->event_page_addr) {
+if (!synic->sctl_enabled || !synic->event_page_addr) {
 return -ENXIO;
 }
 
@@ -364,11 +372,12 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, 
unsigned eventno)
 HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
HvSintMsgCb cb, void *cb_data)
 {
-HvSintRoute *sint_route;
-EventNotifier *ack_notifier;
+HvSintRoute *sint_route = NULL;
+EventNotifier *ack_notifier = NULL;
 int r, gsi;
 CPUState *cs;
 SynICState *synic;
+bool ack_event_initialized = false;
 
 cs = hyperv_find_vcpu(vp_index);
 if (!cs) {
@@ -381,57 +390,77 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, 
uint32_t sint,
 }
 
 sint_route = g_new0(HvSintRoute, 1);
-r = event_notifier_init(&sint_route->sint_set_notifier, false);
-if (r) {
-goto err;
+if (!sint_route) {
+return NULL;
 }
 
+sint_route->synic = 

Re: Concerns regarding e17bebd049 ("dump: Set correct vaddr for ELF dump")

2023-09-20 Thread Jon Doron

Hi Stephen,

Like you have said the reason is as I wrote in the commit message, 
without "fixing" the vaddr GDB is messing up mapping and working with 
the generated core file.


This patch is almost 4 years old, perhaps some changes to GDB has been 
introduced to resolve this, I have not checked since then.


As I'm no longer using this feature and have not worked and tested it 
in a long while, so I have no obligations to this change, but perhaps

someone else might be using it...

-- Jon.

On 19/09/2023, Stephen Brennan wrote:

Hello all,

I've started working on better support and documentation around
hypervisor vmcores in the Drgn debugger[1]. Of course there's quite a
lot of different implementations out there, but recently I'm looking at
Qemu kdump and ELF vmcores generated via dump-guest-memory, and one
thing caught my eye. I generated a ELF vmcore without the paging option
enabled, and without the guest note loaded, and the resulting core
dump's program header looked like this:

$ eu-readelf -l dumpfile2
Program Headers:
 Type   Offset   VirtAddr   PhysAddr   FileSiz  MemSiz  
 Flg Align
 NOTE   0x000168 0x 0x 0x001980 
0x001980 0x0
 LOAD   0x001ae8 0x 0x 0x8000 
0x8000 0x0
 LOAD   0x80001ae8 0xfffc 0xfffc 0x04 
0x04 0x0

In particular, the "VirtAddr" field for the loadable segment shows a
confusing address - it appears to reuse the segment's physical address,
despite the fact that there's no actual corresponding mapping.

By comparison, the /proc/kcore and /proc/vmcore ELF vmcores use the
VirtAddr in the program header to represent the real virtual memory
mappings in use by the kernel. Debuggers can directly use these without
needing to walk page tables. If there is no virtual memory mapping
information available, I would have expected a placeholder value such as
... or ... to take the place of VirtAddr here so a debugger can
detect the lack of virtual mappings and know that it needs to use
architecture-specific details (and the vmcoreinfo) to find the page
tables and accurately determine memory mappings. As it is, this program
header seems to advertise to a debugger, "yes, we have the virtual
memory mappings" when in fact, that's not the case.

It seems that this behavior was introduced in e17bebd049 ("dump: Set
correct vaddr for ELF dump")[2], a small commit I'll reproduce below.
The justification seems to be that it fixes an issue reading the vmcore
with GDB, but I wonder if that's not a GDB bug which should have been
fixed with them? If GDB aims to support ELF kernel core dumps,
presumably it should be handling physical addresses separately from
virtual addresses. And if GDB doesn't aim for this, but you'd like to
con it into reading your core dump, presumably the onus is on you to
edit the ELF VirtAddr field to suit your needs? It should be QEMU's
primary goal to produce a *correct* vmcore, not work around limitations
or bugs in GDB.

I'd like to propose reverting this, since it makes it impossible to
interpret QEMU ELF vmcores, unless you discard all the virtual addresses
in the program headers, and unconditionally do all the page table walks
yourself. But I wanted to see if there was some justification for this
behavior that I missed.

Thanks,
Stephen

[1]: https://github.com/osandov/drgn
[2]: https://lore.kernel.org/qemu-devel/20181225125344.4482-1-ari...@gmail.com/

---

commit e17bebd049d78f489c2cff755e2b66a0536a156e
Author: Jon Doron 
Date:   Wed Jan 9 10:22:03 2019 +0200

   dump: Set correct vaddr for ELF dump

   vaddr needs to be equal to the paddr since the dump file represents the
   physical memory image.

   Without setting vaddr correctly, GDB would load all the different memory
   regions on top of each other to vaddr 0, thus making GDB showing the wrong
   memory data for a given address.

   Signed-off-by: Jon Doron 
   Message-Id: <20190109082203.27142-1-ari...@gmail.com>
   Reviewed-by: Marc-André Lureau 
   Tested-by: Marc-André Lureau 
   Acked-by: Laszlo Ersek 

diff --git a/dump.c b/dump.c
index ef1d8025c9..107a67165a 100644
--- a/dump.c
+++ b/dump.c
@@ -192,7 +192,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping 
*memory_mapping,
phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
phdr.p_filesz = cpu_to_dump64(s, filesz);
phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
-phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr);
+phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr) ?: phdr.p_paddr;

assert(memory_mapping->length >= filesz);

@@ -216,7 +216,8 @@ static void write_elf32_load(DumpState *s, MemoryMapping 
*memory_mapping,
phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
p

[Qemu-devel] [PATCH v1] dump: Set correct vaddr for ELF dump

2018-12-25 Thread Jon Doron
vaddr needs to be equal to the paddr since the dump file represents the
physical memory image.

Without setting vaddr correctly, GDB would load all the different memory
regions on top of each other to vaddr 0, thus making GDB showing the wrong
memory data for a given address.

Signed-off-by: Jon Doron 
---
 dump.c   | 4 ++--
 scripts/dump-guest-memory.py | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/dump.c b/dump.c
index 4ec94c5e25..bf77a119ea 100644
--- a/dump.c
+++ b/dump.c
@@ -192,7 +192,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping 
*memory_mapping,
 phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
 phdr.p_filesz = cpu_to_dump64(s, filesz);
 phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
-phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr);
+phdr.p_vaddr = phdr.p_paddr;
 
 assert(memory_mapping->length >= filesz);
 
@@ -216,7 +216,7 @@ static void write_elf32_load(DumpState *s, MemoryMapping 
*memory_mapping,
 phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
 phdr.p_filesz = cpu_to_dump32(s, filesz);
 phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length);
-phdr.p_vaddr = cpu_to_dump32(s, memory_mapping->virt_addr);
+phdr.p_vaddr = phdr.p_paddr;
 
 assert(memory_mapping->length >= filesz);
 
diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py
index 198cd0fe40..2c587cbefc 100644
--- a/scripts/dump-guest-memory.py
+++ b/scripts/dump-guest-memory.py
@@ -163,6 +163,7 @@ class ELF(object):
 phdr = get_arch_phdr(self.endianness, self.elfclass)
 phdr.p_type = p_type
 phdr.p_paddr = p_paddr
+phdr.p_vaddr = p_paddr
 phdr.p_filesz = p_size
 phdr.p_memsz = p_size
 self.segments.append(phdr)
-- 
2.19.2




Re: [Qemu-devel] [PATCH v1] dump: Set correct vaddr for ELF dump

2019-01-07 Thread Jon Doron
Thank you for looking into this, perhaps I could change the patch (at
least in the C part not the python script) to something like:
-phdr.p_vaddr = cpu_to_dumpXX(s, memory_mapping->virt_addr);
+phdr.p_vaddr = cpu_to_dumpXX(s, memory_mapping->virt_addr) ?
cpu_to_dumpXX(s, memory_mapping->virt_addr) : phdr.p_paddr;

So in the case of paging where virt_addr is available we will use it

Thanks,
-- Jon.

On Mon, Jan 7, 2019 at 8:04 PM Laszlo Ersek  wrote:
>
> On 01/07/19 13:14, Marc-André Lureau wrote:
> > Hi
> >
> > On Tue, Dec 25, 2018 at 5:52 PM Jon Doron  wrote:
> >>
> >> vaddr needs to be equal to the paddr since the dump file represents the
> >> physical memory image.
> >>
> >> Without setting vaddr correctly, GDB would load all the different memory
> >> regions on top of each other to vaddr 0, thus making GDB showing the wrong
> >> memory data for a given address.
> >>
> >> Signed-off-by: Jon Doron 
> >
> > This is a non-trivial patch! (qemu-trivial, please ignore).
> >
> >> ---
> >>  dump.c   | 4 ++--
> >>  scripts/dump-guest-memory.py | 1 +
> >>  2 files changed, 3 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/dump.c b/dump.c
> >> index 4ec94c5e25..bf77a119ea 100644
> >> --- a/dump.c
> >> +++ b/dump.c
> >> @@ -192,7 +192,7 @@ static void write_elf64_load(DumpState *s, 
> >> MemoryMapping *memory_mapping,
> >>  phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
> >>  phdr.p_filesz = cpu_to_dump64(s, filesz);
> >>  phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
> >> -phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr);
> >> +phdr.p_vaddr = phdr.p_paddr;
> >
> > This is likely breaking paging=true somehow, which sets
> > memory_mapping->virt_addr to non-0.
> >
> > According to doc "If you want to use gdb to process the core, please
> > set @paging to true."
> >
> > Although I am not able to (gdb) x/10bx 0xa for example on a core
> > produced with paging. Not sure why, anybody could help?
> >
> >>  assert(memory_mapping->length >= filesz);
> >>
> >> @@ -216,7 +216,7 @@ static void write_elf32_load(DumpState *s, 
> >> MemoryMapping *memory_mapping,
> >>  phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
> >>  phdr.p_filesz = cpu_to_dump32(s, filesz);
> >>  phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length);
> >> -phdr.p_vaddr = cpu_to_dump32(s, memory_mapping->virt_addr);
> >> +phdr.p_vaddr = phdr.p_paddr;
> >>
> >>  assert(memory_mapping->length >= filesz);
> >>
> >> diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py
> >> index 198cd0fe40..2c587cbefc 100644
> >> --- a/scripts/dump-guest-memory.py
> >> +++ b/scripts/dump-guest-memory.py
> >> @@ -163,6 +163,7 @@ class ELF(object):
> >>  phdr = get_arch_phdr(self.endianness, self.elfclass)
> >>  phdr.p_type = p_type
> >>  phdr.p_paddr = p_paddr
> >> +phdr.p_vaddr = p_paddr
> >
> > With your proposed change though, I can dump memory with gdb...
> >
> >>  phdr.p_filesz = p_size
> >>  phdr.p_memsz = p_size
> >>  self.segments.append(phdr)
> >> --
> >> 2.19.2
> >>
> >>
> >
> >
>
> I've never used paging-enabled dumps. First, because doing so requires
> QEMU to trust guest memory contents (see original commit 783e9b4826b9;
> or more recently/generally, the @dump-guest-memory docs in
> "qapi/misc.json"). Second, because whenever I had to deal with guest
> memory dumps, I always used "crash" (which needs no paging), and the
> subject guests were all Linux.
>
> I can't comment on paging-enabled patches for dump, except that they
> shouldn't regress the paging-disabled functionality. :) If the patches
> satisfy that, I'm fine.
>
> (I *am* surprised that GDB insists on p_vaddr equaling p_paddr; after
> all, in the guest, the virtual address is "memory_mapping->virt_addr".
> But, I would never claim to understand most of the ELF intricacies,
> and/or what GDB requires on top of those.)
>
> Thanks
> Laszlo



[Qemu-devel] [PATCH v2] dump: Set correct vaddr for ELF dump

2019-01-08 Thread Jon Doron
vaddr needs to be equal to the paddr since the dump file represents the
physical memory image.

Without setting vaddr correctly, GDB would load all the different memory
regions on top of each other to vaddr 0, thus making GDB showing the wrong
memory data for a given address.

Signed-off-by: Jon Doron 
---
 dump.c   | 5 +++--
 scripts/dump-guest-memory.py | 1 +
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/dump.c b/dump.c
index 4ec94c5e25..7a56e254d4 100644
--- a/dump.c
+++ b/dump.c
@@ -192,7 +192,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping 
*memory_mapping,
 phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
 phdr.p_filesz = cpu_to_dump64(s, filesz);
 phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
-phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr);
+phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr) ? : 
phdr.p_paddr;
 
 assert(memory_mapping->length >= filesz);
 
@@ -216,7 +216,8 @@ static void write_elf32_load(DumpState *s, MemoryMapping 
*memory_mapping,
 phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
 phdr.p_filesz = cpu_to_dump32(s, filesz);
 phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length);
-phdr.p_vaddr = cpu_to_dump32(s, memory_mapping->virt_addr);
+phdr.p_vaddr =
+   cpu_to_dump32(s, memory_mapping->virt_addr) ? : phdr.p_paddr;
 
 assert(memory_mapping->length >= filesz);
 
diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py
index 198cd0fe40..2c587cbefc 100644
--- a/scripts/dump-guest-memory.py
+++ b/scripts/dump-guest-memory.py
@@ -163,6 +163,7 @@ class ELF(object):
 phdr = get_arch_phdr(self.endianness, self.elfclass)
 phdr.p_type = p_type
 phdr.p_paddr = p_paddr
+phdr.p_vaddr = p_paddr
 phdr.p_filesz = p_size
 phdr.p_memsz = p_size
 self.segments.append(phdr)
-- 
2.19.2




[Qemu-devel] [PATCH v3] dump: Set correct vaddr for ELF dump

2019-01-09 Thread Jon Doron
vaddr needs to be equal to the paddr since the dump file represents the
physical memory image.

Without setting vaddr correctly, GDB would load all the different memory
regions on top of each other to vaddr 0, thus making GDB showing the wrong
memory data for a given address.

Signed-off-by: Jon Doron 
---
 dump.c   | 5 +++--
 scripts/dump-guest-memory.py | 1 +
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/dump.c b/dump.c
index 4ec94c5e25..de7f70f099 100644
--- a/dump.c
+++ b/dump.c
@@ -192,7 +192,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping 
*memory_mapping,
 phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
 phdr.p_filesz = cpu_to_dump64(s, filesz);
 phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
-phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr);
+phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr) ? : 
phdr.p_paddr;
 
 assert(memory_mapping->length >= filesz);
 
@@ -216,7 +216,8 @@ static void write_elf32_load(DumpState *s, MemoryMapping 
*memory_mapping,
 phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
 phdr.p_filesz = cpu_to_dump32(s, filesz);
 phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length);
-phdr.p_vaddr = cpu_to_dump32(s, memory_mapping->virt_addr);
+phdr.p_vaddr =
+cpu_to_dump32(s, memory_mapping->virt_addr) ? : phdr.p_paddr;
 
 assert(memory_mapping->length >= filesz);
 
diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py
index 198cd0fe40..2c587cbefc 100644
--- a/scripts/dump-guest-memory.py
+++ b/scripts/dump-guest-memory.py
@@ -163,6 +163,7 @@ class ELF(object):
 phdr = get_arch_phdr(self.endianness, self.elfclass)
 phdr.p_type = p_type
 phdr.p_paddr = p_paddr
+phdr.p_vaddr = p_paddr
 phdr.p_filesz = p_size
 phdr.p_memsz = p_size
 self.segments.append(phdr)
-- 
2.19.2




[PATCH v4 1/6] hyperv: expose API to determine if synic is enabled

2020-04-24 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 hw/hyperv/hyperv.c | 8 
 include/hw/hyperv/hyperv.h | 1 +
 2 files changed, 9 insertions(+)

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 8ca3706f5b..ddf4f32c60 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -37,6 +37,13 @@ typedef struct SynICState {
 #define TYPE_SYNIC "hyperv-synic"
 #define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC)
 
+static bool synic_enabled;
+
+bool hyperv_is_synic_enabled(void)
+{
+return synic_enabled;
+}
+
 static SynICState *get_synic(CPUState *cs)
 {
 return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
@@ -133,6 +140,7 @@ void hyperv_synic_add(CPUState *cs)
 object_property_add_child(OBJECT(cs), "synic", obj, &error_abort);
 object_unref(obj);
 object_property_set_bool(obj, true, "realized", &error_abort);
+synic_enabled = true;
 }
 
 void hyperv_synic_reset(CPUState *cs)
diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h
index 597381cb01..a63ee0003c 100644
--- a/include/hw/hyperv/hyperv.h
+++ b/include/hw/hyperv/hyperv.h
@@ -79,5 +79,6 @@ void hyperv_synic_add(CPUState *cs);
 void hyperv_synic_reset(CPUState *cs);
 void hyperv_synic_update(CPUState *cs, bool enable,
  hwaddr msg_page_addr, hwaddr event_page_addr);
+bool hyperv_is_synic_enabled(void);
 
 #endif
-- 
2.24.1




[PATCH v4 5/6] i386: Hyper-V VMBus ACPI DSDT entry

2020-04-24 Thread Jon Doron
Guest OS uses ACPI to discover VMBus presence.  Add a corresponding
entry to DSDT in case VMBus has been enabled.

Experimentally Windows guests were found to require this entry to
include two IRQ resources. They seem to never be used but they still
have to be there.

Make IRQ numbers user-configurable via corresponding properties; use 7
and 13 by default.

Signed-off-by: Evgeny Yakovlev 
Signed-off-by: Roman Kagan 
Signed-off-by: Maciej S. Szmigiero 
Signed-off-by: Jon Doron 
---
 hw/hyperv/vmbus.c|  7 ++
 hw/i386/acpi-build.c | 43 
 include/hw/hyperv/vmbus-bridge.h |  3 +++
 3 files changed, 53 insertions(+)

diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
index 1f5873ab60..0df7afe0ca 100644
--- a/hw/hyperv/vmbus.c
+++ b/hw/hyperv/vmbus.c
@@ -2641,6 +2641,12 @@ static const VMStateDescription vmstate_vmbus_bridge = {
 },
 };
 
+static Property vmbus_bridge_props[] = {
+DEFINE_PROP_UINT8("irq0", VMBusBridge, irq0, 7),
+DEFINE_PROP_UINT8("irq1", VMBusBridge, irq1, 13),
+DEFINE_PROP_END_OF_LIST()
+};
+
 static void vmbus_bridge_class_init(ObjectClass *klass, void *data)
 {
 DeviceClass *k = DEVICE_CLASS(klass);
@@ -2651,6 +2657,7 @@ static void vmbus_bridge_class_init(ObjectClass *klass, 
void *data)
 sk->explicit_ofw_unit_address = vmbus_bridge_ofw_unit_address;
 set_bit(DEVICE_CATEGORY_BRIDGE, k->categories);
 k->vmsd = &vmstate_vmbus_bridge;
+device_class_set_props(k, vmbus_bridge_props);
 /* override SysBusDevice's default */
 k->user_creatable = true;
 }
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 2a7e55bae7..d235074fb8 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -50,6 +50,7 @@
 #include "hw/mem/nvdimm.h"
 #include "sysemu/numa.h"
 #include "sysemu/reset.h"
+#include "hw/hyperv/vmbus-bridge.h"
 
 /* Supported chipsets: */
 #include "hw/southbridge/piix.h"
@@ -1270,9 +1271,47 @@ static Aml *build_com_device_aml(uint8_t uid)
 return dev;
 }
 
+static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge)
+{
+Aml *dev;
+Aml *method;
+Aml *crs;
+
+dev = aml_device("VMBS");
+aml_append(dev, aml_name_decl("STA", aml_int(0xF)));
+aml_append(dev, aml_name_decl("_HID", aml_string("VMBus")));
+aml_append(dev, aml_name_decl("_UID", aml_int(0x0)));
+aml_append(dev, aml_name_decl("_DDN", aml_string("VMBUS")));
+
+method = aml_method("_DIS", 0, AML_NOTSERIALIZED);
+aml_append(method, aml_store(aml_and(aml_name("STA"), aml_int(0xD), NULL),
+ aml_name("STA")));
+aml_append(dev, method);
+
+method = aml_method("_PS0", 0, AML_NOTSERIALIZED);
+aml_append(method, aml_store(aml_or(aml_name("STA"), aml_int(0xF), NULL),
+ aml_name("STA")));
+aml_append(dev, method);
+
+method = aml_method("_STA", 0, AML_NOTSERIALIZED);
+aml_append(method, aml_return(aml_name("STA")));
+aml_append(dev, method);
+
+aml_append(dev, aml_name_decl("_PS3", aml_int(0x0)));
+
+crs = aml_resource_template();
+aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq0));
+/* FIXME: newer HyperV gets by with only one IRQ */
+aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq1));
+aml_append(dev, aml_name_decl("_CRS", crs));
+
+return dev;
+}
+
 static void build_isa_devices_aml(Aml *table)
 {
 ISADevice *fdc = pc_find_fdc0();
+VMBusBridge *vmbus_bridge = vmbus_bridge_find();
 bool ambiguous;
 
 Aml *scope = aml_scope("_SB.PCI0.ISA");
@@ -1296,6 +1335,10 @@ static void build_isa_devices_aml(Aml *table)
 build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
 }
 
+if (vmbus_bridge) {
+aml_append(scope, build_vmbus_device_aml(vmbus_bridge));
+}
+
 aml_append(table, scope);
 }
 
diff --git a/include/hw/hyperv/vmbus-bridge.h b/include/hw/hyperv/vmbus-bridge.h
index 9cc8f780de..c0a06d832c 100644
--- a/include/hw/hyperv/vmbus-bridge.h
+++ b/include/hw/hyperv/vmbus-bridge.h
@@ -19,6 +19,9 @@ typedef struct VMBus VMBus;
 typedef struct VMBusBridge {
 SysBusDevice parent_obj;
 
+uint8_t irq0;
+uint8_t irq1;
+
 VMBus *bus;
 } VMBusBridge;
 
-- 
2.24.1




[PATCH v4 0/6] hyperv: VMBus implementation

2020-04-24 Thread Jon Doron
This is a rebase of the old patchset from Roman for HyperV VMBus
implementation.

How to use:
-device vmbus-bridge

Later on new paravirtualized devices can be implemented on top of it
(Network/SCSI/etc.)

VMBus is a collection of technologies.  At its lowest layer, it's a message
passing and signaling mechanism, allowing efficient passing of messages to and
from guest VMs.  A layer higher, it's a mechanism for defining channels of
communication, where each channel is tagged with a type (which implies a
protocol) and a instance ID.  A layer higher than that, it's a bus driver,
serving as the basis of device enumeration within a VM, where a channel can
optionally be exposed as a paravirtual device.  When a server-side (paravirtual
back-end) component wishes to offer a channel to a guest VM, it does so by
specifying a channel type, a mode, and an instance ID.  VMBus then exposes this
in the guest.

More information about VMBus can be found in the file
vmbuskernelmodeclientlibapi.h in Microsoft's WDK.

v4:
Decided to ditch the patch that envolves handling of EOM as there is
still a discussion going on with it in the KVM mailing list.

v3:
Fixed an error asan

v2:
Rebased on top of latest patchset from Roman and Maciej

Jon Doron (6):
  hyperv: expose API to determine if synic is enabled
  vmbus: add vmbus protocol definitions
  vmbus: vmbus implementation
  i386:pc: whitelist dynamic vmbus-bridge
  i386: Hyper-V VMBus ACPI DSDT entry
  vmbus: add infrastructure to save/load vmbus requests

 Makefile.objs|1 +
 hw/hyperv/Kconfig|5 +
 hw/hyperv/Makefile.objs  |1 +
 hw/hyperv/hyperv.c   |8 +
 hw/hyperv/trace-events   |   18 +
 hw/hyperv/vmbus.c| 2778 ++
 hw/i386/acpi-build.c |   43 +
 hw/i386/pc_piix.c|2 +
 hw/i386/pc_q35.c |2 +
 include/hw/hyperv/hyperv.h   |1 +
 include/hw/hyperv/vmbus-bridge.h |   35 +
 include/hw/hyperv/vmbus-proto.h  |  222 +++
 include/hw/hyperv/vmbus.h|  230 +++
 13 files changed, 3346 insertions(+)
 create mode 100644 hw/hyperv/trace-events
 create mode 100644 hw/hyperv/vmbus.c
 create mode 100644 include/hw/hyperv/vmbus-bridge.h
 create mode 100644 include/hw/hyperv/vmbus-proto.h
 create mode 100644 include/hw/hyperv/vmbus.h

-- 
2.24.1




[PATCH v4 4/6] i386:pc: whitelist dynamic vmbus-bridge

2020-04-24 Thread Jon Doron
As vmbus-bridge is derived from sysbus device, it has to be whitelisted
to be allowed to be created with -device.

Signed-off-by: Roman Kagan 
Signed-off-by: Maciej S. Szmigiero 
Signed-off-by: Jon Doron 
---
 hw/i386/pc_piix.c | 2 ++
 hw/i386/pc_q35.c  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9cceae3e2c..6daa0770fa 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -60,6 +60,7 @@
 #include "migration/global_state.h"
 #include "migration/misc.h"
 #include "sysemu/numa.h"
+#include "hw/hyperv/vmbus-bridge.h"
 #include "hw/mem/nvdimm.h"
 
 #define MAX_IDE_BUS 2
@@ -417,6 +418,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
 m->default_machine_opts = "firmware=bios-256k.bin";
 m->default_display = "std";
 machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
+machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
 }
 
 static void pc_i440fx_5_0_machine_options(MachineClass *m)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index d37c425e22..faaa39ced2 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -53,6 +53,7 @@
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "sysemu/numa.h"
+#include "hw/hyperv/vmbus-bridge.h"
 #include "hw/mem/nvdimm.h"
 
 /* ICH9 AHCI has 6 ports */
@@ -346,6 +347,7 @@ static void pc_q35_machine_options(MachineClass *m)
 machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE);
 machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE);
 machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
+machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
 m->max_cpus = 288;
 }
 
-- 
2.24.1




[PATCH v4 3/6] vmbus: vmbus implementation

2020-04-24 Thread Jon Doron
Add the VMBus infrastructure -- bus, devices, root bridge, vmbus state
machine, vmbus channel interactions, etc.

VMBus is a collection of technologies.  At its lowest layer, it's a message
passing and signaling mechanism, allowing efficient passing of messages to and
from guest VMs.  A layer higher, it's a mechanism for defining channels of
communication, where each channel is tagged with a type (which implies a
protocol) and a instance ID.  A layer higher than that, it's a bus driver,
serving as the basis of device enumeration within a VM, where a channel can
optionally be exposed as a paravirtual device.  When a server-side (paravirtual
back-end) component wishes to offer a channel to a guest VM, it does so by
specifying a channel type, a mode, and an instance ID.  VMBus then exposes this
in the guest.

More information about VMBus can be found in the file
vmbuskernelmodeclientlibapi.h in Microsoft's WDK.

TODO:
 - split into smaller palatable pieces
 - more comments
 - check and handle corner cases

Kudos to Evgeny Yakovlev (formerly eyakov...@virtuozzo.com) and Andrey
Smetatin (formerly asmeta...@virtuozzo.com) for research and
prototyping.

Signed-off-by: Roman Kagan 
Signed-off-by: Maciej S. Szmigiero 
Signed-off-by: Jon Doron 
---
 Makefile.objs|1 +
 hw/hyperv/Kconfig|5 +
 hw/hyperv/Makefile.objs  |1 +
 hw/hyperv/trace-events   |   18 +
 hw/hyperv/vmbus.c| 2672 ++
 include/hw/hyperv/vmbus-bridge.h |   32 +
 include/hw/hyperv/vmbus.h|  227 +++
 7 files changed, 2956 insertions(+)
 create mode 100644 hw/hyperv/trace-events
 create mode 100644 hw/hyperv/vmbus.c
 create mode 100644 include/hw/hyperv/vmbus-bridge.h
 create mode 100644 include/hw/hyperv/vmbus.h

diff --git a/Makefile.objs b/Makefile.objs
index a7c967633a..1ef80ce58f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -151,6 +151,7 @@ trace-events-subdirs += hw/block/dataplane
 trace-events-subdirs += hw/char
 trace-events-subdirs += hw/dma
 trace-events-subdirs += hw/hppa
+trace-events-subdirs += hw/hyperv
 trace-events-subdirs += hw/i2c
 trace-events-subdirs += hw/i386
 trace-events-subdirs += hw/i386/xen
diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig
index a1fa8ff9be..3fbfe41c9e 100644
--- a/hw/hyperv/Kconfig
+++ b/hw/hyperv/Kconfig
@@ -6,3 +6,8 @@ config HYPERV_TESTDEV
 bool
 default y if TEST_DEVICES
 depends on HYPERV
+
+config VMBUS
+bool
+default y
+depends on HYPERV
diff --git a/hw/hyperv/Makefile.objs b/hw/hyperv/Makefile.objs
index edaca2f763..5b614e040c 100644
--- a/hw/hyperv/Makefile.objs
+++ b/hw/hyperv/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y += hyperv.o
 obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
+obj-$(CONFIG_VMBUS) += vmbus.o
diff --git a/hw/hyperv/trace-events b/hw/hyperv/trace-events
new file mode 100644
index 00..ba5bd62d61
--- /dev/null
+++ b/hw/hyperv/trace-events
@@ -0,0 +1,18 @@
+# vmbus
+vmbus_recv_message(uint32_t type, uint32_t size) "type %d size %d"
+vmbus_signal_event(void) ""
+vmbus_channel_notify_guest(uint32_t chan_id) "channel #%d"
+vmbus_post_msg(uint32_t type, uint32_t size) "type %d size %d"
+vmbus_msg_cb(int status) "message status %d"
+vmbus_process_incoming_message(uint32_t message_type) "type %d"
+vmbus_initiate_contact(uint16_t major, uint16_t minor, uint32_t vcpu, uint64_t 
monitor_page1, uint64_t monitor_page2, uint64_t interrupt_page) "version %d.%d 
target vp %d mon pages 0x%"PRIx64",0x%"PRIx64" int page 0x%"PRIx64
+vmbus_send_offer(uint32_t chan_id, void *dev) "channel #%d dev %p"
+vmbus_terminate_offers(void) ""
+vmbus_gpadl_header(uint32_t gpadl_id, uint16_t num_gfns) "gpadl #%d gfns %d"
+vmbus_gpadl_body(uint32_t gpadl_id) "gpadl #%d"
+vmbus_gpadl_created(uint32_t gpadl_id) "gpadl #%d"
+vmbus_gpadl_teardown(uint32_t gpadl_id) "gpadl #%d"
+vmbus_gpadl_torndown(uint32_t gpadl_id) "gpadl #%d"
+vmbus_open_channel(uint32_t chan_id, uint32_t gpadl_id, uint32_t target_vp) 
"channel #%d gpadl #%d target vp %d"
+vmbus_channel_open(uint32_t chan_id, uint32_t status) "channel #%d status %d"
+vmbus_close_channel(uint32_t chan_id) "channel #%d"
diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
new file mode 100644
index 00..1f5873ab60
--- /dev/null
+++ b/hw/hyperv/vmbus.c
@@ -0,0 +1,2672 @@
+/*
+ * QEMU Hyper-V VMBus
+ *
+ * Copyright (c) 2017-2018 Virtuozzo International GmbH.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-prope

[PATCH v4 2/6] vmbus: add vmbus protocol definitions

2020-04-24 Thread Jon Doron
Add a header with data structures and constants used in Hyper-V VMBus
hypervisor <-> guest interactions.

Based on the respective stuff from Linux kernel.

Signed-off-by: Roman Kagan 
Signed-off-by: Maciej S. Szmigiero 
Signed-off-by: Jon Doron 
---
 include/hw/hyperv/vmbus-proto.h | 222 
 1 file changed, 222 insertions(+)
 create mode 100644 include/hw/hyperv/vmbus-proto.h

diff --git a/include/hw/hyperv/vmbus-proto.h b/include/hw/hyperv/vmbus-proto.h
new file mode 100644
index 00..4628d3b323
--- /dev/null
+++ b/include/hw/hyperv/vmbus-proto.h
@@ -0,0 +1,222 @@
+/*
+ * QEMU Hyper-V VMBus support
+ *
+ * Copyright (c) 2017-2018 Virtuozzo International GmbH.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_HYPERV_VMBUS_PROTO_H
+#define HW_HYPERV_VMBUS_PROTO_H
+
+#define VMBUS_VERSION_WS2008((0 << 16) | (13))
+#define VMBUS_VERSION_WIN7  ((1 << 16) | (1))
+#define VMBUS_VERSION_WIN8  ((2 << 16) | (4))
+#define VMBUS_VERSION_WIN8_1((3 << 16) | (0))
+#define VMBUS_VERSION_WIN10 ((4 << 16) | (0))
+#define VMBUS_VERSION_INVAL -1
+#define VMBUS_VERSION_CURRENT   VMBUS_VERSION_WIN10
+
+#define VMBUS_MESSAGE_CONNECTION_ID 1
+#define VMBUS_EVENT_CONNECTION_ID   2
+#define VMBUS_MONITOR_CONNECTION_ID 3
+#define VMBUS_SINT  2
+
+#define VMBUS_MSG_INVALID   0
+#define VMBUS_MSG_OFFERCHANNEL  1
+#define VMBUS_MSG_RESCIND_CHANNELOFFER  2
+#define VMBUS_MSG_REQUESTOFFERS 3
+#define VMBUS_MSG_ALLOFFERS_DELIVERED   4
+#define VMBUS_MSG_OPENCHANNEL   5
+#define VMBUS_MSG_OPENCHANNEL_RESULT6
+#define VMBUS_MSG_CLOSECHANNEL  7
+#define VMBUS_MSG_GPADL_HEADER  8
+#define VMBUS_MSG_GPADL_BODY9
+#define VMBUS_MSG_GPADL_CREATED 10
+#define VMBUS_MSG_GPADL_TEARDOWN11
+#define VMBUS_MSG_GPADL_TORNDOWN12
+#define VMBUS_MSG_RELID_RELEASED13
+#define VMBUS_MSG_INITIATE_CONTACT  14
+#define VMBUS_MSG_VERSION_RESPONSE  15
+#define VMBUS_MSG_UNLOAD16
+#define VMBUS_MSG_UNLOAD_RESPONSE   17
+#define VMBUS_MSG_COUNT 18
+
+#define VMBUS_MESSAGE_SIZE_ALIGNsizeof(uint64_t)
+
+#define VMBUS_PACKET_INVALID0x0
+#define VMBUS_PACKET_SYNCH  0x1
+#define VMBUS_PACKET_ADD_XFER_PAGESET   0x2
+#define VMBUS_PACKET_RM_XFER_PAGESET0x3
+#define VMBUS_PACKET_ESTABLISH_GPADL0x4
+#define VMBUS_PACKET_TEARDOWN_GPADL 0x5
+#define VMBUS_PACKET_DATA_INBAND0x6
+#define VMBUS_PACKET_DATA_USING_XFER_PAGES  0x7
+#define VMBUS_PACKET_DATA_USING_GPADL   0x8
+#define VMBUS_PACKET_DATA_USING_GPA_DIRECT  0x9
+#define VMBUS_PACKET_CANCEL_REQUEST 0xa
+#define VMBUS_PACKET_COMP   0xb
+#define VMBUS_PACKET_DATA_USING_ADDITIONAL_PKT  0xc
+#define VMBUS_PACKET_ADDITIONAL_DATA0xd
+
+#define VMBUS_CHANNEL_USER_DATA_SIZE120
+
+#define VMBUS_OFFER_MONITOR_ALLOCATED   0x1
+#define VMBUS_OFFER_INTERRUPT_DEDICATED 0x1
+
+#define VMBUS_RING_BUFFER_FEAT_PENDING_SZ   (1ul << 0)
+
+#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE  0x1
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES  0x2
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS  0x4
+#define VMBUS_CHANNEL_NAMED_PIPE_MODE 0x10
+#define VMBUS_CHANNEL_LOOPBACK_OFFER  0x100
+#define VMBUS_CHANNEL_PARENT_OFFER0x200
+#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION  0x400
+#define VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER0x2000
+
+#define VMBUS_PACKET_FLAG_REQUEST_COMPLETION1
+
+typedef struct vmbus_message_header {
+uint32_t message_type;
+uint32_t _padding;
+} vmbus_message_header;
+
+typedef struct vmbus_message_initiate_contact {
+vmbus_message_header header;
+uint32_t version_requested;
+uint32_t target_vcpu;
+uint64_t interrupt_page;
+uint64_t monitor_page1;
+uint64_t monitor_page2;
+} vmbus_message_initiate_contact;
+
+typedef struct vmbus_message_version_response {
+vmbus_message_header header;
+uint8_t version_supported;
+uint8_t status;
+} vmbus_message_version_response;
+
+typedef struct vmbus_message_offer_channel {
+vmbus_message_header header;
+uint8_t  type_uuid[16];
+uint8_t  instance_uuid[16];
+uint64_t _reserved1;
+uint64_t _reserved2;
+uint16_t channel_flags;
+uint16_t mmio_size_mb;
+uint8_t  user_data[VMBUS_CHANNEL_USER_DATA_SIZE];
+uint16_t sub_channel_index;
+uint16_t _reserved3;
+uint32_t child_relid;
+uint8_t  monitor_id;

[PATCH v4 6/6] vmbus: add infrastructure to save/load vmbus requests

2020-04-24 Thread Jon Doron
This can be allow to include controller-specific data while
saving/loading in-flight scsi requests of the vmbus scsi controller.

Signed-off-by: Roman Kagan 
Signed-off-by: Maciej S. Szmigiero 
Signed-off-by: Jon Doron 
---
 hw/hyperv/vmbus.c | 99 +++
 include/hw/hyperv/vmbus.h |  3 ++
 2 files changed, 102 insertions(+)

diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
index 0df7afe0ca..ab72a59a4a 100644
--- a/hw/hyperv/vmbus.c
+++ b/hw/hyperv/vmbus.c
@@ -1272,6 +1272,105 @@ void vmbus_free_req(void *req)
 g_free(req);
 }
 
+static const VMStateDescription vmstate_sgent = {
+.name = "vmbus/sgentry",
+.version_id = 0,
+.minimum_version_id = 0,
+.fields = (VMStateField[]) {
+VMSTATE_UINT64(base, ScatterGatherEntry),
+VMSTATE_UINT64(len, ScatterGatherEntry),
+VMSTATE_END_OF_LIST()
+}
+};
+
+typedef struct VMBusChanReqSave {
+uint16_t chan_idx;
+uint16_t pkt_type;
+uint32_t msglen;
+void *msg;
+uint64_t transaction_id;
+bool need_comp;
+uint32_t num;
+ScatterGatherEntry *sgl;
+} VMBusChanReqSave;
+
+static const VMStateDescription vmstate_vmbus_chan_req = {
+.name = "vmbus/vmbus_chan_req",
+.version_id = 0,
+.minimum_version_id = 0,
+.fields = (VMStateField[]) {
+VMSTATE_UINT16(chan_idx, VMBusChanReqSave),
+VMSTATE_UINT16(pkt_type, VMBusChanReqSave),
+VMSTATE_UINT32(msglen, VMBusChanReqSave),
+VMSTATE_VBUFFER_ALLOC_UINT32(msg, VMBusChanReqSave, 0, NULL, msglen),
+VMSTATE_UINT64(transaction_id, VMBusChanReqSave),
+VMSTATE_BOOL(need_comp, VMBusChanReqSave),
+VMSTATE_UINT32(num, VMBusChanReqSave),
+VMSTATE_STRUCT_VARRAY_POINTER_UINT32(sgl, VMBusChanReqSave, num,
+ vmstate_sgent, 
ScatterGatherEntry),
+VMSTATE_END_OF_LIST()
+}
+};
+
+void vmbus_save_req(QEMUFile *f, VMBusChanReq *req)
+{
+VMBusChanReqSave req_save;
+
+req_save.chan_idx = req->chan->subchan_idx;
+req_save.pkt_type = req->pkt_type;
+req_save.msglen = req->msglen;
+req_save.msg = req->msg;
+req_save.transaction_id = req->transaction_id;
+req_save.need_comp = req->need_comp;
+req_save.num = req->sgl.nsg;
+req_save.sgl = g_memdup(req->sgl.sg,
+req_save.num * sizeof(ScatterGatherEntry));
+
+vmstate_save_state(f, &vmstate_vmbus_chan_req, &req_save, NULL);
+
+g_free(req_save.sgl);
+}
+
+void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size)
+{
+VMBusChanReqSave req_save;
+VMBusChanReq *req = NULL;
+VMBusChannel *chan = NULL;
+uint32_t i;
+
+vmstate_load_state(f, &vmstate_vmbus_chan_req, &req_save, 0);
+
+if (req_save.chan_idx >= dev->num_channels) {
+error_report("%s: %u(chan_idx) > %u(num_channels)", __func__,
+ req_save.chan_idx, dev->num_channels);
+goto out;
+}
+chan = &dev->channels[req_save.chan_idx];
+
+if (vmbus_channel_reserve(chan, 0, req_save.msglen)) {
+goto out;
+}
+
+req = vmbus_alloc_req(chan, size, req_save.pkt_type, req_save.msglen,
+  req_save.transaction_id, req_save.need_comp);
+if (req_save.msglen) {
+memcpy(req->msg, req_save.msg, req_save.msglen);
+}
+
+for (i = 0; i < req_save.num; i++) {
+qemu_sglist_add(&req->sgl, req_save.sgl[i].base, req_save.sgl[i].len);
+}
+
+out:
+if (req_save.msglen) {
+g_free(req_save.msg);
+}
+if (req_save.num) {
+g_free(req_save.sgl);
+}
+return req;
+}
+
 static void channel_event_cb(EventNotifier *e)
 {
 VMBusChannel *chan = container_of(e, VMBusChannel, notifier);
diff --git a/include/hw/hyperv/vmbus.h b/include/hw/hyperv/vmbus.h
index 63a5b807b6..9219f34d6b 100644
--- a/include/hw/hyperv/vmbus.h
+++ b/include/hw/hyperv/vmbus.h
@@ -224,4 +224,7 @@ int vmbus_map_sgl(VMBusChanReq *req, DMADirection dir, 
struct iovec *iov,
 void vmbus_unmap_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov,
  unsigned iov_cnt, size_t accessed);
 
+void vmbus_save_req(QEMUFile *f, VMBusChanReq *req);
+void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size);
+
 #endif
-- 
2.24.1




Re: [PATCH v3 2/3] i386: acpi: vmbus: Add _ADR definition

2020-06-24 Thread Jon Doron

On 23/06/2020, Igor Mammedov wrote:

On Thu, 18 Jun 2020 06:00:26 +0300
Jon Doron  wrote:


It seems like latest HyperV sets _ADR to 0 in the ACPI for the VMBS


that's a hardly a good reason to add this.
To me looks like a pointless addition,
_ADR mostly is used when device resides on a bus with standard ennumeration
algorithm (i.e. PCI, ...).

Value is also wrong  for the bus it's placed currently,
and with the next patch it won't make a sense altogether.

Pls, drop this patch unless Windows refuses to work without it.



Windows seems to handle fine without this.



Signed-off-by: Jon Doron 
---
 hw/i386/acpi-build.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 91af0d2d0d..6d9df38e31 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1061,6 +1061,7 @@ static Aml *build_vmbus_device_aml(VMBusBridge 
*vmbus_bridge)

 dev = aml_device("VMBS");
 aml_append(dev, aml_name_decl("STA", aml_int(0xF)));
+aml_append(dev, aml_name_decl("_ADR", aml_int(0x0)));
 aml_append(dev, aml_name_decl("_HID", aml_string("VMBus")));
 aml_append(dev, aml_name_decl("_UID", aml_int(0x0)));
 aml_append(dev, aml_name_decl("_DDN", aml_string("VMBUS")));






Re: [PATCH v3 3/3] acpi: i386: Move VMBus DSDT entry to SB

2020-06-24 Thread Jon Doron

On 23/06/2020, Igor Mammedov wrote:

On Thu, 18 Jun 2020 06:00:27 +0300
Jon Doron  wrote:


Signed-off-by: Jon Doron 
---
 hw/i386/acpi-build.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 6d9df38e31..38be9e5a58 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1092,7 +1092,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge 
*vmbus_bridge)
 static void build_isa_devices_aml(Aml *table)
 {
 ISADevice *fdc = pc_find_fdc0();
-VMBusBridge *vmbus_bridge = vmbus_bridge_find();
 bool ambiguous;

 Aml *scope = aml_scope("_SB.PCI0.ISA");
@@ -1113,10 +1112,6 @@ static void build_isa_devices_aml(Aml *table)
 isa_build_aml(ISA_BUS(obj), scope);
 }

-if (vmbus_bridge) {
-aml_append(scope, build_vmbus_device_aml(vmbus_bridge));
-}
-
 aml_append(table, scope);
 }

@@ -1661,6 +1656,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 PCIBus *bus = NULL;
 TPMIf *tpm = tpm_find();
 int i;
+VMBusBridge *vmbus_bridge = vmbus_bridge_find();

 dsdt = init_aml_allocator();

@@ -1675,6 +1671,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
 aml_append(dev, aml_name_decl("_UID", aml_int(1)));
 aml_append(sb_scope, dev);
+if (vmbus_bridge) {
+aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
+}
 aml_append(dsdt, sb_scope);

 build_hpet_aml(dsdt);
@@ -1692,6 +1691,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 aml_append(dev, aml_name_decl("_UID", aml_int(1)));
 aml_append(dev, build_q35_osc_method());
 aml_append(sb_scope, dev);
+if (vmbus_bridge) {
+aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
+}
 aml_append(dsdt, sb_scope);

 build_hpet_aml(dsdt);

why are you duplicating instead of putting one if () block after

if (misc->is_piix4) {
} else {
}

?



Well it seems like Windows is very "picky" about where you declare the 
VMBS not sure why if i had moved it to the suggested location as such


if (misc->is_piix4) {
} else {
}

if (vmbus_bridge) {
aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
aml_append(dsdt, sb_scope);
}

Windows would BSOD right away with ACPI error.

Same goes for declaring it before PCI0 device...

-- Jon.



Re: [PATCH v3 3/3] acpi: i386: Move VMBus DSDT entry to SB

2020-06-24 Thread Jon Doron

On 25/06/2020, Jon Doron wrote:

On 23/06/2020, Igor Mammedov wrote:

On Thu, 18 Jun 2020 06:00:27 +0300
Jon Doron  wrote:


Signed-off-by: Jon Doron 
---
hw/i386/acpi-build.c | 12 +++-
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 6d9df38e31..38be9e5a58 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1092,7 +1092,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge 
*vmbus_bridge)
static void build_isa_devices_aml(Aml *table)
{
ISADevice *fdc = pc_find_fdc0();
-VMBusBridge *vmbus_bridge = vmbus_bridge_find();
bool ambiguous;

Aml *scope = aml_scope("_SB.PCI0.ISA");
@@ -1113,10 +1112,6 @@ static void build_isa_devices_aml(Aml *table)
isa_build_aml(ISA_BUS(obj), scope);
}

-if (vmbus_bridge) {
-aml_append(scope, build_vmbus_device_aml(vmbus_bridge));
-}
-
aml_append(table, scope);
}

@@ -1661,6 +1656,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
PCIBus *bus = NULL;
TPMIf *tpm = tpm_find();
int i;
+VMBusBridge *vmbus_bridge = vmbus_bridge_find();

dsdt = init_aml_allocator();

@@ -1675,6 +1671,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
aml_append(sb_scope, dev);
+if (vmbus_bridge) {
+aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
+}
aml_append(dsdt, sb_scope);

build_hpet_aml(dsdt);
@@ -1692,6 +1691,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
aml_append(dev, build_q35_osc_method());
aml_append(sb_scope, dev);
+if (vmbus_bridge) {
+aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
+}
aml_append(dsdt, sb_scope);

build_hpet_aml(dsdt);

why are you duplicating instead of putting one if () block after

if (misc->is_piix4) {
} else {
}

?



Well it seems like Windows is very "picky" about where you declare the 
VMBS not sure why if i had moved it to the suggested location as such


if (misc->is_piix4) {
} else {
}

if (vmbus_bridge) {
   aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
   aml_append(dsdt, sb_scope);
}

Windows would BSOD right away with ACPI error.

Same goes for declaring it before PCI0 device...

-- Jon.


Never mind did a silly mistake ill send a new set shortly



[PATCH v4 0/2] hyperv: vmbus: ACPI various corrections

2020-06-24 Thread Jon Doron
After doing further tests and looking at the latest HyperV ACPI DSDT.
Do minor fix to our VMBus ACPI entry.

v4:
* Removed the patch which adds _ADR definition to the VMBus
* Correct the change which moves the VMBus under the SB

v3:
Removed accidental change for the dct submodule head

v2:
Renamed irq0 to irq now that there is a single IRQ required

Jon Doron (2):
  hyperv: vmbus: Remove the 2nd IRQ
  acpi: i386: Move VMBus DSDT entry to SB

 hw/hyperv/vmbus.c|  3 +--
 hw/i386/acpi-build.c | 16 
 include/hw/hyperv/vmbus-bridge.h |  3 +--
 3 files changed, 10 insertions(+), 12 deletions(-)

-- 
2.24.1




[PATCH v4 1/2] hyperv: vmbus: Remove the 2nd IRQ

2020-06-24 Thread Jon Doron
It seems like Windows does not really require 2 IRQs to have a
functioning VMBus.

Signed-off-by: Jon Doron 
Reviewed-by: Igor Mammedov 
---
 hw/hyperv/vmbus.c| 3 +--
 hw/i386/acpi-build.c | 4 +---
 include/hw/hyperv/vmbus-bridge.h | 3 +--
 3 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
index f371240176..a8bcb41026 100644
--- a/hw/hyperv/vmbus.c
+++ b/hw/hyperv/vmbus.c
@@ -2741,8 +2741,7 @@ static const VMStateDescription vmstate_vmbus_bridge = {
 };
 
 static Property vmbus_bridge_props[] = {
-DEFINE_PROP_UINT8("irq0", VMBusBridge, irq0, 7),
-DEFINE_PROP_UINT8("irq1", VMBusBridge, irq1, 13),
+DEFINE_PROP_UINT8("irq", VMBusBridge, irq, 7),
 DEFINE_PROP_END_OF_LIST()
 };
 
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 900f786d08..91af0d2d0d 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1082,9 +1082,7 @@ static Aml *build_vmbus_device_aml(VMBusBridge 
*vmbus_bridge)
 aml_append(dev, aml_name_decl("_PS3", aml_int(0x0)));
 
 crs = aml_resource_template();
-aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq0));
-/* FIXME: newer HyperV gets by with only one IRQ */
-aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq1));
+aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq));
 aml_append(dev, aml_name_decl("_CRS", crs));
 
 return dev;
diff --git a/include/hw/hyperv/vmbus-bridge.h b/include/hw/hyperv/vmbus-bridge.h
index c0a06d832c..33f93de64d 100644
--- a/include/hw/hyperv/vmbus-bridge.h
+++ b/include/hw/hyperv/vmbus-bridge.h
@@ -19,8 +19,7 @@ typedef struct VMBus VMBus;
 typedef struct VMBusBridge {
 SysBusDevice parent_obj;
 
-uint8_t irq0;
-uint8_t irq1;
+uint8_t irq;
 
 VMBus *bus;
 } VMBusBridge;
-- 
2.24.1




[PATCH v4 2/2] acpi: i386: Move VMBus DSDT entry to SB

2020-06-24 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 hw/i386/acpi-build.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 91af0d2d0d..1f938a53b2 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1091,7 +1091,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge 
*vmbus_bridge)
 static void build_isa_devices_aml(Aml *table)
 {
 ISADevice *fdc = pc_find_fdc0();
-VMBusBridge *vmbus_bridge = vmbus_bridge_find();
 bool ambiguous;
 
 Aml *scope = aml_scope("_SB.PCI0.ISA");
@@ -1112,10 +,6 @@ static void build_isa_devices_aml(Aml *table)
 isa_build_aml(ISA_BUS(obj), scope);
 }
 
-if (vmbus_bridge) {
-aml_append(scope, build_vmbus_device_aml(vmbus_bridge));
-}
-
 aml_append(table, scope);
 }
 
@@ -1660,6 +1655,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 PCIBus *bus = NULL;
 TPMIf *tpm = tpm_find();
 int i;
+VMBusBridge *vmbus_bridge = vmbus_bridge_find();
 
 dsdt = init_aml_allocator();
 
@@ -1702,6 +1698,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 }
 }
 
+if (vmbus_bridge) {
+sb_scope = aml_scope("_SB");
+aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
+aml_append(dsdt, sb_scope);
+}
+
 if (pcmc->legacy_cpu_hotplug) {
 build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base);
 } else {
-- 
2.24.1




Re: [PATCH v4 0/2] hyperv: vmbus: ACPI various corrections

2020-07-13 Thread Jon Doron
Sure thing I'll try to take a look at it this weekend.

Jon.

On Mon, Jul 13, 2020, 11:44 Igor Mammedov  wrote:

> On Thu, 25 Jun 2020 07:50:09 +0300
> Jon Doron  wrote:
>
> > After doing further tests and looking at the latest HyperV ACPI DSDT.
> > Do minor fix to our VMBus ACPI entry.
>
> Jon,
> vmbus feature needs a testcase, could you look into it please?
> (see tests/qtest/bios-tables-test.c for an example.
> also look into comment blob at the top for the propper process
> for acpi patches/tests)
>
>
> > v4:
> > * Removed the patch which adds _ADR definition to the VMBus
> > * Correct the change which moves the VMBus under the SB
> >
> > v3:
> > Removed accidental change for the dct submodule head
> >
> > v2:
> > Renamed irq0 to irq now that there is a single IRQ required
> >
> > Jon Doron (2):
> >   hyperv: vmbus: Remove the 2nd IRQ
> >   acpi: i386: Move VMBus DSDT entry to SB
> >
> >  hw/hyperv/vmbus.c|  3 +--
> >  hw/i386/acpi-build.c | 16 
> >  include/hw/hyperv/vmbus-bridge.h |  3 +--
> >  3 files changed, 10 insertions(+), 12 deletions(-)
> >
>
>


[PATCH v5 1/2] acpi: i386: Move VMBus DSDT entry to SB

2020-07-15 Thread Jon Doron
Signed-off-by: Jon Doron 
---
 hw/i386/acpi-build.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b7bc2a..7708a27f70 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -975,7 +975,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge 
*vmbus_bridge)
 
 static void build_isa_devices_aml(Aml *table)
 {
-VMBusBridge *vmbus_bridge = vmbus_bridge_find();
 bool ambiguous;
 Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
 Aml *scope;
@@ -986,10 +985,6 @@ static void build_isa_devices_aml(Aml *table)
 build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
 isa_build_aml(ISA_BUS(obj), scope);
 
-if (vmbus_bridge) {
-aml_append(scope, build_vmbus_device_aml(vmbus_bridge));
-}
-
 aml_append(table, scope);
 }
 
@@ -1485,6 +1480,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 PCIBus *bus = NULL;
 TPMIf *tpm = tpm_find();
 int i;
+VMBusBridge *vmbus_bridge = vmbus_bridge_find();
 
 dsdt = init_aml_allocator();
 
@@ -1526,6 +1522,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 }
 }
 
+if (vmbus_bridge) {
+sb_scope = aml_scope("_SB");
+aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
+aml_append(dsdt, sb_scope);
+}
+
 if (pcmc->legacy_cpu_hotplug) {
 build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base);
 } else {
-- 
2.24.1




[PATCH v5 0/2] hyperv: vmbus: ACPI various corrections

2020-07-15 Thread Jon Doron
After doing further tests and looking at the latest HyperV ACPI DSDT.
Do minor fix to our VMBus ACPI entry.

v5:
* Rebased on latest master
* Added a patch to fix 32bit compliation on VMBus

v4:
* Removed the patch which adds _ADR definition to the VMBus
* Correct the change which moves the VMBus under the SB

v3:
Removed accidental change for the dct submodule head

v2:
Renamed irq0 to irq now that there is a single IRQ required

Jon Doron (2):
  acpi: i386: Move VMBus DSDT entry to SB
  hw: hyperv: vmbus: Fix 32bit compilation

 hw/hyperv/vmbus.c|  3 ++-
 hw/i386/acpi-build.c | 12 +++-
 2 files changed, 9 insertions(+), 6 deletions(-)

-- 
2.24.1




  1   2   3   4   >