diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 0b4f0a0..1506263 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -122,6 +122,10 @@ bool has_%(argname)s = false;
 %(argtype)s %(argname)s;
 ''',
                          argname=c_var(argname), argtype=c_type(argtype))
+        if argtype == '**':
+            ret += mcgen('''
+QString *arglist = NULL;
+''')
 
     pop_indent()
     return ret.rstrip()
@@ -146,6 +150,8 @@ v = qmp_input_get_visitor(mi);
                      obj=obj)
 
     for argname, argtype, optional, structured in parse_args(args):
+        if argtype == '**':
+            continue
         if optional:
             ret += mcgen('''
 visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
@@ -257,6 +263,86 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
     if (error_is_set(errp)) {
         goto out;
     }
+''')
+
+    # '**' implementation
+    regular_args = []
+    var_list_name = ""
+    for argname, argtype, optional, structured in parse_args(args):
+        if argtype == '**':
+            var_list_name = argname
+        else:
+            regular_args.append(argname)
+
+    if var_list_name:
+        ret += mcgen('''
+    else {
+        const QDictEntry *entry;
+
+        arglist = qstring_new();
+        for (entry = qdict_first(args); entry;
+             entry = qdict_next(qdict, entry)) {
+            const QObject *obj = qdict_entry_value(entry);
+            char buf[32];
+            int n;
+
+''')
+        for argname in regular_args:
+            ret += mcgen('''
+            if (strcmp(qdict_entry_key(entry), "%(argname)s") == 0) {
+                continue;
+            }
+
+''', argname=argname)
+
+        ret += mcgen('''
+            if (qstring_len(arglist) > 0) {
+                qstring_append(arglist, ",");
+            }
+
+            qstring_append(arglist, qdict_entry_key(entry));
+            qstring_append(arglist, "=");
+
+            switch(qobject_type(obj)) {
+            case QTYPE_QSTRING:
+                qstring_append(arglist,
+                               qstring_get_str(qobject_to_qstring(obj)));
+                break;
+            case QTYPE_QINT:
+                n = snprintf(buf, sizeof(buf), %(arg1)s,
+                             qint_get_int(qobject_to_qint(obj)));
+                assert(n < sizeof(buf));
+                qstring_append(arglist, buf);
+                break;
+            case QTYPE_QFLOAT:
+                n = snprintf(buf, sizeof(buf), %(arg2)s,
+                             qfloat_get_double(qobject_to_qfloat(obj)));
+                qstring_append(arglist, buf);
+                break;
+            case QTYPE_QBOOL:
+                pstrcpy(buf, sizeof(buf),
+                        qbool_get_int(qobject_to_qbool(obj)) ? "on" : "off");
+                qstring_append(arglist, buf);
+                break;
+            default:
+                QDECREF(arglist);
+                error_set(&local_err, QERR_INVALID_PARAMETER_TYPE,
+                          qdict_entry_key(entry),
+                          "string, int, float or bool");
+                goto out;
+            }
+        }
+
+        if (qstring_len(arglist) > 0) {
+            has_%(var_list_name)s = true;
+            %(var_list_name)s = qstring_get_str(arglist);
+        }
+    }
+
+''', var_list_name=c_var(var_list_name), arg1='"%" PRId64', arg2='"%.17g"',
+    arg3='"%d"')
+
+    ret += mcgen('''
 %(sync_call)s
 ''',
                  sync_call=gen_sync_call(name, args, ret_type, indent=4))
@@ -270,6 +356,11 @@ out:
                  visitor_input_block_cleanup=gen_visitor_input_block(args, None,
                                                                      dealloc=True))
 
+    if var_list_name:
+        ret += mcgen('''
+    QDECREF(arglist);
+''')
+
     if middle_mode:
         ret += mcgen('''
 
diff --git a/scripts/qapi.py b/scripts/qapi.py
index e062336..9bd6e95 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -163,6 +163,8 @@ def c_type(name):
         return 'bool'
     elif name == 'number':
         return 'double'
+    elif name == '**':
+        return 'const char *'
     elif type(name) == list:
         return '%s *' % c_list_type(name[0])
     elif is_enum(name):
