mirror of https://github.com/xemu-project/xemu.git
docs/devel/writing-monitor-commands: Repair a decade of rot
The tutorial doesn't match reality since at least 2013. Repairing it involves fixing the following issues: * Update for commit6d32717155
(aio / timers: Remove alarm timers): replace the broken examples. Instead of having one for returning a struct and another for returning a list of structs, do just one for the latter. This resolves the FIXME added in commite218052f92
(aio / timers: De-document -clock) back in 2014. * Update for commit895a2a80e0
(qapi: Use 'struct' instead of 'type' in schema). * Update for commit3313b6124b
(qapi: add qapi2texi script): add required documentation to the schema snippets, and drop section "Command Documentation". * Update for commita3c45b3e62
(qapi: New special feature flag "unstable"): supply the required feature, deemphasize the x- prefix. * Update for commitdd98234c05
(qapi: introduce x-query-roms QMP command): rephrase from "add new command" to "examine existing command". * Update for commit9492718b7c
(qapi misc: Elide redundant has_FOO in generated C): hello-world's message argument no longer comes with a has_message, add a second argument that does. * Update for moved and renamed files. While there, update QMP version output to current output. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-ID: <20240227115617.237875-2-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> [Whitespace tidied up, typo fixed]
This commit is contained in:
parent
e1f684ea2e
commit
59807e2098
|
@ -66,12 +66,13 @@ Then, in a different terminal::
|
|||
"version": {
|
||||
"qemu": {
|
||||
"micro": 50,
|
||||
"minor": 15,
|
||||
"major": 0
|
||||
"minor": 2,
|
||||
"major": 8
|
||||
},
|
||||
"package": ""
|
||||
"package": ...
|
||||
},
|
||||
"capabilities": [
|
||||
"oob"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +108,11 @@ The first step is defining the command in the appropriate QAPI schema
|
|||
module. We pick module qapi/misc.json, and add the following line at
|
||||
the bottom::
|
||||
|
||||
##
|
||||
# @hello-world:
|
||||
#
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'command': 'hello-world' }
|
||||
|
||||
The "command" keyword defines a new QMP command. It's an JSON object. All
|
||||
|
@ -148,37 +154,50 @@ you don't see it then something went wrong.
|
|||
Arguments
|
||||
~~~~~~~~~
|
||||
|
||||
Let's add an argument called "message" to our "hello-world" command. The new
|
||||
argument will contain the string to be printed to stdout. It's an optional
|
||||
argument, if it's not present we print our default "Hello, World" string.
|
||||
Let's add arguments to our "hello-world" command.
|
||||
|
||||
The first change we have to do is to modify the command specification in the
|
||||
schema file to the following::
|
||||
|
||||
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
||||
##
|
||||
# @hello-world:
|
||||
#
|
||||
# @message: message to be printed (default: "Hello, world!")
|
||||
#
|
||||
# @times: how many times to print the message (default: 1)
|
||||
#
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'command': 'hello-world',
|
||||
'data': { '*message': 'str', '*times': 'int' } }
|
||||
|
||||
Notice the new 'data' member in the schema. It's an JSON object whose each
|
||||
element is an argument to the command in question. Also notice the asterisk,
|
||||
it's used to mark the argument optional (that means that you shouldn't use it
|
||||
for mandatory arguments). Finally, 'str' is the argument's type, which
|
||||
stands for "string". The QAPI also supports integers, booleans, enumerations
|
||||
and user defined types.
|
||||
Notice the new 'data' member in the schema. It specifies an argument
|
||||
'message' of QAPI type 'str', and an argument 'times' of QAPI type
|
||||
'int'. Also notice the asterisk, it's used to mark the argument
|
||||
optional.
|
||||
|
||||
Now, let's update our C implementation in monitor/qmp-cmds.c::
|
||||
|
||||
void qmp_hello_world(const char *message, Error **errp)
|
||||
void qmp_hello_world(const char *message, bool has_times, int64_t times,
|
||||
Error **errp)
|
||||
{
|
||||
if (message) {
|
||||
if (!message) {
|
||||
message = "Hello, world";
|
||||
}
|
||||
if (!has_times) {
|
||||
times = 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < times; i++) {
|
||||
printf("%s\n", message);
|
||||
} else {
|
||||
printf("Hello, world\n");
|
||||
}
|
||||
}
|
||||
|
||||
There are two important details to be noticed:
|
||||
|
||||
1. All optional arguments are accompanied by a 'has\_' boolean, which is set
|
||||
if the optional argument is present or false otherwise
|
||||
1. Optional arguments other than pointers are accompanied by a 'has\_'
|
||||
boolean, which is set if the optional argument is present or false
|
||||
otherwise
|
||||
2. The C implementation signature must follow the schema's argument ordering,
|
||||
which is defined by the "data" member
|
||||
|
||||
|
@ -254,35 +273,6 @@ If the failure you want to report falls into one of the two cases above,
|
|||
use error_set() with a second argument of an ErrorClass value.
|
||||
|
||||
|
||||
Command Documentation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There's only one step missing to make "hello-world"'s implementation complete,
|
||||
and that's its documentation in the schema file.
|
||||
|
||||
There are many examples of such documentation in the schema file already, but
|
||||
here goes "hello-world"'s new entry for qapi/misc.json::
|
||||
|
||||
##
|
||||
# @hello-world:
|
||||
#
|
||||
# Print a client provided string to the standard output stream.
|
||||
#
|
||||
# @message: string to be printed
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Notes: if @message is not provided, the "Hello, world" string will
|
||||
# be printed instead
|
||||
#
|
||||
# Since: <next qemu stable release, eg. 1.0>
|
||||
##
|
||||
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
||||
|
||||
Please, note that the "Returns" clause is optional if a command doesn't return
|
||||
any data nor any errors.
|
||||
|
||||
|
||||
Implementing the HMP command
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -306,18 +296,20 @@ Here's the implementation of the "hello-world" HMP command::
|
|||
}
|
||||
}
|
||||
|
||||
Also, you have to add the function's prototype to the hmp.h file.
|
||||
Add it to monitor/hmp-cmds.c. Also, add its prototype to
|
||||
include/monitor/hmp.h.
|
||||
|
||||
There are three important points to be noticed:
|
||||
There are four important points to be noticed:
|
||||
|
||||
1. The "mon" and "qdict" arguments are mandatory for all HMP functions. The
|
||||
former is the monitor object. The latter is how the monitor passes
|
||||
arguments entered by the user to the command implementation
|
||||
2. hmp_hello_world() performs error checking. In this example we just call
|
||||
2. We chose not to support the "times" argument in HMP
|
||||
3. hmp_hello_world() performs error checking. In this example we just call
|
||||
hmp_handle_error() which prints a message to the user, but we could do
|
||||
more, like taking different actions depending on the error
|
||||
qmp_hello_world() returns
|
||||
3. The "err" variable must be initialized to NULL before performing the
|
||||
4. The "err" variable must be initialized to NULL before performing the
|
||||
QMP call
|
||||
|
||||
There's one last step to actually make the command available to monitor users,
|
||||
|
@ -372,7 +364,7 @@ data, it is not expected that machines will need to parse the result.
|
|||
The overhead of defining a fine grained QAPI type for the data may not
|
||||
be justified by the potential benefit. In such cases, it is permitted
|
||||
to have a command return a simple string that contains formatted data,
|
||||
however, it is mandatory for the command to use the 'x-' name prefix.
|
||||
however, it is mandatory for the command to be marked unstable.
|
||||
This indicates that the command is not guaranteed to be long term
|
||||
stable / liable to change in future and is not following QAPI design
|
||||
best practices. An example where this approach is taken is the QMP
|
||||
|
@ -386,302 +378,207 @@ an illustration.
|
|||
User Defined Types
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
FIXME This example needs to be redone after commit 6d32717
|
||||
For this example we will write the query-option-roms command, which
|
||||
returns information about ROMs loaded into the option ROM space. For
|
||||
more information about it, please check the "-option-rom" command-line
|
||||
option.
|
||||
|
||||
For this example we will write the query-alarm-clock command, which returns
|
||||
information about QEMU's timer alarm. For more information about it, please
|
||||
check the "-clock" command-line option.
|
||||
|
||||
We want to return two pieces of information. The first one is the alarm clock's
|
||||
name. The second one is when the next alarm will fire. The former information is
|
||||
returned as a string, the latter is an integer in nanoseconds (which is not
|
||||
very useful in practice, as the timer has probably already fired when the
|
||||
information reaches the client).
|
||||
|
||||
The best way to return that data is to create a new QAPI type, as shown below::
|
||||
For each option ROM, we want to return two pieces of information: the
|
||||
ROM image's file name, and its bootindex, if any. We need to create a
|
||||
new QAPI type for that, as shown below::
|
||||
|
||||
##
|
||||
# @QemuAlarmClock
|
||||
# @OptionRomInfo:
|
||||
#
|
||||
# QEMU alarm clock information.
|
||||
# @filename: option ROM image file name
|
||||
#
|
||||
# @clock-name: The alarm clock method's name.
|
||||
# @bootindex: option ROM's bootindex
|
||||
#
|
||||
# @next-deadline: The time (in nanoseconds) the next alarm will fire.
|
||||
#
|
||||
# Since: 1.0
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'type': 'QemuAlarmClock',
|
||||
'data': { 'clock-name': 'str', '*next-deadline': 'int' } }
|
||||
{ 'struct': 'OptionRomInfo',
|
||||
'data': { 'filename': 'str', '*bootindex': 'int' } }
|
||||
|
||||
The "type" keyword defines a new QAPI type. Its "data" member contains the
|
||||
type's members. In this example our members are the "clock-name" and the
|
||||
"next-deadline" one, which is optional.
|
||||
The "struct" keyword defines a new QAPI type. Its "data" member
|
||||
contains the type's members. In this example our members are
|
||||
"filename" and "bootindex". The latter is optional.
|
||||
|
||||
Now let's define the query-alarm-clock command::
|
||||
Now let's define the query-option-roms command::
|
||||
|
||||
##
|
||||
# @query-alarm-clock
|
||||
# @query-option-roms:
|
||||
#
|
||||
# Return information about QEMU's alarm clock.
|
||||
# Query information on ROMs loaded into the option ROM space.
|
||||
#
|
||||
# Returns a @QemuAlarmClock instance describing the alarm clock method
|
||||
# being currently used by QEMU (this is usually set by the '-clock'
|
||||
# command-line option).
|
||||
# Returns: OptionRomInfo
|
||||
#
|
||||
# Since: 1.0
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' }
|
||||
{ 'command': 'query-option-roms',
|
||||
'returns': ['OptionRomInfo'] }
|
||||
|
||||
Notice the "returns" keyword. As its name suggests, it's used to define the
|
||||
data returned by a command.
|
||||
|
||||
It's time to implement the qmp_query_alarm_clock() function, you can put it
|
||||
in the qemu-timer.c file::
|
||||
Notice the syntax ['OptionRomInfo']". This should be read as "returns
|
||||
a list of OptionRomInfo".
|
||||
|
||||
QemuAlarmClock *qmp_query_alarm_clock(Error **errp)
|
||||
It's time to implement the qmp_query_option_roms() function. Add to
|
||||
monitor/qmp-cmds.c::
|
||||
|
||||
OptionRomInfoList *qmp_query_option_roms(Error **errp)
|
||||
{
|
||||
QemuAlarmClock *clock;
|
||||
int64_t deadline;
|
||||
OptionRomInfoList *info_list = NULL;
|
||||
OptionRomInfoList **tailp = &info_list;
|
||||
OptionRomInfo *info;
|
||||
|
||||
clock = g_malloc0(sizeof(*clock));
|
||||
|
||||
deadline = qemu_next_alarm_deadline();
|
||||
if (deadline > 0) {
|
||||
clock->has_next_deadline = true;
|
||||
clock->next_deadline = deadline;
|
||||
for (int i = 0; i < nb_option_roms; i++) {
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->filename = g_strdup(option_rom[i].name);
|
||||
info->has_bootindex = option_rom[i].bootindex >= 0;
|
||||
if (info->has_bootindex) {
|
||||
info->bootindex = option_rom[i].bootindex;
|
||||
}
|
||||
QAPI_LIST_APPEND(tailp, info);
|
||||
}
|
||||
clock->clock_name = g_strdup(alarm_timer->name);
|
||||
|
||||
return clock;
|
||||
return info_list;
|
||||
}
|
||||
|
||||
There are a number of things to be noticed:
|
||||
|
||||
1. The QemuAlarmClock type is automatically generated by the QAPI framework,
|
||||
its members correspond to the type's specification in the schema file
|
||||
2. As specified in the schema file, the function returns a QemuAlarmClock
|
||||
instance and takes no arguments (besides the "errp" one, which is mandatory
|
||||
for all QMP functions)
|
||||
3. The "clock" variable (which will point to our QAPI type instance) is
|
||||
allocated by the regular g_malloc0() function. Note that we chose to
|
||||
initialize the memory to zero. This is recommended for all QAPI types, as
|
||||
it helps avoiding bad surprises (specially with booleans)
|
||||
4. Remember that "next_deadline" is optional? Non-pointer optional
|
||||
members have a 'has_TYPE_NAME' member that should be properly set
|
||||
1. Type OptionRomInfo is automatically generated by the QAPI framework,
|
||||
its members correspond to the type's specification in the schema
|
||||
file
|
||||
2. Type OptionRomInfoList is also generated. It's a singly linked
|
||||
list.
|
||||
3. As specified in the schema file, the function returns a
|
||||
OptionRomInfoList, and takes no arguments (besides the "errp" one,
|
||||
which is mandatory for all QMP functions)
|
||||
4. The returned object is dynamically allocated
|
||||
5. All strings are dynamically allocated. This is so because QAPI also
|
||||
generates a function to free its types and it cannot distinguish
|
||||
between dynamically or statically allocated strings
|
||||
6. Remember that "bootindex" is optional? As a non-pointer optional
|
||||
member, it comes with a 'has_bootindex' member that needs to be set
|
||||
by the implementation, as shown above
|
||||
5. Even static strings, such as "alarm_timer->name", should be dynamically
|
||||
allocated by the implementation. This is so because the QAPI also generates
|
||||
a function to free its types and it cannot distinguish between dynamically
|
||||
or statically allocated strings
|
||||
6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c
|
||||
|
||||
Time to test the new command. Build qemu, run it as described in the "Testing"
|
||||
section and try this::
|
||||
|
||||
{ "execute": "query-alarm-clock" }
|
||||
{ "execute": "query-option-rom" }
|
||||
{
|
||||
"return": {
|
||||
"next-deadline": 2368219,
|
||||
"clock-name": "dynticks"
|
||||
}
|
||||
"return": [
|
||||
{
|
||||
"filename": "kvmvapic.bin"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
The HMP command
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Here's the HMP counterpart of the query-alarm-clock command::
|
||||
Here's the HMP counterpart of the query-option-roms command::
|
||||
|
||||
void hmp_info_alarm_clock(Monitor *mon)
|
||||
void hmp_info_option_roms(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
QemuAlarmClock *clock;
|
||||
Error *err = NULL;
|
||||
OptionRomInfoList *info_list, *tail;
|
||||
OptionRomInfo *info;
|
||||
|
||||
clock = qmp_query_alarm_clock(&err);
|
||||
info_list = qmp_query_option_roms(&err);
|
||||
if (hmp_handle_error(mon, err)) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_name);
|
||||
if (clock->has_next_deadline) {
|
||||
monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseconds\n",
|
||||
clock->next_deadline);
|
||||
}
|
||||
|
||||
qapi_free_QemuAlarmClock(clock);
|
||||
}
|
||||
|
||||
It's important to notice that hmp_info_alarm_clock() calls
|
||||
qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock().
|
||||
For user defined types, the QAPI will generate a qapi_free_QAPI_TYPE_NAME()
|
||||
function and that's what you have to use to free the types you define and
|
||||
qapi_free_QAPI_TYPE_NAMEList() for list types (explained in the next section).
|
||||
If the QMP call returns a string, then you should g_free() to free it.
|
||||
|
||||
Also note that hmp_info_alarm_clock() performs error handling. That's not
|
||||
strictly required if you're sure the QMP function doesn't return errors, but
|
||||
it's good practice to always check for errors.
|
||||
|
||||
Another important detail is that HMP's "info" commands don't go into the
|
||||
hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined
|
||||
in the monitor/misc.c file. The entry for the "info alarmclock" follows::
|
||||
|
||||
{
|
||||
.name = "alarmclock",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show information about the alarm clock",
|
||||
.cmd = hmp_info_alarm_clock,
|
||||
},
|
||||
|
||||
To test this, run qemu and type "info alarmclock" in the user monitor.
|
||||
|
||||
|
||||
Returning Lists
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
For this example, we're going to return all available methods for the timer
|
||||
alarm, which is pretty much what the command-line option "-clock ?" does,
|
||||
except that we're also going to inform which method is in use.
|
||||
|
||||
This first step is to define a new type::
|
||||
|
||||
##
|
||||
# @TimerAlarmMethod
|
||||
#
|
||||
# Timer alarm method information.
|
||||
#
|
||||
# @method-name: The method's name.
|
||||
#
|
||||
# @current: true if this alarm method is currently in use, false otherwise
|
||||
#
|
||||
# Since: 1.0
|
||||
##
|
||||
{ 'type': 'TimerAlarmMethod',
|
||||
'data': { 'method-name': 'str', 'current': 'bool' } }
|
||||
|
||||
The command will be called "query-alarm-methods", here is its schema
|
||||
specification::
|
||||
|
||||
##
|
||||
# @query-alarm-methods
|
||||
#
|
||||
# Returns information about available alarm methods.
|
||||
#
|
||||
# Returns: a list of @TimerAlarmMethod for each method
|
||||
#
|
||||
# Since: 1.0
|
||||
##
|
||||
{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] }
|
||||
|
||||
Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this
|
||||
should be read as "returns a list of TimerAlarmMethod instances".
|
||||
|
||||
The C implementation follows::
|
||||
|
||||
TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
|
||||
{
|
||||
TimerAlarmMethodList *method_list = NULL;
|
||||
const struct qemu_alarm_timer *p;
|
||||
bool current = true;
|
||||
|
||||
for (p = alarm_timers; p->name; p++) {
|
||||
TimerAlarmMethod *value = g_malloc0(*value);
|
||||
value->method_name = g_strdup(p->name);
|
||||
value->current = current;
|
||||
QAPI_LIST_PREPEND(method_list, value);
|
||||
current = false;
|
||||
}
|
||||
|
||||
return method_list;
|
||||
}
|
||||
|
||||
The most important difference from the previous examples is the
|
||||
TimerAlarmMethodList type, which is automatically generated by the QAPI from
|
||||
the TimerAlarmMethod type.
|
||||
|
||||
Each list node is represented by a TimerAlarmMethodList instance. We have to
|
||||
allocate it, and that's done inside the for loop: the "info" pointer points to
|
||||
an allocated node. We also have to allocate the node's contents, which is
|
||||
stored in its "value" member. In our example, the "value" member is a pointer
|
||||
to an TimerAlarmMethod instance.
|
||||
|
||||
Notice that the "current" variable is used as "true" only in the first
|
||||
iteration of the loop. That's because the alarm timer method in use is the
|
||||
first element of the alarm_timers array. Also notice that QAPI lists are handled
|
||||
by hand and we return the head of the list.
|
||||
|
||||
Now Build qemu, run it as explained in the "Testing" section and try our new
|
||||
command::
|
||||
|
||||
{ "execute": "query-alarm-methods" }
|
||||
{
|
||||
"return": [
|
||||
{
|
||||
"current": false,
|
||||
"method-name": "unix"
|
||||
},
|
||||
{
|
||||
"current": true,
|
||||
"method-name": "dynticks"
|
||||
for (tail = info_list; tail; tail = tail->next) {
|
||||
info = tail->value;
|
||||
monitor_printf(mon, "%s", info->filename);
|
||||
if (info->has_bootindex) {
|
||||
monitor_printf(mon, " %" PRId64, info->bootindex);
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
The HMP counterpart is a bit more complex than previous examples because it
|
||||
has to traverse the list, it's shown below for reference::
|
||||
|
||||
void hmp_info_alarm_methods(Monitor *mon)
|
||||
{
|
||||
TimerAlarmMethodList *method_list, *method;
|
||||
Error *err = NULL;
|
||||
|
||||
method_list = qmp_query_alarm_methods(&err);
|
||||
if (hmp_handle_error(mon, err)) {
|
||||
return;
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
for (method = method_list; method; method = method->next) {
|
||||
monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ',
|
||||
method->value->method_name);
|
||||
}
|
||||
|
||||
qapi_free_TimerAlarmMethodList(method_list);
|
||||
qapi_free_OptionRomInfoList(info_list);
|
||||
}
|
||||
|
||||
It's important to notice that hmp_info_option_roms() calls
|
||||
qapi_free_OptionRomInfoList() to free the data returned by
|
||||
qmp_query_option_roms(). For user defined types, QAPI will generate a
|
||||
qapi_free_QAPI_TYPE_NAME() function, and that's what you have to use to
|
||||
free the types you define and qapi_free_QAPI_TYPE_NAMEList() for list
|
||||
types (explained in the next section). If the QMP function returns a
|
||||
string, then you should g_free() to free it.
|
||||
|
||||
Also note that hmp_info_option_roms() performs error handling. That's
|
||||
not strictly required when you're sure the QMP function doesn't return
|
||||
errors; you could instead pass it &error_abort then.
|
||||
|
||||
Another important detail is that HMP's "info" commands go into
|
||||
hmp-commands-info.hx, not hmp-commands.hx. The entry for the "info
|
||||
option-roms" follows::
|
||||
|
||||
{
|
||||
.name = "option-roms",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show roms",
|
||||
.cmd = hmp_info_option_roms,
|
||||
},
|
||||
SRST
|
||||
``info option-roms``
|
||||
Show the option ROMs.
|
||||
ERST
|
||||
|
||||
To test this, run qemu and type "info option-roms" in the user monitor.
|
||||
|
||||
|
||||
Writing a debugging aid returning unstructured text
|
||||
---------------------------------------------------
|
||||
|
||||
As discussed in section `Modelling data in QAPI`_, it is required that
|
||||
commands expecting machine usage be using fine-grained QAPI data types.
|
||||
The exception to this rule applies when the command is solely intended
|
||||
as a debugging aid and allows for returning unstructured text. This is
|
||||
commonly needed for query commands that report aspects of QEMU's
|
||||
internal state that are useful to human operators.
|
||||
as a debugging aid and allows for returning unstructured text, such as
|
||||
a query command that report aspects of QEMU's internal state that are
|
||||
useful only to human operators.
|
||||
|
||||
In this example we will consider a simplified variant of the HMP
|
||||
command ``info roms``. Following the earlier rules, this command will
|
||||
need to live under the ``x-`` name prefix, so its QMP implementation
|
||||
will be called ``x-query-roms``. It will have no parameters and will
|
||||
return a single text string::
|
||||
|
||||
{ 'struct': 'HumanReadableText',
|
||||
'data': { 'human-readable-text': 'str' } }
|
||||
In this example we will consider the existing QMP command
|
||||
``x-query-roms`` in qapi/machine.json. It has no parameters and
|
||||
returns a ``HumanReadableText``::
|
||||
|
||||
##
|
||||
# @x-query-roms:
|
||||
#
|
||||
# Query information on the registered ROMS
|
||||
#
|
||||
# Features:
|
||||
#
|
||||
# @unstable: This command is meant for debugging.
|
||||
#
|
||||
# Returns: registered ROMs
|
||||
#
|
||||
# Since: 6.2
|
||||
##
|
||||
{ 'command': 'x-query-roms',
|
||||
'returns': 'HumanReadableText' }
|
||||
'returns': 'HumanReadableText',
|
||||
'features': [ 'unstable' ] }
|
||||
|
||||
The ``HumanReadableText`` struct is intended to be used for all
|
||||
commands, under the ``x-`` name prefix that are returning unstructured
|
||||
text targeted at humans. It should never be used for commands outside
|
||||
the ``x-`` name prefix, as those should be using structured QAPI types.
|
||||
The ``HumanReadableText`` struct is defined in qapi/common.json as a
|
||||
struct with a string member. It is intended to be used for all
|
||||
commands that are returning unstructured text targeted at
|
||||
humans. These should all have feature 'unstable'. Note that the
|
||||
feature's documentation states why the command is unstable. We
|
||||
commonly use a ``x-`` command name prefix to make lack of stability
|
||||
obvious to human users.
|
||||
|
||||
Implementing the QMP command
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The QMP implementation will typically involve creating a ``GString``
|
||||
object and printing formatted data into it::
|
||||
object and printing formatted data into it, like this::
|
||||
|
||||
HumanReadableText *qmp_x_query_roms(Error **errp)
|
||||
{
|
||||
|
@ -698,6 +595,9 @@ object and printing formatted data into it::
|
|||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
The actual implementation emits more information. You can find it in
|
||||
hw/core/loader.c.
|
||||
|
||||
|
||||
Implementing the HMP command
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -706,7 +606,7 @@ Now that the QMP command is in place, we can also make it available in
|
|||
the human monitor (HMP) as shown in previous examples. The HMP
|
||||
implementations will all look fairly similar, as all they need do is
|
||||
invoke the QMP command and then print the resulting text or error
|
||||
message. Here's the implementation of the "info roms" HMP command::
|
||||
message. Here's an implementation of the "info roms" HMP command::
|
||||
|
||||
void hmp_info_roms(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
|
@ -746,3 +646,5 @@ field NULL::
|
|||
.help = "show roms",
|
||||
.cmd_info_hrt = qmp_x_query_roms,
|
||||
},
|
||||
|
||||
This is how the actual HMP command is done.
|
||||
|
|
Loading…
Reference in New Issue