123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650 |
- How to write monitor commands
- =============================
- This document is a step-by-step guide on how to write new QMP commands using
- the QAPI framework and HMP commands.
- This document doesn't discuss QMP protocol level details, nor does it dive
- into the QAPI framework implementation.
- For an in-depth introduction to the QAPI framework, please refer to
- :doc:`qapi-code-gen`. For the QMP protocol, see the
- :doc:`/interop/qmp-spec`.
- New commands may be implemented in QMP only. New HMP commands should be
- implemented on top of QMP. The typical HMP command wraps around an
- equivalent QMP command, but HMP convenience commands built from QMP
- building blocks are also fine. The long term goal is to make all
- existing HMP commands conform to this, to fully isolate HMP from the
- internals of QEMU. Refer to the `Writing a debugging aid returning
- unstructured text`_ section for further guidance on commands that
- would have traditionally been HMP only.
- Overview
- --------
- Generally speaking, the following steps should be taken in order to write a
- new QMP command.
- 1. Define the command and any types it needs in the appropriate QAPI
- schema module.
- 2. Write the QMP command itself, which is a regular C function. Preferably,
- the command should be exported by some QEMU subsystem. But it can also be
- added to the monitor/qmp-cmds.c file
- 3. At this point the command can be tested under the QMP protocol
- 4. Write the HMP command equivalent. This is not required and should only be
- done if it does make sense to have the functionality in HMP. The HMP command
- is implemented in terms of the QMP command
- The following sections will demonstrate each of the steps above. We will start
- very simple and get more complex as we progress.
- Testing
- -------
- For all the examples in the next sections, the test setup is the same and is
- shown here.
- First, QEMU should be started like this::
- # qemu-system-TARGET [...] \
- -chardev socket,id=qmp,port=4444,host=localhost,server=on \
- -mon chardev=qmp,mode=control,pretty=on
- Then, in a different terminal::
- $ telnet localhost 4444
- Trying 127.0.0.1...
- Connected to localhost.
- Escape character is '^]'.
- {
- "QMP": {
- "version": {
- "qemu": {
- "micro": 50,
- "minor": 2,
- "major": 8
- },
- "package": ...
- },
- "capabilities": [
- "oob"
- ]
- }
- }
- The above output is the QMP server saying you're connected. The server is
- actually in capabilities negotiation mode. To enter in command mode type::
- { "execute": "qmp_capabilities" }
- Then the server should respond::
- {
- "return": {
- }
- }
- Which is QMP's way of saying "the latest command executed OK and didn't return
- any data". Now you're ready to enter the QMP example commands as explained in
- the following sections.
- Writing a simple command: hello-world
- -------------------------------------
- That's the most simple QMP command that can be written. Usually, this kind of
- command carries some meaningful action in QEMU but here it will just print
- "Hello, world" to the standard output.
- Our command will be called "hello-world". It takes no arguments, nor does it
- return any data.
- 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
- schema entries are JSON objects. The line above will instruct the QAPI to
- generate any prototypes and the necessary code to marshal and unmarshal
- protocol data.
- The next step is to write the "hello-world" implementation. As explained
- earlier, it's preferable for commands to live in QEMU subsystems. But
- "hello-world" doesn't pertain to any, so we put its implementation in
- monitor/qmp-cmds.c::
- void qmp_hello_world(Error **errp)
- {
- printf("Hello, world!\n");
- }
- There are a few things to be noticed:
- 1. QMP command implementation functions must be prefixed with "qmp\_"
- 2. qmp_hello_world() returns void, this is in accordance with the fact that the
- command doesn't return any data
- 3. It takes an "Error \*\*" argument. This is required. Later we will see how to
- return errors and take additional arguments. The Error argument should not
- be touched if the command doesn't return errors
- 4. We won't add the function's prototype. That's automatically done by the QAPI
- 5. Printing to the terminal is discouraged for QMP commands, we do it here
- because it's the easiest way to demonstrate a QMP command
- You're done. Now build qemu, run it as suggested in the "Testing" section,
- and then type the following QMP command::
- { "execute": "hello-world" }
- Then check the terminal running qemu and look for the "Hello, world" string. If
- you don't see it then something went wrong.
- Arguments
- ~~~~~~~~~
- 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::
- ##
- # @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 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, bool has_times, int64_t times,
- Error **errp)
- {
- if (!message) {
- message = "Hello, world";
- }
- if (!has_times) {
- times = 1;
- }
- for (int i = 0; i < times; i++) {
- printf("%s\n", message);
- }
- }
- There are two important details to be noticed:
- 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
- Time to test our new version of the "hello-world" command. Build qemu, run it as
- described in the "Testing" section and then send two commands::
- { "execute": "hello-world" }
- {
- "return": {
- }
- }
- { "execute": "hello-world", "arguments": { "message": "We love qemu" } }
- {
- "return": {
- }
- }
- You should see "Hello, world" and "We love qemu" in the terminal running qemu,
- if you don't see these strings, then something went wrong.
- Errors
- ~~~~~~
- QMP commands should use the error interface exported by the error.h header
- file. Basically, most errors are set by calling the error_setg() function.
- Let's say we don't accept the string "message" to contain the word "love". If
- it does contain it, we want the "hello-world" command to return an error::
- void qmp_hello_world(const char *message, Error **errp)
- {
- if (message) {
- if (strstr(message, "love")) {
- error_setg(errp, "the word 'love' is not allowed");
- return;
- }
- printf("%s\n", message);
- } else {
- printf("Hello, world\n");
- }
- }
- The first argument to the error_setg() function is the Error pointer
- to pointer, which is passed to all QMP functions. The next argument is a human
- description of the error, this is a free-form printf-like string.
- Let's test the example above. Build qemu, run it as defined in the "Testing"
- section, and then issue the following command::
- { "execute": "hello-world", "arguments": { "message": "all you need is love" } }
- The QMP server's response should be::
- {
- "error": {
- "class": "GenericError",
- "desc": "the word 'love' is not allowed"
- }
- }
- Note that error_setg() produces a "GenericError" class. In general,
- all QMP errors should have that error class. There are two exceptions
- to this rule:
- 1. To support a management application's need to recognize a specific
- error for special handling
- 2. Backward compatibility
- 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.
- Implementing the HMP command
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Now that the QMP command is in place, we can also make it available in the human
- monitor (HMP).
- With the introduction of the QAPI, HMP commands make QMP calls. Most of the
- time HMP commands are simple wrappers. All HMP commands implementation exist in
- the monitor/hmp-cmds.c file.
- Here's the implementation of the "hello-world" HMP command::
- void hmp_hello_world(Monitor *mon, const QDict *qdict)
- {
- const char *message = qdict_get_try_str(qdict, "message");
- Error *err = NULL;
- qmp_hello_world(!!message, message, &err);
- if (hmp_handle_error(mon, err)) {
- return;
- }
- }
- Add it to monitor/hmp-cmds.c. Also, add its prototype to
- include/monitor/hmp.h.
- 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. 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
- 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,
- we should add it to the hmp-commands.hx file::
- {
- .name = "hello-world",
- .args_type = "message:s?",
- .params = "hello-world [message]",
- .help = "Print message to the standard output",
- .cmd = hmp_hello_world,
- },
- SRST
- ``hello_world`` *message*
- Print message to the standard output
- ERST
- To test this you have to open a user monitor and issue the "hello-world"
- command. It might be instructive to check the command's documentation with
- HMP's "help" command.
- Please, check the "-monitor" command-line option to know how to open a user
- monitor.
- Writing more complex commands
- -----------------------------
- A QMP command is capable of returning any data the QAPI supports like integers,
- strings, booleans, enumerations and user defined types.
- In this section we will focus on user defined types. Please, check the QAPI
- documentation for information about the other types.
- Modelling data in QAPI
- ~~~~~~~~~~~~~~~~~~~~~~
- For a QMP command that to be considered stable and supported long term,
- there is a requirement returned data should be explicitly modelled
- using fine-grained QAPI types. As a general guide, a caller of the QMP
- command should never need to parse individual returned data fields. If
- a field appears to need parsing, then it should be split into separate
- fields corresponding to each distinct data item. This should be the
- common case for any new QMP command that is intended to be used by
- machines, as opposed to exclusively human operators.
- Some QMP commands, however, are only intended as ad hoc debugging aids
- for human operators. While they may return large amounts of formatted
- 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 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
- command "x-query-registers". This returns a formatted dump of the
- architecture specific CPU state. The way the data is formatted varies
- across QEMU targets, is liable to change over time, and is only
- intended to be consumed as an opaque string by machines. Refer to the
- `Writing a debugging aid returning unstructured text`_ section for
- an illustration.
- User Defined Types
- ~~~~~~~~~~~~~~~~~~
- 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 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::
- ##
- # @OptionRomInfo:
- #
- # @filename: option ROM image file name
- #
- # @bootindex: option ROM's bootindex
- #
- # Since: 9.0
- ##
- { 'struct': 'OptionRomInfo',
- 'data': { 'filename': 'str', '*bootindex': 'int' } }
- 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-option-roms command::
- ##
- # @query-option-roms:
- #
- # Query information on ROMs loaded into the option ROM space.
- #
- # Returns: OptionRomInfo
- #
- # Since: 9.0
- ##
- { '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.
- Notice the syntax ['OptionRomInfo']". This should be read as "returns
- a list of OptionRomInfo".
- It's time to implement the qmp_query_option_roms() function. Add to
- monitor/qmp-cmds.c::
- OptionRomInfoList *qmp_query_option_roms(Error **errp)
- {
- OptionRomInfoList *info_list = NULL;
- OptionRomInfoList **tailp = &info_list;
- OptionRomInfo *info;
- 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);
- }
- return info_list;
- }
- There are a number of things to be noticed:
- 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
- Time to test the new command. Build qemu, run it as described in the "Testing"
- section and try this::
- { "execute": "query-option-rom" }
- {
- "return": [
- {
- "filename": "kvmvapic.bin"
- }
- ]
- }
- The HMP command
- ~~~~~~~~~~~~~~~
- Here's the HMP counterpart of the query-option-roms command::
- void hmp_info_option_roms(Monitor *mon, const QDict *qdict)
- {
- Error *err = NULL;
- OptionRomInfoList *info_list, *tail;
- OptionRomInfo *info;
- info_list = qmp_query_option_roms(&err);
- if (hmp_handle_error(mon, err)) {
- return;
- }
- 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);
- }
- monitor_printf(mon, "\n");
- }
- 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, 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 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',
- 'features': [ 'unstable' ] }
- 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, like this::
- HumanReadableText *qmp_x_query_roms(Error **errp)
- {
- g_autoptr(GString) buf = g_string_new("");
- Rom *rom;
- QTAILQ_FOREACH(rom, &roms, next) {
- g_string_append_printf("%s size=0x%06zx name=\"%s\"\n",
- memory_region_name(rom->mr),
- rom->romsize,
- rom->name);
- }
- 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
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 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 an implementation of the "info roms" HMP command::
- void hmp_info_roms(Monitor *mon, const QDict *qdict)
- {
- Error err = NULL;
- g_autoptr(HumanReadableText) info = qmp_x_query_roms(&err);
- if (hmp_handle_error(mon, err)) {
- return;
- }
- monitor_puts(mon, info->human_readable_text);
- }
- Also, you have to add the function's prototype to the hmp.h file.
- There's one last step to actually make the command available to
- monitor users, we should add it to the hmp-commands-info.hx file::
- {
- .name = "roms",
- .args_type = "",
- .params = "",
- .help = "show roms",
- .cmd = hmp_info_roms,
- },
- The case of writing a HMP info handler that calls a no-parameter QMP query
- command is quite common. To simplify the implementation there is a general
- purpose HMP info handler for this scenario. All that is required to expose
- a no-parameter QMP query command via HMP is to declare it using the
- '.cmd_info_hrt' field to point to the QMP handler, and leave the '.cmd'
- field NULL::
- {
- .name = "roms",
- .args_type = "",
- .params = "",
- .help = "show roms",
- .cmd_info_hrt = qmp_x_query_roms,
- },
- This is how the actual HMP command is done.
|