diff --git a/docs/devel/writing-monitor-commands.rst b/docs/devel/writing-monitor-commands.rst
index 930da5cd06..843458e52c 100644
--- a/docs/devel/writing-monitor-commands.rst
+++ b/docs/devel/writing-monitor-commands.rst
@@ -561,6 +561,7 @@ returns a ``HumanReadableText``::
  # Since: 6.2
  ##
  { 'command': 'x-query-roms',
+   'data': { 'json-args': 'str'},
    'returns': 'HumanReadableText',
    'features': [ 'unstable' ] }
 
@@ -578,7 +579,7 @@ Implementing the QMP command
 The QMP implementation will typically involve creating a ``GString``
 object and printing formatted data into it, like this::
 
- HumanReadableText *qmp_x_query_roms(Error **errp)
+ HumanReadableText *qmp_x_query_roms(const char *json_args, Error **errp)
  {
      g_autoptr(GString) buf = g_string_new("");
      Rom *rom;
@@ -596,6 +597,18 @@ object and printing formatted data into it, like this::
 The actual implementation emits more information.  You can find it in
 hw/core/loader.c.
 
+For QMP command taking (optional) parameters, these parameters are
+serialized as a JSON dictionary, and can be retrieved using the QDict
+API. If the previous ``x-query-roms`` command were taking a "index"
+argument, it could be retrieved as::
+
+ HumanReadableText *qmp_x_query_roms(const char *json_args, Error **errp)
+ {
+     g_autoptr(GString) buf = g_string_new("");
+     QDict *qdict = qobject_to(QDict, qobject_from_json(json_args, &error_abort));
+     uint64_t index = qdict_get_int(qdict, "index");
+     ...
+ }
 
 Implementing the HMP command
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/qapi/machine.json b/qapi/machine.json
index 1283d14493..6da72f2585 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1697,6 +1697,8 @@
 #
 # Query interrupt statistics
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1706,6 +1708,7 @@
 # Since: 6.2
 ##
 { 'command': 'x-query-irq',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'features': [ 'unstable' ] }
 
@@ -1714,6 +1717,8 @@
 #
 # Query TCG compiler statistics
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1723,6 +1728,7 @@
 # Since: 6.2
 ##
 { 'command': 'x-query-jit',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'if': 'CONFIG_TCG',
   'features': [ 'unstable' ] }
@@ -1732,6 +1738,8 @@
 #
 # Query NUMA topology information
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1741,6 +1749,7 @@
 # Since: 6.2
 ##
 { 'command': 'x-query-numa',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'features': [ 'unstable' ] }
 
@@ -1749,6 +1758,8 @@
 #
 # Query TCG opcode counters
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1758,6 +1769,7 @@
 # Since: 6.2
 ##
 { 'command': 'x-query-opcount',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'if': 'CONFIG_TCG',
   'features': [ 'unstable' ] }
@@ -1767,6 +1779,8 @@
 #
 # Query system ramblock information
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1776,6 +1790,7 @@
 # Since: 6.2
 ##
 { 'command': 'x-query-ramblock',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'features': [ 'unstable' ] }
 
@@ -1784,6 +1799,8 @@
 #
 # Query information on the registered ROMS
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1793,6 +1810,7 @@
 # Since: 6.2
 ##
 { 'command': 'x-query-roms',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'features': [ 'unstable' ] }
 
@@ -1801,6 +1819,8 @@
 #
 # Query information on the USB devices
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1810,6 +1830,7 @@
 # Since: 6.2
 ##
 { 'command': 'x-query-usb',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'features': [ 'unstable' ] }
 
@@ -1870,6 +1891,8 @@
 #
 # Query information on interrupt controller devices
 #
+# @json-args: HMP arguments encoded as JSON string (unused for this command).
+#
 # Features:
 #
 # @unstable: This command is meant for debugging.
@@ -1879,5 +1902,6 @@
 # Since: 9.1
 ##
 { 'command': 'x-query-interrupt-controllers',
+  'data': { 'json-args': 'str'},
   'returns': 'HumanReadableText',
   'features': [ 'unstable' ]}
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 965f5d5450..b21c702c12 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -58,7 +58,8 @@ int64_t monitor_fdset_dup_fd_find(int dup_fd);
 void monitor_register_hmp(const char *name, bool info,
                           void (*cmd)(Monitor *mon, const QDict *qdict));
 void monitor_register_hmp_info_hrt(const char *name,
-                                   HumanReadableText *(*handler)(Error **errp));
+                                   HumanReadableText *(*handler)(const char *json_args,
+                                                                 Error **errp));
 
 int error_vprintf_unless_qmp(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0);
 int error_printf_unless_qmp(const char *fmt, ...) G_GNUC_PRINTF(1, 2);
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 252de85681..b3aa50834b 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -81,7 +81,7 @@ typedef struct HMPCommand {
      * @cmd_info_hrt to the corresponding QMP handler that returns
      * the formatted text.
      */
-    HumanReadableText *(*cmd_info_hrt)(Error **errp);
+    HumanReadableText *(*cmd_info_hrt)(const char *json_args, Error **errp);
     bool coroutine;
     /*
      * @sub_table is a list of 2nd level of commands. If it does not exist,
diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c
index 093efe9714..517c96eeb7 100644
--- a/accel/tcg/monitor.c
+++ b/accel/tcg/monitor.c
@@ -199,7 +199,7 @@ static void dump_exec_info(GString *buf)
     tcg_dump_info(buf);
 }
 
-HumanReadableText *qmp_x_query_jit(Error **errp)
+HumanReadableText *qmp_x_query_jit(const char *json_args, Error **errp)
 {
     g_autoptr(GString) buf = g_string_new("");
 
@@ -220,7 +220,7 @@ static void tcg_dump_op_count(GString *buf)
     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
 }
 
-HumanReadableText *qmp_x_query_opcount(Error **errp)
+HumanReadableText *qmp_x_query_opcount(const char *json_args, Error **errp)
 {
     g_autoptr(GString) buf = g_string_new("");
 
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 2f8105d7de..e0da5edbb3 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -1679,7 +1679,7 @@ void *rom_ptr_for_as(AddressSpace *as, hwaddr addr, size_t size)
     return cbdata.rom;
 }
 
-HumanReadableText *qmp_x_query_roms(Error **errp)
+HumanReadableText *qmp_x_query_roms(const char *json_args, Error **errp)
 {
     Rom *rom;
     g_autoptr(GString) buf = g_string_new("");
diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
index 130217da8f..fc79772df8 100644
--- a/hw/core/machine-qmp-cmds.c
+++ b/hw/core/machine-qmp-cmds.c
@@ -214,7 +214,7 @@ MemdevList *qmp_query_memdev(Error **errp)
     return list;
 }
 
-HumanReadableText *qmp_x_query_numa(Error **errp)
+HumanReadableText *qmp_x_query_numa(const char *json_args, Error **errp)
 {
     g_autoptr(GString) buf = g_string_new("");
     int i, nb_numa_nodes;
@@ -311,7 +311,7 @@ MemoryInfo *qmp_query_memory_size_summary(Error **errp)
     return mem_info;
 }
 
-HumanReadableText *qmp_x_query_ramblock(Error **errp)
+HumanReadableText *qmp_x_query_ramblock(const char *json_args, Error **errp)
 {
     g_autoptr(GString) buf = ram_block_format();
 
@@ -351,7 +351,7 @@ static int qmp_x_query_irq_foreach(Object *obj, void *opaque)
     return 0;
 }
 
-HumanReadableText *qmp_x_query_irq(Error **errp)
+HumanReadableText *qmp_x_query_irq(const char *json_args, Error **errp)
 {
     g_autoptr(GString) buf = g_string_new("");
 
@@ -382,7 +382,8 @@ static int qmp_x_query_intc_foreach(Object *obj, void *opaque)
     return 0;
 }
 
-HumanReadableText *qmp_x_query_interrupt_controllers(Error **errp)
+HumanReadableText *qmp_x_query_interrupt_controllers(const char *json_args,
+                                                     Error **errp)
 {
     g_autoptr(GString) buf = g_string_new("");
     object_child_foreach_recursive(object_get_root(),
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index bfab2807d7..daa3f71d47 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -598,7 +598,7 @@ static char *usb_get_fw_dev_path(DeviceState *qdev)
     return fw_path;
 }
 
-HumanReadableText *qmp_x_query_usb(Error **errp)
+HumanReadableText *qmp_x_query_usb(const char *json_args, Error **errp)
 {
     g_autoptr(GString) buf = g_string_new("");
     USBBus *bus;
diff --git a/monitor/hmp-target.c b/monitor/hmp-target.c
index 0466474354..81e53a5767 100644
--- a/monitor/hmp-target.c
+++ b/monitor/hmp-target.c
@@ -157,7 +157,8 @@ void monitor_register_hmp(const char *name, bool info,
 }
 
 void monitor_register_hmp_info_hrt(const char *name,
-                                   HumanReadableText *(*handler)(Error **errp))
+                                   HumanReadableText *(*handler)(const char *json_args,
+                                                                 Error **errp))
 {
     HMPCommand *table = hmp_info_cmds;
 
diff --git a/monitor/hmp.c b/monitor/hmp.c
index 69c1b7e98a..7802a31412 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -29,6 +29,7 @@
 #include "monitor/hmp.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qjson.h"
 #include "qemu/config-file.h"
 #include "qemu/ctype.h"
 #include "qemu/cutils.h"
@@ -1082,11 +1083,13 @@ fail:
     return NULL;
 }
 
-static void hmp_info_human_readable_text(Monitor *mon,
-                                         HumanReadableText *(*handler)(Error **))
+static void hmp_info_human_readable_text(Monitor *mon, QDict *qdict,
+                                         HumanReadableText *(*handler)(const char *,
+                                                                       Error **))
 {
     Error *err = NULL;
-    g_autoptr(HumanReadableText) info = handler(&err);
+    g_autoptr(GString) ret_json = qobject_to_json(QOBJECT(qdict));
+    g_autoptr(HumanReadableText) info = handler(ret_json->str, &err);
 
     if (hmp_handle_error(mon, err)) {
         return;
@@ -1100,7 +1103,7 @@ static void handle_hmp_command_exec(Monitor *mon,
                                     QDict *qdict)
 {
     if (cmd->cmd_info_hrt) {
-        hmp_info_human_readable_text(mon,
+        hmp_info_human_readable_text(mon, qdict,
                                      cmd->cmd_info_hrt);
     } else {
         cmd->cmd(mon, qdict);
