Features/QCFG
Summary
Replace QemuOpts infrastructure with code generation leveraging QAPI.
Owner
- Name: Anthony Liguori
- Email: anthony@codemonkey.ws
Detailed Summary
Use code generator to generate demarshalling routines for command line arguments into structures. Pass structures to function calls to process QEMU command line.
For instance, consider the -vnc option. We would first add a type corresponding to the options -vnc takes:
{ 'type': 'VncConfig', 'data': { 'addr': 'str', '*x509': 'str', '*x509verify': 'str', '*password': 'bool', '*tls': 'bool', '*sasl': 'bool' } }
No major code generation changes are needed since this is a normal QMP schema type. We just need to add a new type of command for configuration entries:
{ 'config': 'vnc', 'type': 'VncConfig' }
Which generates:
void qcfg_vnc_config(VncConfig * config, Error **errp); static void qcfg_marshal_vnc(const QDict *args, Error **errp) { VncConfig *config; Error *local_err = NULL; config = qmp_unmarshal_type_VncConfig(args, &local_err); if (local_err) { error_propagate(errp, local_err); return; } qcfg_vnc(config, errp); qmp_free_vnc_config(config); } void qcfg_init(void) { qcfg_register_handler("vnc", &qcfg_marshal_vnc); }
We just need to take a command line string, marshal it into a QDict. The effect is automatic translation of -vnc :1 into a strongly typed function call to a function qcfg_vnc.
This function can also be reused by QMP trivially without going through multiple levels of marshaling and unmarshaling.
This provides a consistent way to document all options including the parameters that they take. It also provides a consistent way to do introspection of command line arguments.
This mechanism can also be applied to qdev which will allow for strongly typed qdev initialization functions that can also be trivially called from within QEMU.
For instance, for the serial device, we would do:
{ 'type': 'ISASerialConfig', 'data': { '*index': 'int', '*iobase': 'int', '*irq': 'int', 'chardev': 'CharDriverState' } }
This would translate to:
typedef struct ISASerialConfig { int64_t index; int64_t iobase; int64_t irq; struct CharDriverState * chr } ISASerialConfig;
This requires no modifications to the current code generation. To use this in qdev, we would add:
{ 'device': 'isa-serial', 'config': 'ISASerialConfig' }
This would generate the following function:
DeviceState *qdev_ctor_isa_serial(ISASerialConfig *config, Error **errp); static DeviceState *qdev_marshal_isa_serial(const QDict *args, Error **errp) { ISASerialConfig *config; Error *local_err = NULL; DeviceState *dev; config = qmp_unmarshal_type_ISASerialConfig(args, &local_err); if (local_err) { error_propagate(errp, local_err); return; } dev = qdev_ctor_isa_serial(config, errp); qmp_free_isa_serial_config(config); return dev; }
This lets QMP invoke qdev constructors directly without going remarshaling to strings. It also provides a convenient interface for QEMU to consume internally to create devices which is fully type safe.
It also provides a mechanism to do full introspection of qdev and a consistent way to provide documentation.
Open Questions
- Should we use a structure or marshal parameters as function calls?