1fb0bc835SMarkus Armbruster""" 2fb0bc835SMarkus ArmbrusterQAPI command marshaller generator 3fb0bc835SMarkus Armbruster 4fb0bc835SMarkus ArmbrusterCopyright IBM, Corp. 2011 5fb0bc835SMarkus ArmbrusterCopyright (C) 2014-2018 Red Hat, Inc. 6fb0bc835SMarkus Armbruster 7fb0bc835SMarkus ArmbrusterAuthors: 8fb0bc835SMarkus Armbruster Anthony Liguori <aliguori@us.ibm.com> 9fb0bc835SMarkus Armbruster Michael Roth <mdroth@linux.vnet.ibm.com> 10fb0bc835SMarkus Armbruster Markus Armbruster <armbru@redhat.com> 11fb0bc835SMarkus Armbruster 12fb0bc835SMarkus ArmbrusterThis work is licensed under the terms of the GNU GPL, version 2. 13fb0bc835SMarkus ArmbrusterSee the COPYING file in the top-level directory. 14fb0bc835SMarkus Armbruster""" 15fb0bc835SMarkus Armbruster 16*5af8263dSJohn Snowfrom .common import build_params, c_name, mcgen 177137a960SJohn Snowfrom .gen import QAPIGenCCode, QAPISchemaModularCVisitor, ifcontext 18fb0bc835SMarkus Armbruster 19fb0bc835SMarkus Armbruster 20fb0bc835SMarkus Armbrusterdef gen_command_decl(name, arg_type, boxed, ret_type): 21fb0bc835SMarkus Armbruster return mcgen(''' 22fb0bc835SMarkus Armbruster%(c_type)s qmp_%(c_name)s(%(params)s); 23fb0bc835SMarkus Armbruster''', 24fb0bc835SMarkus Armbruster c_type=(ret_type and ret_type.c_type()) or 'void', 25fb0bc835SMarkus Armbruster c_name=c_name(name), 26fb0bc835SMarkus Armbruster params=build_params(arg_type, boxed, 'Error **errp')) 27fb0bc835SMarkus Armbruster 28fb0bc835SMarkus Armbruster 29fb0bc835SMarkus Armbrusterdef gen_call(name, arg_type, boxed, ret_type): 30fb0bc835SMarkus Armbruster ret = '' 31fb0bc835SMarkus Armbruster 32fb0bc835SMarkus Armbruster argstr = '' 33fb0bc835SMarkus Armbruster if boxed: 34675b214bSMarkus Armbruster assert arg_type 35fb0bc835SMarkus Armbruster argstr = '&arg, ' 36fb0bc835SMarkus Armbruster elif arg_type: 37fb0bc835SMarkus Armbruster assert not arg_type.variants 38fb0bc835SMarkus Armbruster for memb in arg_type.members: 39fb0bc835SMarkus Armbruster if memb.optional: 40fb0bc835SMarkus Armbruster argstr += 'arg.has_%s, ' % c_name(memb.name) 41fb0bc835SMarkus Armbruster argstr += 'arg.%s, ' % c_name(memb.name) 42fb0bc835SMarkus Armbruster 43fb0bc835SMarkus Armbruster lhs = '' 44fb0bc835SMarkus Armbruster if ret_type: 45fb0bc835SMarkus Armbruster lhs = 'retval = ' 46fb0bc835SMarkus Armbruster 47fb0bc835SMarkus Armbruster ret = mcgen(''' 48fb0bc835SMarkus Armbruster 49fb0bc835SMarkus Armbruster %(lhs)sqmp_%(c_name)s(%(args)s&err); 50cdd2b228SMarkus Armbruster error_propagate(errp, err); 51fb0bc835SMarkus Armbruster''', 52fb0bc835SMarkus Armbruster c_name=c_name(name), args=argstr, lhs=lhs) 53fb0bc835SMarkus Armbruster if ret_type: 54fb0bc835SMarkus Armbruster ret += mcgen(''' 55fb0bc835SMarkus Armbruster if (err) { 56fb0bc835SMarkus Armbruster goto out; 57fb0bc835SMarkus Armbruster } 58fb0bc835SMarkus Armbruster 59cdd2b228SMarkus Armbruster qmp_marshal_output_%(c_name)s(retval, ret, errp); 60fb0bc835SMarkus Armbruster''', 61fb0bc835SMarkus Armbruster c_name=ret_type.c_name()) 62fb0bc835SMarkus Armbruster return ret 63fb0bc835SMarkus Armbruster 64fb0bc835SMarkus Armbruster 65fb0bc835SMarkus Armbrusterdef gen_marshal_output(ret_type): 66fb0bc835SMarkus Armbruster return mcgen(''' 67fb0bc835SMarkus Armbruster 68fb0bc835SMarkus Armbrusterstatic void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp) 69fb0bc835SMarkus Armbruster{ 70fb0bc835SMarkus Armbruster Visitor *v; 71fb0bc835SMarkus Armbruster 72fb0bc835SMarkus Armbruster v = qobject_output_visitor_new(ret_out); 73cdd2b228SMarkus Armbruster if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) { 74fb0bc835SMarkus Armbruster visit_complete(v, ret_out); 75fb0bc835SMarkus Armbruster } 76fb0bc835SMarkus Armbruster visit_free(v); 77fb0bc835SMarkus Armbruster v = qapi_dealloc_visitor_new(); 78fb0bc835SMarkus Armbruster visit_type_%(c_name)s(v, "unused", &ret_in, NULL); 79fb0bc835SMarkus Armbruster visit_free(v); 80fb0bc835SMarkus Armbruster} 81fb0bc835SMarkus Armbruster''', 82fb0bc835SMarkus Armbruster c_type=ret_type.c_type(), c_name=ret_type.c_name()) 83fb0bc835SMarkus Armbruster 84fb0bc835SMarkus Armbruster 85fb0bc835SMarkus Armbrusterdef build_marshal_proto(name): 86fb0bc835SMarkus Armbruster return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' 87fb0bc835SMarkus Armbruster % c_name(name)) 88fb0bc835SMarkus Armbruster 89fb0bc835SMarkus Armbruster 90fb0bc835SMarkus Armbrusterdef gen_marshal_decl(name): 91fb0bc835SMarkus Armbruster return mcgen(''' 92fb0bc835SMarkus Armbruster%(proto)s; 93fb0bc835SMarkus Armbruster''', 94fb0bc835SMarkus Armbruster proto=build_marshal_proto(name)) 95fb0bc835SMarkus Armbruster 96fb0bc835SMarkus Armbruster 97fb0bc835SMarkus Armbrusterdef gen_marshal(name, arg_type, boxed, ret_type): 98675b214bSMarkus Armbruster have_args = boxed or (arg_type and not arg_type.is_empty()) 99fb0bc835SMarkus Armbruster 100fb0bc835SMarkus Armbruster ret = mcgen(''' 101fb0bc835SMarkus Armbruster 102fb0bc835SMarkus Armbruster%(proto)s 103fb0bc835SMarkus Armbruster{ 104fb0bc835SMarkus Armbruster Error *err = NULL; 105cdd2b228SMarkus Armbruster bool ok = false; 1062061487bSMarkus Armbruster Visitor *v; 107fb0bc835SMarkus Armbruster''', 108fb0bc835SMarkus Armbruster proto=build_marshal_proto(name)) 109fb0bc835SMarkus Armbruster 110fb0bc835SMarkus Armbruster if ret_type: 111fb0bc835SMarkus Armbruster ret += mcgen(''' 112fb0bc835SMarkus Armbruster %(c_type)s retval; 113fb0bc835SMarkus Armbruster''', 114fb0bc835SMarkus Armbruster c_type=ret_type.c_type()) 115fb0bc835SMarkus Armbruster 116fb0bc835SMarkus Armbruster if have_args: 117fb0bc835SMarkus Armbruster ret += mcgen(''' 118fb0bc835SMarkus Armbruster %(c_name)s arg = {0}; 119fb0bc835SMarkus Armbruster''', 120fb0bc835SMarkus Armbruster c_name=arg_type.c_name()) 121fb0bc835SMarkus Armbruster 122fb0bc835SMarkus Armbruster ret += mcgen(''' 1232061487bSMarkus Armbruster 124fb0bc835SMarkus Armbruster v = qobject_input_visitor_new(QOBJECT(args)); 125cdd2b228SMarkus Armbruster if (!visit_start_struct(v, NULL, NULL, 0, errp)) { 126fb0bc835SMarkus Armbruster goto out; 127fb0bc835SMarkus Armbruster } 12889bf68f9SMarkus Armbruster''') 12989bf68f9SMarkus Armbruster 13089bf68f9SMarkus Armbruster if have_args: 13189bf68f9SMarkus Armbruster ret += mcgen(''' 132cdd2b228SMarkus Armbruster if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) { 133cdd2b228SMarkus Armbruster ok = visit_check_struct(v, errp); 134fb0bc835SMarkus Armbruster } 13589bf68f9SMarkus Armbruster''', 13689bf68f9SMarkus Armbruster c_arg_type=arg_type.c_name()) 13789bf68f9SMarkus Armbruster else: 13889bf68f9SMarkus Armbruster ret += mcgen(''' 139cdd2b228SMarkus Armbruster ok = visit_check_struct(v, errp); 14089bf68f9SMarkus Armbruster''') 14189bf68f9SMarkus Armbruster 14289bf68f9SMarkus Armbruster ret += mcgen(''' 143fb0bc835SMarkus Armbruster visit_end_struct(v, NULL); 144cdd2b228SMarkus Armbruster if (!ok) { 145fb0bc835SMarkus Armbruster goto out; 146fb0bc835SMarkus Armbruster } 14789bf68f9SMarkus Armbruster''') 148fb0bc835SMarkus Armbruster 149fb0bc835SMarkus Armbruster ret += gen_call(name, arg_type, boxed, ret_type) 150fb0bc835SMarkus Armbruster 151fb0bc835SMarkus Armbruster ret += mcgen(''' 152fb0bc835SMarkus Armbruster 153fb0bc835SMarkus Armbrusterout: 154fb0bc835SMarkus Armbruster visit_free(v); 155fb0bc835SMarkus Armbruster''') 156fb0bc835SMarkus Armbruster 157fb0bc835SMarkus Armbruster ret += mcgen(''' 158fb0bc835SMarkus Armbruster v = qapi_dealloc_visitor_new(); 159fb0bc835SMarkus Armbruster visit_start_struct(v, NULL, NULL, 0, NULL); 16089bf68f9SMarkus Armbruster''') 16189bf68f9SMarkus Armbruster 16289bf68f9SMarkus Armbruster if have_args: 16389bf68f9SMarkus Armbruster ret += mcgen(''' 16489bf68f9SMarkus Armbruster visit_type_%(c_arg_type)s_members(v, &arg, NULL); 16589bf68f9SMarkus Armbruster''', 16689bf68f9SMarkus Armbruster c_arg_type=arg_type.c_name()) 16789bf68f9SMarkus Armbruster 16889bf68f9SMarkus Armbruster ret += mcgen(''' 169fb0bc835SMarkus Armbruster visit_end_struct(v, NULL); 170fb0bc835SMarkus Armbruster visit_free(v); 17189bf68f9SMarkus Armbruster''') 172fb0bc835SMarkus Armbruster 173fb0bc835SMarkus Armbruster ret += mcgen(''' 174fb0bc835SMarkus Armbruster} 175fb0bc835SMarkus Armbruster''') 176fb0bc835SMarkus Armbruster return ret 177fb0bc835SMarkus Armbruster 178fb0bc835SMarkus Armbruster 17904f22362SKevin Wolfdef gen_register_command(name, success_response, allow_oob, allow_preconfig, 18004f22362SKevin Wolf coroutine): 181876c6751SPeter Xu options = [] 182876c6751SPeter Xu 183fb0bc835SMarkus Armbruster if not success_response: 184876c6751SPeter Xu options += ['QCO_NO_SUCCESS_RESP'] 185876c6751SPeter Xu if allow_oob: 186876c6751SPeter Xu options += ['QCO_ALLOW_OOB'] 187d6fe3d02SIgor Mammedov if allow_preconfig: 188d6fe3d02SIgor Mammedov options += ['QCO_ALLOW_PRECONFIG'] 18904f22362SKevin Wolf if coroutine: 19004f22362SKevin Wolf options += ['QCO_COROUTINE'] 191876c6751SPeter Xu 192876c6751SPeter Xu if not options: 193876c6751SPeter Xu options = ['QCO_NO_OPTIONS'] 194876c6751SPeter Xu 195876c6751SPeter Xu options = " | ".join(options) 196fb0bc835SMarkus Armbruster 197fb0bc835SMarkus Armbruster ret = mcgen(''' 198fb0bc835SMarkus Armbruster qmp_register_command(cmds, "%(name)s", 199fb0bc835SMarkus Armbruster qmp_marshal_%(c_name)s, %(opts)s); 200fb0bc835SMarkus Armbruster''', 201fb0bc835SMarkus Armbruster name=name, c_name=c_name(name), 202fb0bc835SMarkus Armbruster opts=options) 203fb0bc835SMarkus Armbruster return ret 204fb0bc835SMarkus Armbruster 205fb0bc835SMarkus Armbruster 206fb0bc835SMarkus Armbrusterdef gen_registry(registry, prefix): 207fb0bc835SMarkus Armbruster ret = mcgen(''' 208fb0bc835SMarkus Armbruster 209fb0bc835SMarkus Armbrustervoid %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds) 210fb0bc835SMarkus Armbruster{ 211fb0bc835SMarkus Armbruster QTAILQ_INIT(cmds); 212fb0bc835SMarkus Armbruster 213fb0bc835SMarkus Armbruster''', 214fb0bc835SMarkus Armbruster c_prefix=c_name(prefix, protect=False)) 215fb0bc835SMarkus Armbruster ret += registry 216fb0bc835SMarkus Armbruster ret += mcgen(''' 217fb0bc835SMarkus Armbruster} 218fb0bc835SMarkus Armbruster''') 219fb0bc835SMarkus Armbruster return ret 220fb0bc835SMarkus Armbruster 221fb0bc835SMarkus Armbruster 222252dc310SMarkus Armbrusterclass QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): 223fb0bc835SMarkus Armbruster 22471b3f045SMarkus Armbruster def __init__(self, prefix): 2252cae67bcSMarkus Armbruster super().__init__( 2262cae67bcSMarkus Armbruster prefix, 'qapi-commands', 2273bef3aaeSMarkus Armbruster ' * Schema-defined QAPI/QMP commands', None, __doc__) 228dddee4d7SMarkus Armbruster self._regy = QAPIGenCCode(None) 229252dc310SMarkus Armbruster self._visited_ret_types = {} 230252dc310SMarkus Armbruster 231dcac6471SMarkus Armbruster def _begin_user_module(self, name): 232252dc310SMarkus Armbruster self._visited_ret_types[self._genc] = set() 2339af23989SMarkus Armbruster commands = self._module_basename('qapi-commands', name) 2349af23989SMarkus Armbruster types = self._module_basename('qapi-types', name) 2359af23989SMarkus Armbruster visit = self._module_basename('qapi-visit', name) 23671b3f045SMarkus Armbruster self._genc.add(mcgen(''' 237fb0bc835SMarkus Armbruster#include "qemu/osdep.h" 238fb0bc835SMarkus Armbruster#include "qapi/visitor.h" 239fb0bc835SMarkus Armbruster#include "qapi/qmp/qdict.h" 240fb0bc835SMarkus Armbruster#include "qapi/qobject-output-visitor.h" 241fb0bc835SMarkus Armbruster#include "qapi/qobject-input-visitor.h" 242fb0bc835SMarkus Armbruster#include "qapi/dealloc-visitor.h" 243fb0bc835SMarkus Armbruster#include "qapi/error.h" 2449af23989SMarkus Armbruster#include "%(visit)s.h" 2459af23989SMarkus Armbruster#include "%(commands)s.h" 246fb0bc835SMarkus Armbruster 247fb0bc835SMarkus Armbruster''', 2489af23989SMarkus Armbruster commands=commands, visit=visit)) 24971b3f045SMarkus Armbruster self._genh.add(mcgen(''' 2509af23989SMarkus Armbruster#include "%(types)s.h" 251fb0bc835SMarkus Armbruster 252fb0bc835SMarkus Armbruster''', 2539af23989SMarkus Armbruster types=types)) 254fb0bc835SMarkus Armbruster 25571b3f045SMarkus Armbruster def visit_end(self): 25600ca24ffSMarkus Armbruster self._add_system_module('init', ' * QAPI Commands initialization') 25700ca24ffSMarkus Armbruster self._genh.add(mcgen(''' 25800ca24ffSMarkus Armbruster#include "qapi/qmp/dispatch.h" 25900ca24ffSMarkus Armbruster 260252dc310SMarkus Armbrustervoid %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); 261252dc310SMarkus Armbruster''', 262252dc310SMarkus Armbruster c_prefix=c_name(self._prefix, protect=False))) 26300ca24ffSMarkus Armbruster self._genc.preamble_add(mcgen(''' 26400ca24ffSMarkus Armbruster#include "qemu/osdep.h" 26500ca24ffSMarkus Armbruster#include "%(prefix)sqapi-commands.h" 26600ca24ffSMarkus Armbruster#include "%(prefix)sqapi-init-commands.h" 26700ca24ffSMarkus Armbruster''', 26800ca24ffSMarkus Armbruster prefix=self._prefix)) 26900ca24ffSMarkus Armbruster self._genc.add(gen_registry(self._regy.get_content(), self._prefix)) 27071b3f045SMarkus Armbruster 2717b3bc9e2SMarkus Armbruster def visit_command(self, name, info, ifcond, features, 2727b3bc9e2SMarkus Armbruster arg_type, ret_type, gen, success_response, boxed, 27304f22362SKevin Wolf allow_oob, allow_preconfig, coroutine): 27471b3f045SMarkus Armbruster if not gen: 27571b3f045SMarkus Armbruster return 2761f7b9f31SMarc-André Lureau # FIXME: If T is a user-defined type, the user is responsible 2771f7b9f31SMarc-André Lureau # for making this work, i.e. to make T's condition the 2781f7b9f31SMarc-André Lureau # conjunction of the T-returning commands' conditions. If T 2791f7b9f31SMarc-André Lureau # is a built-in type, this isn't possible: the 2801f7b9f31SMarc-André Lureau # qmp_marshal_output_T() will be generated unconditionally. 281252dc310SMarkus Armbruster if ret_type and ret_type not in self._visited_ret_types[self._genc]: 282252dc310SMarkus Armbruster self._visited_ret_types[self._genc].add(ret_type) 2831f7b9f31SMarc-André Lureau with ifcontext(ret_type.ifcond, 2841f7b9f31SMarc-André Lureau self._genh, self._genc, self._regy): 28571b3f045SMarkus Armbruster self._genc.add(gen_marshal_output(ret_type)) 2861f7b9f31SMarc-André Lureau with ifcontext(ifcond, self._genh, self._genc, self._regy): 2871f7b9f31SMarc-André Lureau self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type)) 28871b3f045SMarkus Armbruster self._genh.add(gen_marshal_decl(name)) 28971b3f045SMarkus Armbruster self._genc.add(gen_marshal(name, arg_type, boxed, ret_type)) 2901f7b9f31SMarc-André Lureau self._regy.add(gen_register_command(name, success_response, 29104f22362SKevin Wolf allow_oob, allow_preconfig, 29204f22362SKevin Wolf coroutine)) 29371b3f045SMarkus Armbruster 29471b3f045SMarkus Armbruster 29571b3f045SMarkus Armbrusterdef gen_commands(schema, output_dir, prefix): 296fb0bc835SMarkus Armbruster vis = QAPISchemaGenCommandVisitor(prefix) 297fb0bc835SMarkus Armbruster schema.visit(vis) 29871b3f045SMarkus Armbruster vis.write(output_dir) 299