aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-09-29 23:19:39 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-09-29 23:19:39 +0100
commite344ffe73bd77e7067099155cfd8bf42b07ed631 (patch)
treecf85f68f00ec2c004fccb574ce35d7aec7afdbdf
parentb150cb8f67bf491a49a1cb1c7da151eeacbdbcc9 (diff)
parent7cd77fb02b9a2117a56fed172f09a1820fcd6b0b (diff)
downloadqemu-e344ffe73bd77e7067099155cfd8bf42b07ed631.zip
qemu-e344ffe73bd77e7067099155cfd8bf42b07ed631.tar.gz
qemu-e344ffe73bd77e7067099155cfd8bf42b07ed631.tar.bz2
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2020-09-29' into staging
QAPI patches patches for 2020-09-29 # gpg: Signature made Tue 29 Sep 2020 20:54:51 BST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2020-09-29: (29 commits) Remove texinfo dependency from docker and CI configs configure: Drop texinfo requirement Remove Texinfo related line from git.orderfile scripts/texi2pod: Delete unused script docs/devel/qapi-code-gen.txt: Update to new rST backend conventions scripts/qapi: Remove texinfo generation support tests/qapi-schema: Add test of the rST QAPI doc-comment output meson.build: Make manuals depend on source to Sphinx extensions meson.build: Move SPHINX_ARGS to top level meson.build file tests/qapi-schema: Convert doc-good.json to rST-style strong/emphasis qga/qapi-schema.json: Add some headings qapi: Use rST markup for literal blocks docs/interop: Convert qemu-qmp-ref to rST docs/interop: Convert qemu-ga-ref to rST docs/sphinx: Add new qapi-doc Sphinx extension qapi/machine.json: Escape a literal '*' in doc comment scripts/qapi/parser.py: improve doc comment indent handling scripts/qapi: Move doc-comment whitespace stripping to doc.py tests/qapi/doc-good.json: Prepare for qapi-doc Sphinx extension qapi/block.json: Add newline after "Example:" for block-latency-histogram-set ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--.travis.yml1
-rw-r--r--MAINTAINERS6
-rw-r--r--Makefile2
-rw-r--r--block/iscsi.c2
-rwxr-xr-xconfigure12
-rw-r--r--docs/conf.py6
-rw-r--r--docs/devel/qapi-code-gen.txt98
-rw-r--r--docs/index.html.in2
-rw-r--r--docs/interop/conf.py4
-rw-r--r--docs/interop/index.rst2
-rw-r--r--docs/interop/qemu-ga-ref.rst13
-rw-r--r--docs/interop/qemu-ga-ref.texi80
-rw-r--r--docs/interop/qemu-qmp-ref.rst13
-rw-r--r--docs/interop/qemu-qmp-ref.texi80
-rw-r--r--docs/meson.build12
-rw-r--r--docs/sphinx/qapidoc.py549
-rw-r--r--hw/acpi/core.c2
-rw-r--r--hw/acpi/cpu.c2
-rw-r--r--hw/acpi/memory_hotplug.c3
-rw-r--r--hw/acpi/vmgenid.c2
-rw-r--r--hw/core/qdev-properties.c1
-rw-r--r--hw/i386/kvm/i8254.c2
-rw-r--r--hw/pci/pci-stub.c2
-rw-r--r--hw/pci/pci.c2
-rw-r--r--hw/virtio/virtio-balloon.c2
-rw-r--r--hw/virtio/virtio-mem-pci.c1
-rw-r--r--include/hw/acpi/acpi_dev_interface.h2
-rw-r--r--include/hw/mem/memory-device.h2
-rw-r--r--include/hw/rtc/mc146818rtc.h2
-rw-r--r--include/hw/virtio/virtio-pmem.h2
-rw-r--r--include/sysemu/balloon.h2
-rw-r--r--meson.build103
-rw-r--r--monitor/hmp-cmds.c2
-rw-r--r--monitor/qmp-cmds.c1
-rw-r--r--qapi/acpi.json141
-rw-r--r--qapi/block-core.json20
-rw-r--r--qapi/block.json12
-rw-r--r--qapi/machine.json392
-rw-r--r--qapi/meson.build6
-rw-r--r--qapi/migration.json108
-rw-r--r--qapi/misc.json820
-rw-r--r--qapi/pci.json316
-rw-r--r--qapi/qapi-schema.json8
-rw-r--r--qga/meson.build3
-rw-r--r--qga/qapi-schema.json8
-rwxr-xr-xscripts/checkpatch.pl2
-rw-r--r--scripts/coverity-scan/coverity-scan.docker1
-rw-r--r--scripts/git.orderfile1
-rw-r--r--scripts/qapi-gen.py2
-rw-r--r--scripts/qapi/doc.py301
-rw-r--r--scripts/qapi/gen.py7
-rw-r--r--scripts/qapi/parser.py105
-rwxr-xr-xscripts/texi2pod.pl536
-rw-r--r--softmmu/balloon.c2
-rw-r--r--storage-daemon/qapi/meson.build2
-rw-r--r--stubs/uuid.c2
-rw-r--r--stubs/vmgenid.c2
-rw-r--r--tests/docker/dockerfiles/debian10.docker1
-rw-r--r--tests/docker/dockerfiles/fedora.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu1804.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu2004.docker1
-rw-r--r--tests/qapi-schema/doc-bad-indent.err1
-rw-r--r--tests/qapi-schema/doc-bad-indent.json8
-rw-r--r--tests/qapi-schema/doc-bad-indent.out0
-rw-r--r--tests/qapi-schema/doc-good.json27
-rw-r--r--tests/qapi-schema/doc-good.out22
-rw-r--r--tests/qapi-schema/doc-good.rst5
-rw-r--r--tests/qapi-schema/doc-good.texi319
-rw-r--r--tests/qapi-schema/doc-good.txt288
-rw-r--r--tests/qapi-schema/meson.build63
71 files changed, 2108 insertions, 2444 deletions
diff --git a/.travis.yml b/.travis.yml
index c75221d..bd9a6fc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -192,7 +192,6 @@ jobs:
apt:
packages:
- python3-sphinx
- - texinfo
- perl
diff --git a/MAINTAINERS b/MAINTAINERS
index 5eed1e6..e1e8ae2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1617,6 +1617,7 @@ F: include/hw/pci/*
F: hw/misc/pci-testdev.c
F: hw/pci/*
F: hw/pci-bridge/*
+F: qapi/pci.json
F: docs/pci*
F: docs/specs/*pci*
F: default-configs/pci.mak
@@ -1632,6 +1633,7 @@ F: hw/acpi/*
F: hw/smbios/*
F: hw/i386/acpi-build.[hc]
F: hw/arm/virt-acpi-build.c
+F: qapi/acpi.json
F: tests/qtest/bios-tables-test*
F: tests/qtest/acpi-utils.[hc]
F: tests/data/acpi/
@@ -2385,6 +2387,7 @@ F: tests/test-qmp-*.c
F: tests/test-visitor-serialization.c
F: scripts/qapi-gen.py
F: scripts/qapi/*
+F: docs/sphinx/qapidoc.py
F: docs/devel/qapi*
T: git https://repo.or.cz/qemu/armbru.git qapi-next
@@ -2418,9 +2421,9 @@ M: Michael Roth <mdroth@linux.vnet.ibm.com>
S: Maintained
F: qga/
F: docs/interop/qemu-ga.rst
+F: docs/interop/qemu-ga-ref.rst
F: scripts/qemu-guest-agent/
F: tests/test-qga.c
-F: docs/interop/qemu-ga-ref.texi
T: git https://github.com/mdroth/qemu.git qga
QOM
@@ -3149,6 +3152,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: docs/conf.py
F: docs/*/conf.py
+F: docs/sphinx/
Miscellaneous
-------------
diff --git a/Makefile b/Makefile
index 7c60b9d..7b2655d 100644
--- a/Makefile
+++ b/Makefile
@@ -280,7 +280,7 @@ endif
$(call print-help,vm-help,Help about targets running tests inside VM)
@echo ''
@echo 'Documentation targets:'
- $(call print-help,html info pdf txt man,Build documentation in specified format)
+ $(call print-help,html man,Build documentation in specified format)
@echo ''
ifdef CONFIG_WIN32
@echo 'Windows targets:'
diff --git a/block/iscsi.c b/block/iscsi.c
index bd2122a..e30a7e3 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -42,7 +42,7 @@
#include "qemu/uuid.h"
#include "sysemu/replay.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-machine.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
#include "crypto/secret.h"
diff --git a/configure b/configure
index 8ee1581..ecc8e90 100755
--- a/configure
+++ b/configure
@@ -4874,14 +4874,14 @@ if test "$docs" != "no" ; then
else
sphinx_ok=no
fi
- if has makeinfo && has pod2man && test "$sphinx_ok" = "yes"; then
+ if test "$sphinx_ok" = "yes"; then
docs=yes
else
if test "$docs" = "yes" ; then
if has $sphinx_build && test "$sphinx_ok" != "yes"; then
echo "Warning: $sphinx_build exists but it is either too old or uses too old a Python version" >&2
fi
- feature_not_found "docs" "Install texinfo, Perl/perl-podlators and a Python 3 version of python-sphinx"
+ feature_not_found "docs" "Install a Python 3 version of python-sphinx"
fi
docs=no
fi
@@ -6301,13 +6301,6 @@ if test "$solaris" = "no" && test "$tsan" = "no"; then
fi
fi
-# test if pod2man has --utf8 option
-if pod2man --help | grep -q utf8; then
- POD2MAN="pod2man --utf8"
-else
- POD2MAN="pod2man"
-fi
-
# Use ASLR, no-SEH and DEP if available
if test "$mingw32" = "yes" ; then
for flag in --dynamicbase --no-seh --nxcompat; do
@@ -7456,7 +7449,6 @@ echo "HOST_DSOSUF=$HOST_DSOSUF" >> $config_host_mak
echo "LIBS_QGA=$libs_qga" >> $config_host_mak
echo "TASN1_LIBS=$tasn1_libs" >> $config_host_mak
echo "TASN1_CFLAGS=$tasn1_cflags" >> $config_host_mak
-echo "POD2MAN=$POD2MAN" >> $config_host_mak
if test "$gcov" = "yes" ; then
echo "CONFIG_GCOV=y" >> $config_host_mak
fi
diff --git a/docs/conf.py b/docs/conf.py
index 0dbd90d..606f623 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -52,7 +52,10 @@ except NameError:
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use an absolute path starting from qemu_docdir.
#
+# Our extensions are in docs/sphinx; the qapidoc extension requires
+# the QAPI modules from scripts/.
sys.path.insert(0, os.path.join(qemu_docdir, "sphinx"))
+sys.path.insert(0, os.path.join(qemu_docdir, "../scripts"))
# -- General configuration ------------------------------------------------
@@ -67,7 +70,7 @@ needs_sphinx = '1.6'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = ['kerneldoc', 'qmp_lexer', 'hxtool', 'depfile']
+extensions = ['kerneldoc', 'qmp_lexer', 'hxtool', 'depfile', 'qapidoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -241,3 +244,4 @@ texinfo_documents = [
kerneldoc_bin = os.path.join(qemu_docdir, '../scripts/kernel-doc')
kerneldoc_srctree = os.path.join(qemu_docdir, '..')
hxtool_srctree = os.path.join(qemu_docdir, '..')
+qapidoc_srctree = os.path.join(qemu_docdir, '..')
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 9eede44..5fc67c9 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -824,23 +824,37 @@ See below for more on definition documentation.
Free-form documentation may be used to provide additional text and
structuring content.
+==== Headings and subheadings ====
-==== Documentation markup ====
+A free-form documentation comment containing a line which starts with
+some '=' symbols and then a space defines a section heading:
-Comment text starting with '=' is a section title:
+ ##
+ # = This is a top level heading
+ #
+ # This is a free-form comment which will go under the
+ # top level heading.
+ ##
- # = Section title
+ ##
+ # == This is a second level heading
+ ##
-Double the '=' for a subsection title:
+A heading line must be the first line of the documentation
+comment block.
- # == Subsection title
+Section headings must always be correctly nested, so you can only
+define a third-level heading inside a second-level heading, and so on.
-Both are only permitted in free-form documentation.
+==== Documentation markup ====
-'|' denotes examples:
+Documentation comments can use most rST markup. In particular,
+a '::' literal block can be used for examples:
- # | Text of the example, may span
- # | multiple lines
+ # ::
+ #
+ # Text of the example, may span
+ # multiple lines
'*' starts an itemized list:
@@ -856,34 +870,33 @@ A decimal number followed by '.' starts a numbered list:
# multiple lines
# 2. Second item
-The actual number doesn't matter. You could even use '*' instead of
-'2.' for the second item.
+The actual number doesn't matter.
-Lists can't be nested. Blank lines are currently not supported within
-lists.
+Lists of either kind must be preceded and followed by a blank line.
+If a list item's text spans multiple lines, then the second and
+subsequent lines must be correctly indented to line up with the
+first character of the first line.
-Additional whitespace between the initial '#' and the comment text is
-permitted.
-
-*foo* and _foo_ are for strong and emphasis styles respectively (they
-do not work over multiple lines). @foo is used to reference a name in
-the schema.
+The usual '**strong**', '*emphasised*' and '``literal``' markup should
+be used. If you need a single literal '*' you will need to
+backslash-escape it. As an extension beyond the usual rST syntax, you
+can also use '@foo' to reference a name in the schema; this is
+rendered the same way as '``foo``'.
Example:
##
-# = Section
-# == Subsection
-#
-# Some text foo with *strong* and _emphasis_
+# Some text foo with **bold** and *emphasis*
# 1. with a list
# 2. like that
#
# And some code:
-# | $ echo foo
-# | -> do this
-# | <- get that
#
+# ::
+#
+# $ echo foo
+# -> do this
+# <- get that
##
@@ -901,6 +914,22 @@ commands and events), member (for structs and unions), branch (for
alternates), or value (for enums), and finally optional tagged
sections.
+Descriptions of arguments can span multiple lines. The description
+text can start on the line following the '@argname:', in which case it
+must not be indented at all. It can also start on the same line as
+the '@argname:'. In this case if it spans multiple lines then second
+and subsequent lines must be indented to line up with the first
+character of the first line of the description:
+
+# @argone:
+# This is a two line description
+# in the first style.
+#
+# @argtwo: This is a two line description
+# in the second style.
+
+The number of spaces between the ':' and the text is not significant.
+
FIXME: the parser accepts these things in almost any order.
FIXME: union branches should be described, too.
@@ -911,9 +940,26 @@ A tagged section starts with one of the following words:
"Note:"/"Notes:", "Since:", "Example"/"Examples", "Returns:", "TODO:".
The section ends with the start of a new section.
+The text of a section can start on a new line, in
+which case it must not be indented at all. It can also start
+on the same line as the 'Note:', 'Returns:', etc tag. In this
+case if it spans multiple lines then second and subsequent
+lines must be indented to match the first, in the same way as
+multiline argument descriptions.
+
A 'Since: x.y.z' tagged section lists the release that introduced the
definition.
+The text of a section can start on a new line, in
+which case it must not be indented at all. It can also start
+on the same line as the 'Note:', 'Returns:', etc tag. In this
+case if it spans multiple lines then second and subsequent
+lines must be indented to match the first.
+
+An 'Example' or 'Examples' section is automatically rendered
+entirely as literal fixed-width text. In other sections,
+the text is formatted, and rST markup can be used.
+
For example:
##
diff --git a/docs/index.html.in b/docs/index.html.in
index ca28047..33db439 100644
--- a/docs/index.html.in
+++ b/docs/index.html.in
@@ -12,8 +12,6 @@
<li><a href="tools/index.html">Tools Guide</a></li>
<li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
<li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
- <li><a href="interop/qemu-qmp-ref.html">QMP Reference Manual</a></li>
- <li><a href="interop/qemu-ga-ref.html">Guest Agent Protocol Reference</a></li>
</ul>
</body>
</html>
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
index 42ce7e3..2634ca3 100644
--- a/docs/interop/conf.py
+++ b/docs/interop/conf.py
@@ -19,4 +19,8 @@ html_theme_options['description'] = u'System Emulation Management and Interopera
man_pages = [
('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
+ ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
+ [], 7),
+ ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
+ [], 7),
]
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
index 006f986..cd78d67 100644
--- a/docs/interop/index.rst
+++ b/docs/interop/index.rst
@@ -18,6 +18,8 @@ Contents:
live-block-operations
pr-helper
qemu-ga
+ qemu-ga-ref
+ qemu-qmp-ref
vhost-user
vhost-user-gpu
vhost-vdpa
diff --git a/docs/interop/qemu-ga-ref.rst b/docs/interop/qemu-ga-ref.rst
new file mode 100644
index 0000000..3f1c4f9
--- /dev/null
+++ b/docs/interop/qemu-ga-ref.rst
@@ -0,0 +1,13 @@
+QEMU Guest Agent Protocol Reference
+===================================
+
+..
+ TODO: the old Texinfo manual used to note that this manual
+ is GPL-v2-or-later. We should make that reader-visible
+ both here and in our Sphinx manuals more generally.
+
+..
+ TODO: display the QEMU version, both here and in our Sphinx manuals
+ more generally.
+
+.. qapi-doc:: qga/qapi-schema.json
diff --git a/docs/interop/qemu-ga-ref.texi b/docs/interop/qemu-ga-ref.texi
deleted file mode 100644
index a23cc2e..0000000
--- a/docs/interop/qemu-ga-ref.texi
+++ /dev/null
@@ -1,80 +0,0 @@
-\input texinfo
-@setfilename qemu-ga-ref.info
-
-@include version.texi
-
-@exampleindent 0
-@paragraphindent 0
-
-@settitle QEMU Guest Agent Protocol Reference
-
-@iftex
-@center @image{docs/qemu_logo}
-@end iftex
-
-@copying
-This is the QEMU Guest Agent Protocol reference manual.
-
-Copyright @copyright{} 2016 The QEMU Project developers
-
-@quotation
-This manual is free documentation: you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation, either version 2 of the
-License, or (at your option) any later version.
-
-This manual is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this manual. If not, see http://www.gnu.org/licenses/.
-@end quotation
-@end copying
-
-@dircategory QEMU
-@direntry
-* QEMU-GA-Ref: (qemu-ga-ref). QEMU Guest Agent Protocol Reference
-@end direntry
-
-@titlepage
-@title Guest Agent Protocol Reference Manual
-@subtitle QEMU version @value{VERSION}
-@page
-@vskip 0pt plus 1filll
-@insertcopying
-@end titlepage
-
-@contents
-
-@ifnottex
-@node Top
-@top QEMU Guest Agent protocol reference
-@end ifnottex
-
-@menu
-* API Reference::
-* Commands and Events Index::
-* Data Types Index::
-@end menu
-
-@node API Reference
-@chapter API Reference
-
-@c for texi2pod:
-@c man begin DESCRIPTION
-
-@include qga/qga-qapi-doc.texi
-
-@c man end
-
-@node Commands and Events Index
-@unnumbered Commands and Events Index
-@printindex fn
-
-@node Data Types Index
-@unnumbered Data Types Index
-@printindex tp
-
-@bye
diff --git a/docs/interop/qemu-qmp-ref.rst b/docs/interop/qemu-qmp-ref.rst
new file mode 100644
index 0000000..c8abaaf
--- /dev/null
+++ b/docs/interop/qemu-qmp-ref.rst
@@ -0,0 +1,13 @@
+QEMU QMP Reference Manual
+=========================
+
+..
+ TODO: the old Texinfo manual used to note that this manual
+ is GPL-v2-or-later. We should make that reader-visible
+ both here and in our Sphinx manuals more generally.
+
+..
+ TODO: display the QEMU version, both here and in our Sphinx manuals
+ more generally.
+
+.. qapi-doc:: qapi/qapi-schema.json
diff --git a/docs/interop/qemu-qmp-ref.texi b/docs/interop/qemu-qmp-ref.texi
deleted file mode 100644
index ea1d7fe..0000000
--- a/docs/interop/qemu-qmp-ref.texi
+++ /dev/null
@@ -1,80 +0,0 @@
-\input texinfo
-@setfilename qemu-qmp-ref.info
-
-@include version.texi
-
-@exampleindent 0
-@paragraphindent 0
-
-@settitle QEMU QMP Reference Manual
-
-@iftex
-@center @image{docs/qemu_logo}
-@end iftex
-
-@copying
-This is the QEMU QMP reference manual.
-
-Copyright @copyright{} 2016 The QEMU Project developers
-
-@quotation
-This manual is free documentation: you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation, either version 2 of the
-License, or (at your option) any later version.
-
-This manual is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this manual. If not, see http://www.gnu.org/licenses/.
-@end quotation
-@end copying
-
-@dircategory QEMU
-@direntry
-* QEMU-QMP-Ref: (qemu-qmp-ref). QEMU QMP Reference Manual
-@end direntry
-
-@titlepage
-@title QMP Reference Manual
-@subtitle QEMU version @value{VERSION}
-@page
-@vskip 0pt plus 1filll
-@insertcopying
-@end titlepage
-
-@contents
-
-@ifnottex
-@node Top
-@top QEMU QMP reference
-@end ifnottex
-
-@menu
-* API Reference::
-* Commands and Events Index::
-* Data Types Index::
-@end menu
-
-@node API Reference
-@chapter API Reference
-
-@c for texi2pod:
-@c man begin DESCRIPTION
-
-@include qapi/qapi-doc.texi
-
-@c man end
-
-@node Commands and Events Index
-@unnumbered Commands and Events Index
-@printindex fn
-
-@node Data Types Index
-@unnumbered Data Types Index
-@printindex tp
-
-@bye
diff --git a/docs/meson.build b/docs/meson.build
index 50f3673..0340d48 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -1,11 +1,3 @@
-SPHINX_ARGS = [config_host['SPHINX_BUILD'],
- '-Dversion=' + meson.project_version(),
- '-Drelease=' + config_host['PKGVERSION']]
-
-if get_option('werror')
- SPHINX_ARGS += [ '-W' ]
-endif
-
if build_docs
configure_file(output: 'index.html',
input: files('index.html.in'),
@@ -15,6 +7,8 @@ if build_docs
man_pages = {
'interop' : {
'qemu-ga.8': (have_tools ? 'man8' : ''),
+ 'qemu-ga-ref.7': 'man7',
+ 'qemu-qmp-ref.7': 'man7',
},
'tools': {
'qemu-img.1': (have_tools ? 'man1' : ''),
@@ -42,6 +36,7 @@ if build_docs
output: [manual + '.stamp'],
input: [files('conf.py'), files(manual / 'conf.py')],
depfile: manual + '.d',
+ depend_files: sphinx_extn_depends,
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
'-Ddepfile_stamp=@OUTPUT0@',
'-b', 'html', '-d', private_dir,
@@ -69,5 +64,6 @@ if build_docs
endif
endforeach
alias_target('sphinxdocs', sphinxdocs)
+ alias_target('html', sphinxdocs)
alias_target('man', sphinxmans)
endif
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
new file mode 100644
index 0000000..6944ffa
--- /dev/null
+++ b/docs/sphinx/qapidoc.py
@@ -0,0 +1,549 @@
+# coding=utf-8
+#
+# QEMU qapidoc QAPI file parsing extension
+#
+# Copyright (c) 2020 Linaro
+#
+# This work is licensed under the terms of the GNU GPLv2 or later.
+# See the COPYING file in the top-level directory.
+
+"""
+qapidoc is a Sphinx extension that implements the qapi-doc directive
+
+The purpose of this extension is to read the documentation comments
+in QAPI schema files, and insert them all into the current document.
+
+It implements one new rST directive, "qapi-doc::".
+Each qapi-doc:: directive takes one argument, which is the
+pathname of the schema file to process, relative to the source tree.
+
+The docs/conf.py file must set the qapidoc_srctree config value to
+the root of the QEMU source tree.
+
+The Sphinx documentation on writing extensions is at:
+https://www.sphinx-doc.org/en/master/development/index.html
+"""
+
+import os
+import re
+
+from docutils import nodes
+from docutils.statemachine import ViewList
+from docutils.parsers.rst import directives, Directive
+from sphinx.errors import ExtensionError
+from sphinx.util.nodes import nested_parse_with_titles
+import sphinx
+from qapi.gen import QAPISchemaVisitor
+from qapi.schema import QAPIError, QAPISemError, QAPISchema
+
+
+# Sphinx up to 1.6 uses AutodocReporter; 1.7 and later
+# use switch_source_input. Check borrowed from kerneldoc.py.
+Use_SSI = sphinx.__version__[:3] >= '1.7'
+if Use_SSI:
+ from sphinx.util.docutils import switch_source_input
+else:
+ from sphinx.ext.autodoc import AutodocReporter
+
+
+__version__ = '1.0'
+
+
+# Function borrowed from pydash, which is under the MIT license
+def intersperse(iterable, separator):
+ """Yield the members of *iterable* interspersed with *separator*."""
+ iterable = iter(iterable)
+ yield next(iterable)
+ for item in iterable:
+ yield separator
+ yield item
+
+
+class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
+ """A QAPI schema visitor which generates docutils/Sphinx nodes
+
+ This class builds up a tree of docutils/Sphinx nodes corresponding
+ to documentation for the various QAPI objects. To use it, first
+ create a QAPISchemaGenRSTVisitor object, and call its
+ visit_begin() method. Then you can call one of the two methods
+ 'freeform' (to add documentation for a freeform documentation
+ chunk) or 'symbol' (to add documentation for a QAPI symbol). These
+ will cause the visitor to build up the tree of document
+ nodes. Once you've added all the documentation via 'freeform' and
+ 'symbol' method calls, you can call 'get_document_nodes' to get
+ the final list of document nodes (in a form suitable for returning
+ from a Sphinx directive's 'run' method).
+ """
+ def __init__(self, sphinx_directive):
+ self._cur_doc = None
+ self._sphinx_directive = sphinx_directive
+ self._top_node = nodes.section()
+ self._active_headings = [self._top_node]
+
+ def _make_dlitem(self, term, defn):
+ """Return a dlitem node with the specified term and definition.
+
+ term should be a list of Text and literal nodes.
+ defn should be one of:
+ - a string, which will be handed to _parse_text_into_node
+ - a list of Text and literal nodes, which will be put into
+ a paragraph node
+ """
+ dlitem = nodes.definition_list_item()
+ dlterm = nodes.term('', '', *term)
+ dlitem += dlterm
+ if defn:
+ dldef = nodes.definition()
+ if isinstance(defn, list):
+ dldef += nodes.paragraph('', '', *defn)
+ else:
+ self._parse_text_into_node(defn, dldef)
+ dlitem += dldef
+ return dlitem
+
+ def _make_section(self, title):
+ """Return a section node with optional title"""
+ section = nodes.section(ids=[self._sphinx_directive.new_serialno()])
+ if title:
+ section += nodes.title(title, title)
+ return section
+
+ def _nodes_for_ifcond(self, ifcond, with_if=True):
+ """Return list of Text, literal nodes for the ifcond
+
+ Return a list which gives text like ' (If: cond1, cond2, cond3)', where
+ the conditions are in literal-text and the commas are not.
+ If with_if is False, we don't return the "(If: " and ")".
+ """
+ condlist = intersperse([nodes.literal('', c) for c in ifcond],
+ nodes.Text(', '))
+ if not with_if:
+ return condlist
+
+ nodelist = [nodes.Text(' ('), nodes.strong('', 'If: ')]
+ nodelist.extend(condlist)
+ nodelist.append(nodes.Text(')'))
+ return nodelist
+
+ def _nodes_for_one_member(self, member):
+ """Return list of Text, literal nodes for this member
+
+ Return a list of doctree nodes which give text like
+ 'name: type (optional) (If: ...)' suitable for use as the
+ 'term' part of a definition list item.
+ """
+ term = [nodes.literal('', member.name)]
+ if member.type.doc_type():
+ term.append(nodes.Text(': '))
+ term.append(nodes.literal('', member.type.doc_type()))
+ if member.optional:
+ term.append(nodes.Text(' (optional)'))
+ if member.ifcond:
+ term.extend(self._nodes_for_ifcond(member.ifcond))
+ return term
+
+ def _nodes_for_variant_when(self, variants, variant):
+ """Return list of Text, literal nodes for variant 'when' clause
+
+ Return a list of doctree nodes which give text like
+ 'when tagname is variant (If: ...)' suitable for use in
+ the 'variants' part of a definition list.
+ """
+ term = [nodes.Text(' when '),
+ nodes.literal('', variants.tag_member.name),
+ nodes.Text(' is '),
+ nodes.literal('', '"%s"' % variant.name)]
+ if variant.ifcond:
+ term.extend(self._nodes_for_ifcond(variant.ifcond))
+ return term
+
+ def _nodes_for_members(self, doc, what, base=None, variants=None):
+ """Return list of doctree nodes for the table of members"""
+ dlnode = nodes.definition_list()
+ for section in doc.args.values():
+ term = self._nodes_for_one_member(section.member)
+ # TODO drop fallbacks when undocumented members are outlawed
+ if section.text:
+ defn = section.text
+ elif (variants and variants.tag_member == section.member
+ and not section.member.type.doc_type()):
+ values = section.member.type.member_names()
+ defn = [nodes.Text('One of ')]
+ defn.extend(intersperse([nodes.literal('', v) for v in values],
+ nodes.Text(', ')))
+ else:
+ defn = [nodes.Text('Not documented')]
+
+ dlnode += self._make_dlitem(term, defn)
+
+ if base:
+ dlnode += self._make_dlitem([nodes.Text('The members of '),
+ nodes.literal('', base.doc_type())],
+ None)
+
+ if variants:
+ for v in variants.variants:
+ if v.type.is_implicit():
+ assert not v.type.base and not v.type.variants
+ for m in v.type.local_members:
+ term = self._nodes_for_one_member(m)
+ term.extend(self._nodes_for_variant_when(variants, v))
+ dlnode += self._make_dlitem(term, None)
+ else:
+ term = [nodes.Text('The members of '),
+ nodes.literal('', v.type.doc_type())]
+ term.extend(self._nodes_for_variant_when(variants, v))
+ dlnode += self._make_dlitem(term, None)
+
+ if not dlnode.children:
+ return []
+
+ section = self._make_section(what)
+ section += dlnode
+ return [section]
+
+ def _nodes_for_enum_values(self, doc):
+ """Return list of doctree nodes for the table of enum values"""
+ seen_item = False
+ dlnode = nodes.definition_list()
+ for section in doc.args.values():
+ termtext = [nodes.literal('', section.member.name)]
+ if section.member.ifcond:
+ termtext.extend(self._nodes_for_ifcond(section.member.ifcond))
+ # TODO drop fallbacks when undocumented members are outlawed
+ if section.text:
+ defn = section.text
+ else:
+ defn = [nodes.Text('Not documented')]
+
+ dlnode += self._make_dlitem(termtext, defn)
+ seen_item = True
+
+ if not seen_item:
+ return []
+
+ section = self._make_section('Values')
+ section += dlnode
+ return [section]
+
+ def _nodes_for_arguments(self, doc, boxed_arg_type):
+ """Return list of doctree nodes for the arguments section"""
+ if boxed_arg_type:
+ assert not doc.args
+ section = self._make_section('Arguments')
+ dlnode = nodes.definition_list()
+ dlnode += self._make_dlitem(
+ [nodes.Text('The members of '),
+ nodes.literal('', boxed_arg_type.name)],
+ None)
+ section += dlnode
+ return [section]
+
+ return self._nodes_for_members(doc, 'Arguments')
+
+ def _nodes_for_features(self, doc):
+ """Return list of doctree nodes for the table of features"""
+ seen_item = False
+ dlnode = nodes.definition_list()
+ for section in doc.features.values():
+ dlnode += self._make_dlitem([nodes.literal('', section.name)],
+ section.text)
+ seen_item = True
+
+ if not seen_item:
+ return []
+
+ section = self._make_section('Features')
+ section += dlnode
+ return [section]
+
+ def _nodes_for_example(self, exampletext):
+ """Return list of doctree nodes for a code example snippet"""
+ return [nodes.literal_block(exampletext, exampletext)]
+
+ def _nodes_for_sections(self, doc):
+ """Return list of doctree nodes for additional sections"""
+ nodelist = []
+ for section in doc.sections:
+ snode = self._make_section(section.name)
+ if section.name and section.name.startswith('Example'):
+ snode += self._nodes_for_example(section.text)
+ else:
+ self._parse_text_into_node(section.text, snode)
+ nodelist.append(snode)
+ return nodelist
+
+ def _nodes_for_if_section(self, ifcond):
+ """Return list of doctree nodes for the "If" section"""
+ nodelist = []
+ if ifcond:
+ snode = self._make_section('If')
+ snode += self._nodes_for_ifcond(ifcond, with_if=False)
+ nodelist.append(snode)
+ return nodelist
+
+ def _add_doc(self, typ, sections):
+ """Add documentation for a command/object/enum...
+
+ We assume we're documenting the thing defined in self._cur_doc.
+ typ is the type of thing being added ("Command", "Object", etc)
+
+ sections is a list of nodes for sections to add to the definition.
+ """
+
+ doc = self._cur_doc
+ snode = nodes.section(ids=[self._sphinx_directive.new_serialno()])
+ snode += nodes.title('', '', *[nodes.literal(doc.symbol, doc.symbol),
+ nodes.Text(' (' + typ + ')')])
+ self._parse_text_into_node(doc.body.text, snode)
+ for s in sections:
+ if s is not None:
+ snode += s
+ self._add_node_to_current_heading(snode)
+
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
+ doc = self._cur_doc
+ self._add_doc('Enum',
+ self._nodes_for_enum_values(doc)
+ + self._nodes_for_features(doc)
+ + self._nodes_for_sections(doc)
+ + self._nodes_for_if_section(ifcond))
+
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
+ doc = self._cur_doc
+ if base and base.is_implicit():
+ base = None
+ self._add_doc('Object',
+ self._nodes_for_members(doc, 'Members', base, variants)
+ + self._nodes_for_features(doc)
+ + self._nodes_for_sections(doc)
+ + self._nodes_for_if_section(ifcond))
+
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
+ doc = self._cur_doc
+ self._add_doc('Alternate',
+ self._nodes_for_members(doc, 'Members')
+ + self._nodes_for_features(doc)
+ + self._nodes_for_sections(doc)
+ + self._nodes_for_if_section(ifcond))
+
+ def visit_command(self, name, info, ifcond, features, arg_type,
+ ret_type, gen, success_response, boxed, allow_oob,
+ allow_preconfig):
+ doc = self._cur_doc
+ self._add_doc('Command',
+ self._nodes_for_arguments(doc,
+ arg_type if boxed else None)
+ + self._nodes_for_features(doc)
+ + self._nodes_for_sections(doc)
+ + self._nodes_for_if_section(ifcond))
+
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
+ doc = self._cur_doc
+ self._add_doc('Event',
+ self._nodes_for_arguments(doc,
+ arg_type if boxed else None)
+ + self._nodes_for_features(doc)
+ + self._nodes_for_sections(doc)
+ + self._nodes_for_if_section(ifcond))
+
+ def symbol(self, doc, entity):
+ """Add documentation for one symbol to the document tree
+
+ This is the main entry point which causes us to add documentation
+ nodes for a symbol (which could be a 'command', 'object', 'event',
+ etc). We do this by calling 'visit' on the schema entity, which
+ will then call back into one of our visit_* methods, depending
+ on what kind of thing this symbol is.
+ """
+ self._cur_doc = doc
+ entity.visit(self)
+ self._cur_doc = None
+
+ def _start_new_heading(self, heading, level):
+ """Start a new heading at the specified heading level
+
+ Create a new section whose title is 'heading' and which is placed
+ in the docutils node tree as a child of the most recent level-1
+ heading. Subsequent document sections (commands, freeform doc chunks,
+ etc) will be placed as children of this new heading section.
+ """
+ if len(self._active_headings) < level:
+ raise QAPISemError(self._cur_doc.info,
+ 'Level %d subheading found outside a '
+ 'level %d heading'
+ % (level, level - 1))
+ snode = self._make_section(heading)
+ self._active_headings[level - 1] += snode
+ self._active_headings = self._active_headings[:level]
+ self._active_headings.append(snode)
+
+ def _add_node_to_current_heading(self, node):
+ """Add the node to whatever the current active heading is"""
+ self._active_headings[-1] += node
+
+ def freeform(self, doc):
+ """Add a piece of 'freeform' documentation to the document tree
+
+ A 'freeform' document chunk doesn't relate to any particular
+ symbol (for instance, it could be an introduction).
+
+ If the freeform document starts with a line of the form
+ '= Heading text', this is a section or subsection heading, with
+ the heading level indicated by the number of '=' signs.
+ """
+
+ # QAPIDoc documentation says free-form documentation blocks
+ # must have only a body section, nothing else.
+ assert not doc.sections
+ assert not doc.args
+ assert not doc.features
+ self._cur_doc = doc
+
+ text = doc.body.text
+ if re.match(r'=+ ', text):
+ # Section/subsection heading (if present, will always be
+ # the first line of the block)
+ (heading, _, text) = text.partition('\n')
+ (leader, _, heading) = heading.partition(' ')
+ self._start_new_heading(heading, len(leader))
+ if text == '':
+ return
+
+ node = self._make_section(None)
+ self._parse_text_into_node(text, node)
+ self._add_node_to_current_heading(node)
+ self._cur_doc = None
+
+ def _parse_text_into_node(self, doctext, node):
+ """Parse a chunk of QAPI-doc-format text into the node
+
+ The doc comment can contain most inline rST markup, including
+ bulleted and enumerated lists.
+ As an extra permitted piece of markup, @var will be turned
+ into ``var``.
+ """
+
+ # Handle the "@var means ``var`` case
+ doctext = re.sub(r'@([\w-]+)', r'``\1``', doctext)
+
+ rstlist = ViewList()
+ for line in doctext.splitlines():
+ # The reported line number will always be that of the start line
+ # of the doc comment, rather than the actual location of the error.
+ # Being more precise would require overhaul of the QAPIDoc class
+ # to track lines more exactly within all the sub-parts of the doc
+ # comment, as well as counting lines here.
+ rstlist.append(line, self._cur_doc.info.fname,
+ self._cur_doc.info.line)
+ # Append a blank line -- in some cases rST syntax errors get
+ # attributed to the line after one with actual text, and if there
+ # isn't anything in the ViewList corresponding to that then Sphinx
+ # 1.6's AutodocReporter will then misidentify the source/line location
+ # in the error message (usually attributing it to the top-level
+ # .rst file rather than the offending .json file). The extra blank
+ # line won't affect the rendered output.
+ rstlist.append("", self._cur_doc.info.fname, self._cur_doc.info.line)
+ self._sphinx_directive.do_parse(rstlist, node)
+
+ def get_document_nodes(self):
+ """Return the list of docutils nodes which make up the document"""
+ return self._top_node.children
+
+
+class QAPISchemaGenDepVisitor(QAPISchemaVisitor):
+ """A QAPI schema visitor which adds Sphinx dependencies each module
+
+ This class calls the Sphinx note_dependency() function to tell Sphinx
+ that the generated documentation output depends on the input
+ schema file associated with each module in the QAPI input.
+ """
+ def __init__(self, env, qapidir):
+ self._env = env
+ self._qapidir = qapidir
+
+ def visit_module(self, name):
+ if name is not None:
+ qapifile = self._qapidir + '/' + name
+ self._env.note_dependency(os.path.abspath(qapifile))
+ super().visit_module(name)
+
+
+class QAPIDocDirective(Directive):
+ """Extract documentation from the specified QAPI .json file"""
+ required_argument = 1
+ optional_arguments = 1
+ option_spec = {
+ 'qapifile': directives.unchanged_required
+ }
+ has_content = False
+
+ def new_serialno(self):
+ """Return a unique new ID string suitable for use as a node's ID"""
+ env = self.state.document.settings.env
+ return 'qapidoc-%d' % env.new_serialno('qapidoc')
+
+ def run(self):
+ env = self.state.document.settings.env
+ qapifile = env.config.qapidoc_srctree + '/' + self.arguments[0]
+ qapidir = os.path.dirname(qapifile)
+
+ try:
+ schema = QAPISchema(qapifile)
+
+ # First tell Sphinx about all the schema files that the
+ # output documentation depends on (including 'qapifile' itself)
+ schema.visit(QAPISchemaGenDepVisitor(env, qapidir))
+
+ vis = QAPISchemaGenRSTVisitor(self)
+ vis.visit_begin(schema)
+ for doc in schema.docs:
+ if doc.symbol:
+ vis.symbol(doc, schema.lookup_entity(doc.symbol))
+ else:
+ vis.freeform(doc)
+ return vis.get_document_nodes()
+ except QAPIError as err:
+ # Launder QAPI parse errors into Sphinx extension errors
+ # so they are displayed nicely to the user
+ raise ExtensionError(str(err))
+
+ def do_parse(self, rstlist, node):
+ """Parse rST source lines and add them to the specified node
+
+ Take the list of rST source lines rstlist, parse them as
+ rST, and add the resulting docutils nodes as children of node.
+ The nodes are parsed in a way that allows them to include
+ subheadings (titles) without confusing the rendering of
+ anything else.
+ """
+ # This is from kerneldoc.py -- it works around an API change in
+ # Sphinx between 1.6 and 1.7. Unlike kerneldoc.py, we use
+ # sphinx.util.nodes.nested_parse_with_titles() rather than the
+ # plain self.state.nested_parse(), and so we can drop the saving
+ # of title_styles and section_level that kerneldoc.py does,
+ # because nested_parse_with_titles() does that for us.
+ if Use_SSI:
+ with switch_source_input(self.state, rstlist):
+ nested_parse_with_titles(self.state, rstlist, node)
+ else:
+ save = self.state.memo.reporter
+ self.state.memo.reporter = AutodocReporter(
+ rstlist, self.state.memo.reporter)
+ try:
+ nested_parse_with_titles(self.state, rstlist, node)
+ finally:
+ self.state.memo.reporter = save
+
+
+def setup(app):
+ """ Register qapi-doc directive with Sphinx"""
+ app.add_config_value('qapidoc_srctree', None, 'env')
+ app.add_directive('qapi-doc', QAPIDocDirective)
+
+ return dict(
+ version=__version__,
+ parallel_read_safe=True,
+ parallel_write_safe=True
+ )
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
index ac06db3..ade9158 100644
--- a/hw/acpi/core.c
+++ b/hw/acpi/core.c
@@ -27,7 +27,7 @@
#include "qapi/error.h"
#include "qapi/opts-visitor.h"
#include "qapi/qapi-events-run-state.h"
-#include "qapi/qapi-visit-misc.h"
+#include "qapi/qapi-visit-acpi.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/option.h"
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 8dd4d8e..f099b50 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -3,7 +3,7 @@
#include "migration/vmstate.h"
#include "hw/acpi/cpu.h"
#include "qapi/error.h"
-#include "qapi/qapi-events-misc.h"
+#include "qapi/qapi-events-acpi.h"
#include "trace.h"
#include "sysemu/numa.h"
diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c
index 8d2e822..f2552b2 100644
--- a/hw/acpi/memory_hotplug.c
+++ b/hw/acpi/memory_hotplug.c
@@ -7,7 +7,8 @@
#include "migration/vmstate.h"
#include "trace.h"
#include "qapi/error.h"
-#include "qapi/qapi-events-misc.h"
+#include "qapi/qapi-events-acpi.h"
+#include "qapi/qapi-events-machine.h"
#define MEMORY_SLOTS_NUMBER "MDNR"
#define MEMORY_HOTPLUG_IO_REGION "HPMR"
diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
index 53db6af..2c8152d 100644
--- a/hw/acpi/vmgenid.c
+++ b/hw/acpi/vmgenid.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-machine.h"
#include "qemu/module.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 098298c..343c824 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -4,6 +4,7 @@
#include "qapi/error.h"
#include "hw/pci/pci.h"
#include "qapi/qapi-types-block.h"
+#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-types-misc.h"
#include "qapi/qmp/qerror.h"
#include "qemu/ctype.h"
diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c
index e18fd33..40d8473 100644
--- a/hw/i386/kvm/i8254.c
+++ b/hw/i386/kvm/i8254.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include <linux/kvm.h>
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-machine.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/timer.h"
diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c
index cc2a2e1..3a027c4 100644
--- a/hw/pci/pci-stub.c
+++ b/hw/pci/pci-stub.c
@@ -22,7 +22,7 @@
#include "sysemu/sysemu.h"
#include "monitor/monitor.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-pci.h"
#include "qapi/qmp/qerror.h"
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index fce7254..3c8f10b 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -46,7 +46,7 @@
#include "hw/hotplug.h"
#include "hw/boards.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-pci.h"
#include "qemu/cutils.h"
//#define DEBUG_PCI
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 22cb5df..b22b5be 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -24,7 +24,7 @@
#include "hw/virtio/virtio-balloon.h"
#include "exec/address-spaces.h"
#include "qapi/error.h"
-#include "qapi/qapi-events-misc.h"
+#include "qapi/qapi-events-machine.h"
#include "qapi/visitor.h"
#include "trace.h"
#include "qemu/error-report.h"
diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c
index 590cec0..913f4a3 100644
--- a/hw/virtio/virtio-mem-pci.c
+++ b/hw/virtio/virtio-mem-pci.c
@@ -14,6 +14,7 @@
#include "virtio-mem-pci.h"
#include "hw/mem/memory-device.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-machine.h"
#include "qapi/qapi-events-misc.h"
static void virtio_mem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index 9adf1e4..769ff55 100644
--- a/include/hw/acpi/acpi_dev_interface.h
+++ b/include/hw/acpi/acpi_dev_interface.h
@@ -1,7 +1,7 @@
#ifndef ACPI_DEV_INTERFACE_H
#define ACPI_DEV_INTERFACE_H
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-acpi.h"
#include "qom/object.h"
#include "hw/boards.h"
#include "hw/qdev-core.h"
diff --git a/include/hw/mem/memory-device.h b/include/hw/mem/memory-device.h
index cde52e8..30d7e99 100644
--- a/include/hw/mem/memory-device.h
+++ b/include/hw/mem/memory-device.h
@@ -14,7 +14,7 @@
#define MEMORY_DEVICE_H
#include "hw/qdev-core.h"
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-machine.h"
#include "qom/object.h"
#define TYPE_MEMORY_DEVICE "memory-device"
diff --git a/include/hw/rtc/mc146818rtc.h b/include/hw/rtc/mc146818rtc.h
index 6224b52..5b45b22 100644
--- a/include/hw/rtc/mc146818rtc.h
+++ b/include/hw/rtc/mc146818rtc.h
@@ -9,7 +9,7 @@
#ifndef HW_RTC_MC146818RTC_H
#define HW_RTC_MC146818RTC_H
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-machine.h"
#include "qemu/queue.h"
#include "qemu/timer.h"
#include "hw/isa/isa.h"
diff --git a/include/hw/virtio/virtio-pmem.h b/include/hw/virtio/virtio-pmem.h
index 66b5908..fc4fd1f 100644
--- a/include/hw/virtio/virtio-pmem.h
+++ b/include/hw/virtio/virtio-pmem.h
@@ -15,7 +15,7 @@
#define HW_VIRTIO_PMEM_H
#include "hw/virtio/virtio.h"
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-machine.h"
#include "qom/object.h"
#define TYPE_VIRTIO_PMEM "virtio-pmem"
diff --git a/include/sysemu/balloon.h b/include/sysemu/balloon.h
index 20a2def..867687b 100644
--- a/include/sysemu/balloon.h
+++ b/include/sysemu/balloon.h
@@ -15,7 +15,7 @@
#define QEMU_BALLOON_H
#include "exec/cpu-common.h"
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-machine.h"
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
diff --git a/meson.build b/meson.build
index d36dd08..5b586af 100644
--- a/meson.build
+++ b/meson.build
@@ -619,7 +619,6 @@ qapi_gen = find_program('scripts/qapi-gen.py')
qapi_gen_depends = [ meson.source_root() / 'scripts/qapi/__init__.py',
meson.source_root() / 'scripts/qapi/commands.py',
meson.source_root() / 'scripts/qapi/common.py',
- meson.source_root() / 'scripts/qapi/doc.py',
meson.source_root() / 'scripts/qapi/error.py',
meson.source_root() / 'scripts/qapi/events.py',
meson.source_root() / 'scripts/qapi/expr.py',
@@ -631,7 +630,6 @@ qapi_gen_depends = [ meson.source_root() / 'scripts/qapi/__init__.py',
meson.source_root() / 'scripts/qapi/types.py',
meson.source_root() / 'scripts/qapi/visit.py',
meson.source_root() / 'scripts/qapi/common.py',
- meson.source_root() / 'scripts/qapi/doc.py',
meson.source_root() / 'scripts/qapi-gen.py'
]
@@ -672,6 +670,22 @@ foreach d : hx_headers
endforeach
genh += hxdep
+SPHINX_ARGS = [config_host['SPHINX_BUILD'],
+ '-Dversion=' + meson.project_version(),
+ '-Drelease=' + config_host['PKGVERSION']]
+
+if get_option('werror')
+ SPHINX_ARGS += [ '-W' ]
+endif
+
+sphinx_extn_depends = [ meson.source_root() / 'docs/sphinx/depfile.py',
+ meson.source_root() / 'docs/sphinx/hxtool.py',
+ meson.source_root() / 'docs/sphinx/kerneldoc.py',
+ meson.source_root() / 'docs/sphinx/kernellog.py',
+ meson.source_root() / 'docs/sphinx/qapidoc.py',
+ meson.source_root() / 'docs/sphinx/qmp_lexer.py',
+ qapi_gen_depends ]
+
# Collect sourcesets.
util_ss = ss.source_set()
@@ -1204,91 +1218,6 @@ if 'CONFIG_GTK' in config_host
subdir('po')
endif
-if build_docs
- makeinfo = find_program('makeinfo', required: build_docs)
-
- docs_inc = [
- '-I', meson.current_source_dir(),
- '-I', meson.current_build_dir() / 'docs',
- '-I', '@OUTDIR@',
- ]
-
- version_texi = configure_file(output: 'version.texi',
- input: 'version.texi.in',
- configuration: {'VERSION': meson.project_version(),
- 'qemu_confdir': config_host['qemu_confdir']})
-
- texi = {
- 'qemu-qmp-ref': ['docs/interop/qemu-qmp-ref.texi', qapi_doc_texi, version_texi],
- }
- if 'CONFIG_GUEST_AGENT' in config_host
- texi += {'qemu-ga-ref': ['docs/interop/qemu-ga-ref.texi', qga_qapi_doc_texi, version_texi]}
- endif
-
- if makeinfo.found()
- cmd = [
- 'env', 'LC_ALL=C', makeinfo, '--no-split', '--number-sections', docs_inc,
- '@INPUT0@', '-o', '@OUTPUT@',
- ]
- foreach ext, args: {
- 'info': [],
- 'html': ['--no-headers', '--html'],
- 'txt': ['--no-headers', '--plaintext'],
- }
- t = []
- foreach doc, input: texi
- output = doc + '.' + ext
- t += custom_target(output,
- input: input,
- output: output,
- install: true,
- install_dir: qemu_docdir / 'interop',
- command: cmd + args)
- endforeach
- alias_target(ext, t)
- endforeach
- endif
-
- texi2pdf = find_program('texi2pdf', required: false)
-
- if texi2pdf.found()
- pdfs = []
- foreach doc, input: texi
- output = doc + '.pdf'
- pdfs += custom_target(output,
- input: input,
- output: output,
- command: [texi2pdf, '-q', docs_inc, '@INPUT0@', '-o', '@OUTPUT@'],
- build_by_default: false)
- endforeach
- alias_target('pdf', pdfs)
- endif
-
- texi2pod = find_program('scripts/texi2pod.pl')
- pod2man = find_program('pod2man', required: build_docs)
-
- if pod2man.found()
- foreach doc, input: texi
- man = doc + '.7'
- pod = custom_target(man + '.pod',
- input: input,
- output: man + '.pod',
- command: [texi2pod,
- '-DVERSION="' + meson.project_version() + '"',
- '-DCONFDIR="' + config_host['qemu_confdir'] + '"',
- '@INPUT0@', '@OUTPUT@'])
- man = custom_target(man,
- input: pod,
- output: man,
- capture: true,
- install: true,
- install_dir: get_option('mandir') / 'man7',
- command: [pod2man, '--utf8', '--section=7', '--center=" "',
- '--release=" "', '@INPUT@'])
- endforeach
- endif
-endif
-
if host_machine.system() == 'windows'
nsis_cmd = [
find_program('scripts/nsis.py'),
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 7711726..dc0de39 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -32,9 +32,11 @@
#include "qapi/qapi-commands-block.h"
#include "qapi/qapi-commands-char.h"
#include "qapi/qapi-commands-control.h"
+#include "qapi/qapi-commands-machine.h"
#include "qapi/qapi-commands-migration.h"
#include "qapi/qapi-commands-misc.h"
#include "qapi/qapi-commands-net.h"
+#include "qapi/qapi-commands-pci.h"
#include "qapi/qapi-commands-rocker.h"
#include "qapi/qapi-commands-run-state.h"
#include "qapi/qapi-commands-tpm.h"
diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index 864cbfa..0ab5b78 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -30,6 +30,7 @@
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-acpi.h"
#include "qapi/qapi-commands-block.h"
#include "qapi/qapi-commands-control.h"
#include "qapi/qapi-commands-machine.h"
diff --git a/qapi/acpi.json b/qapi/acpi.json
new file mode 100644
index 0000000..51f0d55
--- /dev/null
+++ b/qapi/acpi.json
@@ -0,0 +1,141 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+##
+# = ACPI
+##
+
+##
+# @AcpiTableOptions:
+#
+# Specify an ACPI table on the command line to load.
+#
+# At most one of @file and @data can be specified. The list of files specified
+# by any one of them is loaded and concatenated in order. If both are omitted,
+# @data is implied.
+#
+# Other fields / optargs can be used to override fields of the generic ACPI
+# table header; refer to the ACPI specification 5.0, section 5.2.6 System
+# Description Table Header. If a header field is not overridden, then the
+# corresponding value from the concatenated blob is used (in case of @file), or
+# it is filled in with a hard-coded value (in case of @data).
+#
+# String fields are copied into the matching ACPI member from lowest address
+# upwards, and silently truncated / NUL-padded to length.
+#
+# @sig: table signature / identifier (4 bytes)
+#
+# @rev: table revision number (dependent on signature, 1 byte)
+#
+# @oem_id: OEM identifier (6 bytes)
+#
+# @oem_table_id: OEM table identifier (8 bytes)
+#
+# @oem_rev: OEM-supplied revision number (4 bytes)
+#
+# @asl_compiler_id: identifier of the utility that created the table
+# (4 bytes)
+#
+# @asl_compiler_rev: revision number of the utility that created the
+# table (4 bytes)
+#
+# @file: colon (:) separated list of pathnames to load and
+# concatenate as table data. The resultant binary blob is expected to
+# have an ACPI table header. At least one file is required. This field
+# excludes @data.
+#
+# @data: colon (:) separated list of pathnames to load and
+# concatenate as table data. The resultant binary blob must not have an
+# ACPI table header. At least one file is required. This field excludes
+# @file.
+#
+# Since: 1.5
+##
+{ 'struct': 'AcpiTableOptions',
+ 'data': {
+ '*sig': 'str',
+ '*rev': 'uint8',
+ '*oem_id': 'str',
+ '*oem_table_id': 'str',
+ '*oem_rev': 'uint32',
+ '*asl_compiler_id': 'str',
+ '*asl_compiler_rev': 'uint32',
+ '*file': 'str',
+ '*data': 'str' }}
+
+##
+# @ACPISlotType:
+#
+# @DIMM: memory slot
+# @CPU: logical CPU slot (since 2.7)
+##
+{ 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
+
+##
+# @ACPIOSTInfo:
+#
+# OSPM Status Indication for a device
+# For description of possible values of @source and @status fields
+# see "_OST (OSPM Status Indication)" chapter of ACPI5.0 spec.
+#
+# @device: device ID associated with slot
+#
+# @slot: slot ID, unique per slot of a given @slot-type
+#
+# @slot-type: type of the slot
+#
+# @source: an integer containing the source event
+#
+# @status: an integer containing the status code
+#
+# Since: 2.1
+##
+{ 'struct': 'ACPIOSTInfo',
+ 'data' : { '*device': 'str',
+ 'slot': 'str',
+ 'slot-type': 'ACPISlotType',
+ 'source': 'int',
+ 'status': 'int' } }
+
+##
+# @query-acpi-ospm-status:
+#
+# Return a list of ACPIOSTInfo for devices that support status
+# reporting via ACPI _OST method.
+#
+# Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-acpi-ospm-status" }
+# <- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
+# { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
+# { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
+# { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
+# ]}
+#
+##
+{ 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
+
+##
+# @ACPI_DEVICE_OST:
+#
+# Emitted when guest executes ACPI _OST method.
+#
+# @info: OSPM Status Indication
+#
+# Since: 2.1
+#
+# Example:
+#
+# <- { "event": "ACPI_DEVICE_OST",
+# "data": { "device": "d1", "slot": "0",
+# "slot-type": "DIMM", "source": 1, "status": 0 } }
+#
+##
+{ 'event': 'ACPI_DEVICE_OST',
+ 'data': { 'info': 'ACPIOSTInfo' } }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 3c16f1e..86ed72e 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -570,13 +570,15 @@
# For the example above, @bins may be something like [3, 1, 5, 2],
# and corresponding histogram looks like:
#
-# | 5| *
-# | 4| *
-# | 3| * *
-# | 2| * * *
-# | 1| * * * *
-# | +------------------
-# | 10 50 100
+# ::
+#
+# 5| *
+# 4| *
+# 3| * *
+# 2| * * *
+# 1| * * * *
+# +------------------
+# 10 50 100
#
# Since: 4.0
##
@@ -4316,8 +4318,8 @@
# @data-file-raw: True if the external data file must stay valid as a
# standalone (read-only) raw image without looking at qcow2
# metadata (default: false; since: 4.0)
-# @extended-l2 True to make the image have extended L2 entries
-# (default: false; since 5.2)
+# @extended-l2: True to make the image have extended L2 entries
+# (default: false; since 5.2)
# @size: Size of the virtual disk in bytes
# @version: Compatibility level (default: v3)
# @backing-file: File name of the backing file if a backing file
diff --git a/qapi/block.json b/qapi/block.json
index c54a393..a009f7d 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -528,7 +528,8 @@
#
# Since: 4.0
#
-# Example: set new histograms for all io types with intervals
+# Example:
+# set new histograms for all io types with intervals
# [0, 10), [10, 50), [50, 100), [100, +inf):
#
# -> { "execute": "block-latency-histogram-set",
@@ -536,7 +537,8 @@
# "boundaries": [10, 50, 100] } }
# <- { "return": {} }
#
-# Example: set new histogram only for write, other histograms will remain
+# Example:
+# set new histogram only for write, other histograms will remain
# not changed (or not created):
#
# -> { "execute": "block-latency-histogram-set",
@@ -544,7 +546,8 @@
# "boundaries-write": [10, 50, 100] } }
# <- { "return": {} }
#
-# Example: set new histograms with the following intervals:
+# Example:
+# set new histograms with the following intervals:
# read, flush: [0, 10), [10, 50), [50, 100), [100, +inf)
# write: [0, 1000), [1000, 5000), [5000, +inf)
#
@@ -554,7 +557,8 @@
# "boundaries-write": [1000, 5000] } }
# <- { "return": {} }
#
-# Example: remove all latency histograms:
+# Example:
+# remove all latency histograms:
#
# -> { "execute": "block-latency-histogram-set",
# "arguments": { "id": "drive0" } }
diff --git a/qapi/machine.json b/qapi/machine.json
index d8ed096..756dacb 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -13,7 +13,7 @@
#
# The comprehensive enumeration of QEMU system emulation ("softmmu")
# targets. Run "./configure --help" in the project root directory, and
-# look for the *-softmmu targets near the "--target-list" option. The
+# look for the \*-softmmu targets near the "--target-list" option. The
# individual target constants are not documented here, for the time
# being.
#
@@ -403,6 +403,88 @@
{ 'command': 'query-target', 'returns': 'TargetInfo' }
##
+# @UuidInfo:
+#
+# Guest UUID information (Universally Unique Identifier).
+#
+# @UUID: the UUID of the guest
+#
+# Since: 0.14.0
+#
+# Notes: If no UUID was specified for the guest, a null UUID is returned.
+##
+{ 'struct': 'UuidInfo', 'data': {'UUID': 'str'} }
+
+##
+# @query-uuid:
+#
+# Query the guest UUID information.
+#
+# Returns: The @UuidInfo for the guest
+#
+# Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-uuid" }
+# <- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
+#
+##
+{ 'command': 'query-uuid', 'returns': 'UuidInfo', 'allow-preconfig': true }
+
+##
+# @GuidInfo:
+#
+# GUID information.
+#
+# @guid: the globally unique identifier
+#
+# Since: 2.9
+##
+{ 'struct': 'GuidInfo', 'data': {'guid': 'str'} }
+
+##
+# @query-vm-generation-id:
+#
+# Show Virtual Machine Generation ID
+#
+# Since: 2.9
+##
+{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
+
+##
+# @LostTickPolicy:
+#
+# Policy for handling lost ticks in timer devices. Ticks end up getting
+# lost when, for example, the guest is paused.
+#
+# @discard: throw away the missed ticks and continue with future injection
+# normally. The guest OS will see the timer jump ahead by a
+# potentially quite significant amount all at once, as if the
+# intervening chunk of time had simply not existed; needless to
+# say, such a sudden jump can easily confuse a guest OS which is
+# not specifically prepared to deal with it. Assuming the guest
+# OS can deal correctly with the time jump, the time in the guest
+# and in the host should now match.
+#
+# @delay: continue to deliver ticks at the normal rate. The guest OS will
+# not notice anything is amiss, as from its point of view time will
+# have continued to flow normally. The time in the guest should now
+# be behind the time in the host by exactly the amount of time during
+# which ticks have been missed.
+#
+# @slew: deliver ticks at a higher rate to catch up with the missed ticks.
+# The guest OS will not notice anything is amiss, as from its point
+# of view time will have continued to flow normally. Once the timer
+# has managed to catch up with all the missing ticks, the time in
+# the guest and in the host should match.
+#
+# Since: 2.0
+##
+{ 'enum': 'LostTickPolicy',
+ 'data': ['discard', 'delay', 'slew' ] }
+
+##
# @NumaOptionsType:
#
# @node: NUMA nodes configuration
@@ -913,3 +995,311 @@
'data': 'NumaOptions',
'allow-preconfig': true
}
+
+##
+# @balloon:
+#
+# Request the balloon driver to change its balloon size.
+#
+# @value: the target logical size of the VM in bytes.
+# We can deduce the size of the balloon using this formula:
+#
+# logical_vm_size = vm_ram_size - balloon_size
+#
+# From it we have: balloon_size = vm_ram_size - @value
+#
+# Returns: - Nothing on success
+# - If the balloon driver is enabled but not functional because the KVM
+# kernel module cannot support it, KvmMissingCap
+# - If no balloon device is present, DeviceNotActive
+#
+# Notes: This command just issues a request to the guest. When it returns,
+# the balloon size may not have changed. A guest can change the balloon
+# size independent of this command.
+#
+# Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "balloon", "arguments": { "value": 536870912 } }
+# <- { "return": {} }
+#
+# With a 2.5GiB guest this command inflated the ballon to 3GiB.
+#
+##
+{ 'command': 'balloon', 'data': {'value': 'int'} }
+
+##
+# @BalloonInfo:
+#
+# Information about the guest balloon device.
+#
+# @actual: the logical size of the VM in bytes
+# Formula used: logical_vm_size = vm_ram_size - balloon_size
+#
+# Since: 0.14.0
+#
+##
+{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
+
+##
+# @query-balloon:
+#
+# Return information about the balloon device.
+#
+# Returns: - @BalloonInfo on success
+# - If the balloon driver is enabled but not functional because the KVM
+# kernel module cannot support it, KvmMissingCap
+# - If no balloon device is present, DeviceNotActive
+#
+# Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-balloon" }
+# <- { "return": {
+# "actual": 1073741824,
+# }
+# }
+#
+##
+{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
+
+##
+# @BALLOON_CHANGE:
+#
+# Emitted when the guest changes the actual BALLOON level. This value is
+# equivalent to the @actual field return by the 'query-balloon' command
+#
+# @actual: the logical size of the VM in bytes
+# Formula used: logical_vm_size = vm_ram_size - balloon_size
+#
+# Note: this event is rate-limited.
+#
+# Since: 1.2
+#
+# Example:
+#
+# <- { "event": "BALLOON_CHANGE",
+# "data": { "actual": 944766976 },
+# "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+#
+##
+{ 'event': 'BALLOON_CHANGE',
+ 'data': { 'actual': 'int' } }
+
+##
+# @MemoryInfo:
+#
+# Actual memory information in bytes.
+#
+# @base-memory: size of "base" memory specified with command line
+# option -m.
+#
+# @plugged-memory: size of memory that can be hot-unplugged. This field
+# is omitted if target doesn't support memory hotplug
+# (i.e. CONFIG_MEM_DEVICE not defined at build time).
+#
+# Since: 2.11.0
+##
+{ 'struct': 'MemoryInfo',
+ 'data' : { 'base-memory': 'size', '*plugged-memory': 'size' } }
+
+##
+# @query-memory-size-summary:
+#
+# Return the amount of initially allocated and present hotpluggable (if
+# enabled) memory in bytes.
+#
+# Example:
+#
+# -> { "execute": "query-memory-size-summary" }
+# <- { "return": { "base-memory": 4294967296, "plugged-memory": 0 } }
+#
+# Since: 2.11.0
+##
+{ 'command': 'query-memory-size-summary', 'returns': 'MemoryInfo' }
+
+##
+# @PCDIMMDeviceInfo:
+#
+# PCDIMMDevice state information
+#
+# @id: device's ID
+#
+# @addr: physical address, where device is mapped
+#
+# @size: size of memory that the device provides
+#
+# @slot: slot number at which device is plugged in
+#
+# @node: NUMA node number where device is plugged in
+#
+# @memdev: memory backend linked with device
+#
+# @hotplugged: true if device was hotplugged
+#
+# @hotpluggable: true if device if could be added/removed while machine is running
+#
+# Since: 2.1
+##
+{ 'struct': 'PCDIMMDeviceInfo',
+ 'data': { '*id': 'str',
+ 'addr': 'int',
+ 'size': 'int',
+ 'slot': 'int',
+ 'node': 'int',
+ 'memdev': 'str',
+ 'hotplugged': 'bool',
+ 'hotpluggable': 'bool'
+ }
+}
+
+##
+# @VirtioPMEMDeviceInfo:
+#
+# VirtioPMEM state information
+#
+# @id: device's ID
+#
+# @memaddr: physical address in memory, where device is mapped
+#
+# @size: size of memory that the device provides
+#
+# @memdev: memory backend linked with device
+#
+# Since: 4.1
+##
+{ 'struct': 'VirtioPMEMDeviceInfo',
+ 'data': { '*id': 'str',
+ 'memaddr': 'size',
+ 'size': 'size',
+ 'memdev': 'str'
+ }
+}
+
+##
+# @VirtioMEMDeviceInfo:
+#
+# VirtioMEMDevice state information
+#
+# @id: device's ID
+#
+# @memaddr: physical address in memory, where device is mapped
+#
+# @requested-size: the user requested size of the device
+#
+# @size: the (current) size of memory that the device provides
+#
+# @max-size: the maximum size of memory that the device can provide
+#
+# @block-size: the block size of memory that the device provides
+#
+# @node: NUMA node number where device is assigned to
+#
+# @memdev: memory backend linked with the region
+#
+# Since: 5.1
+##
+{ 'struct': 'VirtioMEMDeviceInfo',
+ 'data': { '*id': 'str',
+ 'memaddr': 'size',
+ 'requested-size': 'size',
+ 'size': 'size',
+ 'max-size': 'size',
+ 'block-size': 'size',
+ 'node': 'int',
+ 'memdev': 'str'
+ }
+}
+
+##
+# @MemoryDeviceInfo:
+#
+# Union containing information about a memory device
+#
+# nvdimm is included since 2.12. virtio-pmem is included since 4.1.
+# virtio-mem is included since 5.1.
+#
+# Since: 2.1
+##
+{ 'union': 'MemoryDeviceInfo',
+ 'data': { 'dimm': 'PCDIMMDeviceInfo',
+ 'nvdimm': 'PCDIMMDeviceInfo',
+ 'virtio-pmem': 'VirtioPMEMDeviceInfo',
+ 'virtio-mem': 'VirtioMEMDeviceInfo'
+ }
+}
+
+##
+# @query-memory-devices:
+#
+# Lists available memory devices and their state
+#
+# Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-memory-devices" }
+# <- { "return": [ { "data":
+# { "addr": 5368709120,
+# "hotpluggable": true,
+# "hotplugged": true,
+# "id": "d1",
+# "memdev": "/objects/memX",
+# "node": 0,
+# "size": 1073741824,
+# "slot": 0},
+# "type": "dimm"
+# } ] }
+#
+##
+{ 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
+
+##
+# @MEMORY_DEVICE_SIZE_CHANGE:
+#
+# Emitted when the size of a memory device changes. Only emitted for memory
+# devices that can actually change the size (e.g., virtio-mem due to guest
+# action).
+#
+# @id: device's ID
+# @size: the new size of memory that the device provides
+#
+# Note: this event is rate-limited.
+#
+# Since: 5.1
+#
+# Example:
+#
+# <- { "event": "MEMORY_DEVICE_SIZE_CHANGE",
+# "data": { "id": "vm0", "size": 1073741824},
+# "timestamp": { "seconds": 1588168529, "microseconds": 201316 } }
+#
+##
+{ 'event': 'MEMORY_DEVICE_SIZE_CHANGE',
+ 'data': { '*id': 'str', 'size': 'size' } }
+
+
+##
+# @MEM_UNPLUG_ERROR:
+#
+# Emitted when memory hot unplug error occurs.
+#
+# @device: device name
+#
+# @msg: Informative message
+#
+# Since: 2.4
+#
+# Example:
+#
+# <- { "event": "MEM_UNPLUG_ERROR"
+# "data": { "device": "dimm1",
+# "msg": "acpi: device unplug for unsupported device"
+# },
+# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
+##
+{ 'event': 'MEM_UNPLUG_ERROR',
+ 'data': { 'device': 'str', 'msg': 'str' } }
diff --git a/qapi/meson.build b/qapi/meson.build
index 2b2872a..7c4a89a 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -14,6 +14,7 @@ util_ss.add(files(
))
qapi_all_modules = [
+ 'acpi',
'audio',
'authz',
'block-core',
@@ -34,6 +35,7 @@ qapi_all_modules = [
'net',
'pragma',
'qdev',
+ 'pci',
'qom',
'rdma',
'rocker',
@@ -97,7 +99,7 @@ foreach module : qapi_all_modules
endforeach
qapi_files = custom_target('shared QAPI source files',
- output: qapi_util_outputs + qapi_specific_outputs + qapi_nonmodule_outputs + ['qapi-doc.texi'],
+ output: qapi_util_outputs + qapi_specific_outputs + qapi_nonmodule_outputs,
input: [ files('qapi-schema.json') ],
command: [ qapi_gen, '-o', 'qapi', '-b', '@INPUT0@' ],
depend_files: [ qapi_inputs, qapi_gen_depends ])
@@ -121,5 +123,3 @@ foreach output : qapi_specific_outputs + qapi_nonmodule_outputs
specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: qapi_files[i])
i = i + 1
endforeach
-
-qapi_doc_texi = qapi_files[i]
diff --git a/qapi/migration.json b/qapi/migration.json
index ce2216c..7f5e6fd 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -681,23 +681,23 @@
# Defaults to 1. (Since 5.0)
#
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
-# aliases for the purpose of dirty bitmap migration. Such
-# aliases may for example be the corresponding names on the
-# opposite site.
-# The mapping must be one-to-one, but not necessarily
-# complete: On the source, unmapped bitmaps and all bitmaps
-# on unmapped nodes will be ignored. On the destination,
-# encountering an unmapped alias in the incoming migration
-# stream will result in a report, and all further bitmap
-# migration data will then be discarded.
-# Note that the destination does not know about bitmaps it
-# does not receive, so there is no limitation or requirement
-# regarding the number of bitmaps received, or how they are
-# named, or on which nodes they are placed.
-# By default (when this parameter has never been set), bitmap
-# names are mapped to themselves. Nodes are mapped to their
-# block device name if there is one, and to their node name
-# otherwise. (Since 5.2)
+# aliases for the purpose of dirty bitmap migration. Such
+# aliases may for example be the corresponding names on the
+# opposite site.
+# The mapping must be one-to-one, but not necessarily
+# complete: On the source, unmapped bitmaps and all bitmaps
+# on unmapped nodes will be ignored. On the destination,
+# encountering an unmapped alias in the incoming migration
+# stream will result in a report, and all further bitmap
+# migration data will then be discarded.
+# Note that the destination does not know about bitmaps it
+# does not receive, so there is no limitation or requirement
+# regarding the number of bitmaps received, or how they are
+# named, or on which nodes they are placed.
+# By default (when this parameter has never been set), bitmap
+# names are mapped to themselves. Nodes are mapped to their
+# block device name if there is one, and to their node name
+# otherwise. (Since 5.2)
#
# Since: 2.4
##
@@ -841,23 +841,23 @@
# Defaults to 1. (Since 5.0)
#
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
-# aliases for the purpose of dirty bitmap migration. Such
-# aliases may for example be the corresponding names on the
-# opposite site.
-# The mapping must be one-to-one, but not necessarily
-# complete: On the source, unmapped bitmaps and all bitmaps
-# on unmapped nodes will be ignored. On the destination,
-# encountering an unmapped alias in the incoming migration
-# stream will result in a report, and all further bitmap
-# migration data will then be discarded.
-# Note that the destination does not know about bitmaps it
-# does not receive, so there is no limitation or requirement
-# regarding the number of bitmaps received, or how they are
-# named, or on which nodes they are placed.
-# By default (when this parameter has never been set), bitmap
-# names are mapped to themselves. Nodes are mapped to their
-# block device name if there is one, and to their node name
-# otherwise. (Since 5.2)
+# aliases for the purpose of dirty bitmap migration. Such
+# aliases may for example be the corresponding names on the
+# opposite site.
+# The mapping must be one-to-one, but not necessarily
+# complete: On the source, unmapped bitmaps and all bitmaps
+# on unmapped nodes will be ignored. On the destination,
+# encountering an unmapped alias in the incoming migration
+# stream will result in a report, and all further bitmap
+# migration data will then be discarded.
+# Note that the destination does not know about bitmaps it
+# does not receive, so there is no limitation or requirement
+# regarding the number of bitmaps received, or how they are
+# named, or on which nodes they are placed.
+# By default (when this parameter has never been set), bitmap
+# names are mapped to themselves. Nodes are mapped to their
+# block device name if there is one, and to their node name
+# otherwise. (Since 5.2)
#
# Since: 2.4
##
@@ -1037,23 +1037,23 @@
# Defaults to 1. (Since 5.0)
#
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
-# aliases for the purpose of dirty bitmap migration. Such
-# aliases may for example be the corresponding names on the
-# opposite site.
-# The mapping must be one-to-one, but not necessarily
-# complete: On the source, unmapped bitmaps and all bitmaps
-# on unmapped nodes will be ignored. On the destination,
-# encountering an unmapped alias in the incoming migration
-# stream will result in a report, and all further bitmap
-# migration data will then be discarded.
-# Note that the destination does not know about bitmaps it
-# does not receive, so there is no limitation or requirement
-# regarding the number of bitmaps received, or how they are
-# named, or on which nodes they are placed.
-# By default (when this parameter has never been set), bitmap
-# names are mapped to themselves. Nodes are mapped to their
-# block device name if there is one, and to their node name
-# otherwise. (Since 5.2)
+# aliases for the purpose of dirty bitmap migration. Such
+# aliases may for example be the corresponding names on the
+# opposite site.
+# The mapping must be one-to-one, but not necessarily
+# complete: On the source, unmapped bitmaps and all bitmaps
+# on unmapped nodes will be ignored. On the destination,
+# encountering an unmapped alias in the incoming migration
+# stream will result in a report, and all further bitmap
+# migration data will then be discarded.
+# Note that the destination does not know about bitmaps it
+# does not receive, so there is no limitation or requirement
+# regarding the number of bitmaps received, or how they are
+# named, or on which nodes they are placed.
+# By default (when this parameter has never been set), bitmap
+# names are mapped to themselves. Nodes are mapped to their
+# block device name if there is one, and to their node name
+# otherwise. (Since 5.2)
#
# Since: 2.4
##
@@ -1744,9 +1744,9 @@
# Information about current dirty page rate of vm.
#
# @dirty-rate: @dirtyrate describing the dirty page rate of vm
-# in units of MB/s.
-# If this field returns '-1', it means querying has not
-# yet started or completed.
+# in units of MB/s.
+# If this field returns '-1', it means querying has not
+# yet started or completed.
#
# @status: status containing dirtyrate query status includes
# 'unstarted' or 'measuring' or 'measured'
diff --git a/qapi/misc.json b/qapi/misc.json
index 8cf6ebe..694d214 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -9,38 +9,6 @@
{ 'include': 'common.json' }
##
-# @LostTickPolicy:
-#
-# Policy for handling lost ticks in timer devices. Ticks end up getting
-# lost when, for example, the guest is paused.
-#
-# @discard: throw away the missed ticks and continue with future injection
-# normally. The guest OS will see the timer jump ahead by a
-# potentially quite significant amount all at once, as if the
-# intervening chunk of time had simply not existed; needless to
-# say, such a sudden jump can easily confuse a guest OS which is
-# not specifically prepared to deal with it. Assuming the guest
-# OS can deal correctly with the time jump, the time in the guest
-# and in the host should now match.
-#
-# @delay: continue to deliver ticks at the normal rate. The guest OS will
-# not notice anything is amiss, as from its point of view time will
-# have continued to flow normally. The time in the guest should now
-# be behind the time in the host by exactly the amount of time during
-# which ticks have been missed.
-#
-# @slew: deliver ticks at a higher rate to catch up with the missed ticks.
-# The guest OS will not notice anything is amiss, as from its point
-# of view time will have continued to flow normally. Once the timer
-# has managed to catch up with all the missing ticks, the time in
-# the guest and in the host should match.
-#
-# Since: 2.0
-##
-{ 'enum': 'LostTickPolicy',
- 'data': ['discard', 'delay', 'slew' ] }
-
-##
# @add_client:
#
# Allow client connections for VNC, Spice and socket based
@@ -131,36 +99,6 @@
{ 'command': 'query-kvm', 'returns': 'KvmInfo' }
##
-# @UuidInfo:
-#
-# Guest UUID information (Universally Unique Identifier).
-#
-# @UUID: the UUID of the guest
-#
-# Since: 0.14.0
-#
-# Notes: If no UUID was specified for the guest, a null UUID is returned.
-##
-{ 'struct': 'UuidInfo', 'data': {'UUID': 'str'} }
-
-##
-# @query-uuid:
-#
-# Query the guest UUID information.
-#
-# Returns: The @UuidInfo for the guest
-#
-# Since: 0.14.0
-#
-# Example:
-#
-# -> { "execute": "query-uuid" }
-# <- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
-#
-##
-{ 'command': 'query-uuid', 'returns': 'UuidInfo', 'allow-preconfig': true }
-
-##
# @IOThreadInfo:
#
# Information about an iothread
@@ -220,369 +158,6 @@
'allow-preconfig': true }
##
-# @BalloonInfo:
-#
-# Information about the guest balloon device.
-#
-# @actual: the number of bytes the balloon currently contains
-#
-# Since: 0.14.0
-#
-##
-{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
-
-##
-# @query-balloon:
-#
-# Return information about the balloon device.
-#
-# Returns: - @BalloonInfo on success
-# - If the balloon driver is enabled but not functional because the KVM
-# kernel module cannot support it, KvmMissingCap
-# - If no balloon device is present, DeviceNotActive
-#
-# Since: 0.14.0
-#
-# Example:
-#
-# -> { "execute": "query-balloon" }
-# <- { "return": {
-# "actual": 1073741824,
-# }
-# }
-#
-##
-{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
-
-##
-# @BALLOON_CHANGE:
-#
-# Emitted when the guest changes the actual BALLOON level. This value is
-# equivalent to the @actual field return by the 'query-balloon' command
-#
-# @actual: actual level of the guest memory balloon in bytes
-#
-# Note: this event is rate-limited.
-#
-# Since: 1.2
-#
-# Example:
-#
-# <- { "event": "BALLOON_CHANGE",
-# "data": { "actual": 944766976 },
-# "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-#
-##
-{ 'event': 'BALLOON_CHANGE',
- 'data': { 'actual': 'int' } }
-
-##
-# @PciMemoryRange:
-#
-# A PCI device memory region
-#
-# @base: the starting address (guest physical)
-#
-# @limit: the ending address (guest physical)
-#
-# Since: 0.14.0
-##
-{ 'struct': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
-
-##
-# @PciMemoryRegion:
-#
-# Information about a PCI device I/O region.
-#
-# @bar: the index of the Base Address Register for this region
-#
-# @type: - 'io' if the region is a PIO region
-# - 'memory' if the region is a MMIO region
-#
-# @size: memory size
-#
-# @prefetch: if @type is 'memory', true if the memory is prefetchable
-#
-# @mem_type_64: if @type is 'memory', true if the BAR is 64-bit
-#
-# Since: 0.14.0
-##
-{ 'struct': 'PciMemoryRegion',
- 'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
- '*prefetch': 'bool', '*mem_type_64': 'bool' } }
-
-##
-# @PciBusInfo:
-#
-# Information about a bus of a PCI Bridge device
-#
-# @number: primary bus interface number. This should be the number of the
-# bus the device resides on.
-#
-# @secondary: secondary bus interface number. This is the number of the
-# main bus for the bridge
-#
-# @subordinate: This is the highest number bus that resides below the
-# bridge.
-#
-# @io_range: The PIO range for all devices on this bridge
-#
-# @memory_range: The MMIO range for all devices on this bridge
-#
-# @prefetchable_range: The range of prefetchable MMIO for all devices on
-# this bridge
-#
-# Since: 2.4
-##
-{ 'struct': 'PciBusInfo',
- 'data': {'number': 'int', 'secondary': 'int', 'subordinate': 'int',
- 'io_range': 'PciMemoryRange',
- 'memory_range': 'PciMemoryRange',
- 'prefetchable_range': 'PciMemoryRange' } }
-
-##
-# @PciBridgeInfo:
-#
-# Information about a PCI Bridge device
-#
-# @bus: information about the bus the device resides on
-#
-# @devices: a list of @PciDeviceInfo for each device on this bridge
-#
-# Since: 0.14.0
-##
-{ 'struct': 'PciBridgeInfo',
- 'data': {'bus': 'PciBusInfo', '*devices': ['PciDeviceInfo']} }
-
-##
-# @PciDeviceClass:
-#
-# Information about the Class of a PCI device
-#
-# @desc: a string description of the device's class
-#
-# @class: the class code of the device
-#
-# Since: 2.4
-##
-{ 'struct': 'PciDeviceClass',
- 'data': {'*desc': 'str', 'class': 'int'} }
-
-##
-# @PciDeviceId:
-#
-# Information about the Id of a PCI device
-#
-# @device: the PCI device id
-#
-# @vendor: the PCI vendor id
-#
-# @subsystem: the PCI subsystem id (since 3.1)
-#
-# @subsystem-vendor: the PCI subsystem vendor id (since 3.1)
-#
-# Since: 2.4
-##
-{ 'struct': 'PciDeviceId',
- 'data': {'device': 'int', 'vendor': 'int', '*subsystem': 'int',
- '*subsystem-vendor': 'int'} }
-
-##
-# @PciDeviceInfo:
-#
-# Information about a PCI device
-#
-# @bus: the bus number of the device
-#
-# @slot: the slot the device is located in
-#
-# @function: the function of the slot used by the device
-#
-# @class_info: the class of the device
-#
-# @id: the PCI device id
-#
-# @irq: if an IRQ is assigned to the device, the IRQ number
-#
-# @irq_pin: the IRQ pin, zero means no IRQ (since 5.1)
-#
-# @qdev_id: the device name of the PCI device
-#
-# @pci_bridge: if the device is a PCI bridge, the bridge information
-#
-# @regions: a list of the PCI I/O regions associated with the device
-#
-# Notes: the contents of @class_info.desc are not stable and should only be
-# treated as informational.
-#
-# Since: 0.14.0
-##
-{ 'struct': 'PciDeviceInfo',
- 'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
- 'class_info': 'PciDeviceClass', 'id': 'PciDeviceId',
- '*irq': 'int', 'irq_pin': 'int', 'qdev_id': 'str',
- '*pci_bridge': 'PciBridgeInfo', 'regions': ['PciMemoryRegion'] }}
-
-##
-# @PciInfo:
-#
-# Information about a PCI bus
-#
-# @bus: the bus index
-#
-# @devices: a list of devices on this bus
-#
-# Since: 0.14.0
-##
-{ 'struct': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
-
-##
-# @query-pci:
-#
-# Return information about the PCI bus topology of the guest.
-#
-# Returns: a list of @PciInfo for each PCI bus. Each bus is
-# represented by a json-object, which has a key with a json-array of
-# all PCI devices attached to it. Each device is represented by a
-# json-object.
-#
-# Since: 0.14.0
-#
-# Example:
-#
-# -> { "execute": "query-pci" }
-# <- { "return": [
-# {
-# "bus": 0,
-# "devices": [
-# {
-# "bus": 0,
-# "qdev_id": "",
-# "slot": 0,
-# "class_info": {
-# "class": 1536,
-# "desc": "Host bridge"
-# },
-# "id": {
-# "device": 32902,
-# "vendor": 4663
-# },
-# "function": 0,
-# "regions": [
-# ]
-# },
-# {
-# "bus": 0,
-# "qdev_id": "",
-# "slot": 1,
-# "class_info": {
-# "class": 1537,
-# "desc": "ISA bridge"
-# },
-# "id": {
-# "device": 32902,
-# "vendor": 28672
-# },
-# "function": 0,
-# "regions": [
-# ]
-# },
-# {
-# "bus": 0,
-# "qdev_id": "",
-# "slot": 1,
-# "class_info": {
-# "class": 257,
-# "desc": "IDE controller"
-# },
-# "id": {
-# "device": 32902,
-# "vendor": 28688
-# },
-# "function": 1,
-# "regions": [
-# {
-# "bar": 4,
-# "size": 16,
-# "address": 49152,
-# "type": "io"
-# }
-# ]
-# },
-# {
-# "bus": 0,
-# "qdev_id": "",
-# "slot": 2,
-# "class_info": {
-# "class": 768,
-# "desc": "VGA controller"
-# },
-# "id": {
-# "device": 4115,
-# "vendor": 184
-# },
-# "function": 0,
-# "regions": [
-# {
-# "prefetch": true,
-# "mem_type_64": false,
-# "bar": 0,
-# "size": 33554432,
-# "address": 4026531840,
-# "type": "memory"
-# },
-# {
-# "prefetch": false,
-# "mem_type_64": false,
-# "bar": 1,
-# "size": 4096,
-# "address": 4060086272,
-# "type": "memory"
-# },
-# {
-# "prefetch": false,
-# "mem_type_64": false,
-# "bar": 6,
-# "size": 65536,
-# "address": -1,
-# "type": "memory"
-# }
-# ]
-# },
-# {
-# "bus": 0,
-# "qdev_id": "",
-# "irq": 11,
-# "slot": 4,
-# "class_info": {
-# "class": 1280,
-# "desc": "RAM controller"
-# },
-# "id": {
-# "device": 6900,
-# "vendor": 4098
-# },
-# "function": 0,
-# "regions": [
-# {
-# "bar": 0,
-# "size": 32,
-# "address": 49280,
-# "type": "io"
-# }
-# ]
-# }
-# ]
-# }
-# ]
-# }
-#
-# Note: This example has been shortened as the real response is too long.
-#
-##
-{ 'command': 'query-pci', 'returns': ['PciInfo'] }
-
-##
# @stop:
#
# Stop all guest VCPU execution.
@@ -787,32 +362,6 @@
{ 'command': 'inject-nmi' }
##
-# @balloon:
-#
-# Request the balloon driver to change its balloon size.
-#
-# @value: the target size of the balloon in bytes
-#
-# Returns: - Nothing on success
-# - If the balloon driver is enabled but not functional because the KVM
-# kernel module cannot support it, KvmMissingCap
-# - If no balloon device is present, DeviceNotActive
-#
-# Notes: This command just issues a request to the guest. When it returns,
-# the balloon size may not have changed. A guest can change the balloon
-# size independent of this command.
-#
-# Since: 0.14.0
-#
-# Example:
-#
-# -> { "execute": "balloon", "arguments": { "value": 536870912 } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'balloon', 'data': {'value': 'int'} }
-
-##
# @human-monitor-command:
#
# Execute a command on the human monitor and return the output.
@@ -972,39 +521,6 @@
{ 'command': 'closefd', 'data': {'fdname': 'str'} }
##
-# @MemoryInfo:
-#
-# Actual memory information in bytes.
-#
-# @base-memory: size of "base" memory specified with command line
-# option -m.
-#
-# @plugged-memory: size of memory that can be hot-unplugged. This field
-# is omitted if target doesn't support memory hotplug
-# (i.e. CONFIG_MEM_DEVICE not defined at build time).
-#
-# Since: 2.11.0
-##
-{ 'struct': 'MemoryInfo',
- 'data' : { 'base-memory': 'size', '*plugged-memory': 'size' } }
-
-##
-# @query-memory-size-summary:
-#
-# Return the amount of initially allocated and present hotpluggable (if
-# enabled) memory in bytes.
-#
-# Example:
-#
-# -> { "execute": "query-memory-size-summary" }
-# <- { "return": { "base-memory": 4294967296, "plugged-memory": 0 } }
-#
-# Since: 2.11.0
-##
-{ 'command': 'query-memory-size-summary', 'returns': 'MemoryInfo' }
-
-
-##
# @AddfdInfo:
#
# Information about a file descriptor that was added to an fd set.
@@ -1149,64 +665,6 @@
{ 'command': 'query-fdsets', 'returns': ['FdsetInfo'] }
##
-# @AcpiTableOptions:
-#
-# Specify an ACPI table on the command line to load.
-#
-# At most one of @file and @data can be specified. The list of files specified
-# by any one of them is loaded and concatenated in order. If both are omitted,
-# @data is implied.
-#
-# Other fields / optargs can be used to override fields of the generic ACPI
-# table header; refer to the ACPI specification 5.0, section 5.2.6 System
-# Description Table Header. If a header field is not overridden, then the
-# corresponding value from the concatenated blob is used (in case of @file), or
-# it is filled in with a hard-coded value (in case of @data).
-#
-# String fields are copied into the matching ACPI member from lowest address
-# upwards, and silently truncated / NUL-padded to length.
-#
-# @sig: table signature / identifier (4 bytes)
-#
-# @rev: table revision number (dependent on signature, 1 byte)
-#
-# @oem_id: OEM identifier (6 bytes)
-#
-# @oem_table_id: OEM table identifier (8 bytes)
-#
-# @oem_rev: OEM-supplied revision number (4 bytes)
-#
-# @asl_compiler_id: identifier of the utility that created the table
-# (4 bytes)
-#
-# @asl_compiler_rev: revision number of the utility that created the
-# table (4 bytes)
-#
-# @file: colon (:) separated list of pathnames to load and
-# concatenate as table data. The resultant binary blob is expected to
-# have an ACPI table header. At least one file is required. This field
-# excludes @data.
-#
-# @data: colon (:) separated list of pathnames to load and
-# concatenate as table data. The resultant binary blob must not have an
-# ACPI table header. At least one file is required. This field excludes
-# @file.
-#
-# Since: 1.5
-##
-{ 'struct': 'AcpiTableOptions',
- 'data': {
- '*sig': 'str',
- '*rev': 'uint8',
- '*oem_id': 'str',
- '*oem_table_id': 'str',
- '*oem_rev': 'uint32',
- '*asl_compiler_id': 'str',
- '*asl_compiler_rev': 'uint32',
- '*file': 'str',
- '*data': 'str' }}
-
-##
# @CommandLineParameterType:
#
# Possible types for an option parameter.
@@ -1300,263 +758,6 @@
'allow-preconfig': true }
##
-# @PCDIMMDeviceInfo:
-#
-# PCDIMMDevice state information
-#
-# @id: device's ID
-#
-# @addr: physical address, where device is mapped
-#
-# @size: size of memory that the device provides
-#
-# @slot: slot number at which device is plugged in
-#
-# @node: NUMA node number where device is plugged in
-#
-# @memdev: memory backend linked with device
-#
-# @hotplugged: true if device was hotplugged
-#
-# @hotpluggable: true if device if could be added/removed while machine is running
-#
-# Since: 2.1
-##
-{ 'struct': 'PCDIMMDeviceInfo',
- 'data': { '*id': 'str',
- 'addr': 'int',
- 'size': 'int',
- 'slot': 'int',
- 'node': 'int',
- 'memdev': 'str',
- 'hotplugged': 'bool',
- 'hotpluggable': 'bool'
- }
-}
-
-##
-# @VirtioPMEMDeviceInfo:
-#
-# VirtioPMEM state information
-#
-# @id: device's ID
-#
-# @memaddr: physical address in memory, where device is mapped
-#
-# @size: size of memory that the device provides
-#
-# @memdev: memory backend linked with device
-#
-# Since: 4.1
-##
-{ 'struct': 'VirtioPMEMDeviceInfo',
- 'data': { '*id': 'str',
- 'memaddr': 'size',
- 'size': 'size',
- 'memdev': 'str'
- }
-}
-
-##
-# @VirtioMEMDeviceInfo:
-#
-# VirtioMEMDevice state information
-#
-# @id: device's ID
-#
-# @memaddr: physical address in memory, where device is mapped
-#
-# @requested-size: the user requested size of the device
-#
-# @size: the (current) size of memory that the device provides
-#
-# @max-size: the maximum size of memory that the device can provide
-#
-# @block-size: the block size of memory that the device provides
-#
-# @node: NUMA node number where device is assigned to
-#
-# @memdev: memory backend linked with the region
-#
-# Since: 5.1
-##
-{ 'struct': 'VirtioMEMDeviceInfo',
- 'data': { '*id': 'str',
- 'memaddr': 'size',
- 'requested-size': 'size',
- 'size': 'size',
- 'max-size': 'size',
- 'block-size': 'size',
- 'node': 'int',
- 'memdev': 'str'
- }
-}
-
-##
-# @MemoryDeviceInfo:
-#
-# Union containing information about a memory device
-#
-# nvdimm is included since 2.12. virtio-pmem is included since 4.1.
-# virtio-mem is included since 5.1.
-#
-# Since: 2.1
-##
-{ 'union': 'MemoryDeviceInfo',
- 'data': { 'dimm': 'PCDIMMDeviceInfo',
- 'nvdimm': 'PCDIMMDeviceInfo',
- 'virtio-pmem': 'VirtioPMEMDeviceInfo',
- 'virtio-mem': 'VirtioMEMDeviceInfo'
- }
-}
-
-##
-# @query-memory-devices:
-#
-# Lists available memory devices and their state
-#
-# Since: 2.1
-#
-# Example:
-#
-# -> { "execute": "query-memory-devices" }
-# <- { "return": [ { "data":
-# { "addr": 5368709120,
-# "hotpluggable": true,
-# "hotplugged": true,
-# "id": "d1",
-# "memdev": "/objects/memX",
-# "node": 0,
-# "size": 1073741824,
-# "slot": 0},
-# "type": "dimm"
-# } ] }
-#
-##
-{ 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
-
-##
-# @MEMORY_DEVICE_SIZE_CHANGE:
-#
-# Emitted when the size of a memory device changes. Only emitted for memory
-# devices that can actually change the size (e.g., virtio-mem due to guest
-# action).
-#
-# @id: device's ID
-# @size: the new size of memory that the device provides
-#
-# Note: this event is rate-limited.
-#
-# Since: 5.1
-#
-# Example:
-#
-# <- { "event": "MEMORY_DEVICE_SIZE_CHANGE",
-# "data": { "id": "vm0", "size": 1073741824},
-# "timestamp": { "seconds": 1588168529, "microseconds": 201316 } }
-#
-##
-{ 'event': 'MEMORY_DEVICE_SIZE_CHANGE',
- 'data': { '*id': 'str', 'size': 'size' } }
-
-
-##
-# @MEM_UNPLUG_ERROR:
-#
-# Emitted when memory hot unplug error occurs.
-#
-# @device: device name
-#
-# @msg: Informative message
-#
-# Since: 2.4
-#
-# Example:
-#
-# <- { "event": "MEM_UNPLUG_ERROR"
-# "data": { "device": "dimm1",
-# "msg": "acpi: device unplug for unsupported device"
-# },
-# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-#
-##
-{ 'event': 'MEM_UNPLUG_ERROR',
- 'data': { 'device': 'str', 'msg': 'str' } }
-
-##
-# @ACPISlotType:
-#
-# @DIMM: memory slot
-# @CPU: logical CPU slot (since 2.7)
-##
-{ 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
-
-##
-# @ACPIOSTInfo:
-#
-# OSPM Status Indication for a device
-# For description of possible values of @source and @status fields
-# see "_OST (OSPM Status Indication)" chapter of ACPI5.0 spec.
-#
-# @device: device ID associated with slot
-#
-# @slot: slot ID, unique per slot of a given @slot-type
-#
-# @slot-type: type of the slot
-#
-# @source: an integer containing the source event
-#
-# @status: an integer containing the status code
-#
-# Since: 2.1
-##
-{ 'struct': 'ACPIOSTInfo',
- 'data' : { '*device': 'str',
- 'slot': 'str',
- 'slot-type': 'ACPISlotType',
- 'source': 'int',
- 'status': 'int' } }
-
-##
-# @query-acpi-ospm-status:
-#
-# Return a list of ACPIOSTInfo for devices that support status
-# reporting via ACPI _OST method.
-#
-# Since: 2.1
-#
-# Example:
-#
-# -> { "execute": "query-acpi-ospm-status" }
-# <- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
-# { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
-# { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
-# { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
-# ]}
-#
-##
-{ 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
-
-##
-# @ACPI_DEVICE_OST:
-#
-# Emitted when guest executes ACPI _OST method.
-#
-# @info: OSPM Status Indication
-#
-# Since: 2.1
-#
-# Example:
-#
-# <- { "event": "ACPI_DEVICE_OST",
-# "data": { "device": "d1", "slot": "0",
-# "slot-type": "DIMM", "source": 1, "status": 0 } }
-#
-##
-{ 'event': 'ACPI_DEVICE_OST',
- 'data': { 'info': 'ACPIOSTInfo' } }
-
-##
# @ReplayMode:
#
# Mode of the replay subsystem.
@@ -1594,24 +795,3 @@
#
##
{ 'command': 'xen-load-devices-state', 'data': {'filename': 'str'} }
-
-##
-# @GuidInfo:
-#
-# GUID information.
-#
-# @guid: the globally unique identifier
-#
-# Since: 2.9
-##
-{ 'struct': 'GuidInfo', 'data': {'guid': 'str'} }
-
-##
-# @query-vm-generation-id:
-#
-# Show Virtual Machine Generation ID
-#
-# Since: 2.9
-##
-{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
-
diff --git a/qapi/pci.json b/qapi/pci.json
new file mode 100644
index 0000000..b79cbd7
--- /dev/null
+++ b/qapi/pci.json
@@ -0,0 +1,316 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+##
+# = PCI
+##
+
+##
+# @PciMemoryRange:
+#
+# A PCI device memory region
+#
+# @base: the starting address (guest physical)
+#
+# @limit: the ending address (guest physical)
+#
+# Since: 0.14.0
+##
+{ 'struct': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
+
+##
+# @PciMemoryRegion:
+#
+# Information about a PCI device I/O region.
+#
+# @bar: the index of the Base Address Register for this region
+#
+# @type: - 'io' if the region is a PIO region
+# - 'memory' if the region is a MMIO region
+#
+# @size: memory size
+#
+# @prefetch: if @type is 'memory', true if the memory is prefetchable
+#
+# @mem_type_64: if @type is 'memory', true if the BAR is 64-bit
+#
+# Since: 0.14.0
+##
+{ 'struct': 'PciMemoryRegion',
+ 'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
+ '*prefetch': 'bool', '*mem_type_64': 'bool' } }
+
+##
+# @PciBusInfo:
+#
+# Information about a bus of a PCI Bridge device
+#
+# @number: primary bus interface number. This should be the number of the
+# bus the device resides on.
+#
+# @secondary: secondary bus interface number. This is the number of the
+# main bus for the bridge
+#
+# @subordinate: This is the highest number bus that resides below the
+# bridge.
+#
+# @io_range: The PIO range for all devices on this bridge
+#
+# @memory_range: The MMIO range for all devices on this bridge
+#
+# @prefetchable_range: The range of prefetchable MMIO for all devices on
+# this bridge
+#
+# Since: 2.4
+##
+{ 'struct': 'PciBusInfo',
+ 'data': {'number': 'int', 'secondary': 'int', 'subordinate': 'int',
+ 'io_range': 'PciMemoryRange',
+ 'memory_range': 'PciMemoryRange',
+ 'prefetchable_range': 'PciMemoryRange' } }
+
+##
+# @PciBridgeInfo:
+#
+# Information about a PCI Bridge device
+#
+# @bus: information about the bus the device resides on
+#
+# @devices: a list of @PciDeviceInfo for each device on this bridge
+#
+# Since: 0.14.0
+##
+{ 'struct': 'PciBridgeInfo',
+ 'data': {'bus': 'PciBusInfo', '*devices': ['PciDeviceInfo']} }
+
+##
+# @PciDeviceClass:
+#
+# Information about the Class of a PCI device
+#
+# @desc: a string description of the device's class
+#
+# @class: the class code of the device
+#
+# Since: 2.4
+##
+{ 'struct': 'PciDeviceClass',
+ 'data': {'*desc': 'str', 'class': 'int'} }
+
+##
+# @PciDeviceId:
+#
+# Information about the Id of a PCI device
+#
+# @device: the PCI device id
+#
+# @vendor: the PCI vendor id
+#
+# @subsystem: the PCI subsystem id (since 3.1)
+#
+# @subsystem-vendor: the PCI subsystem vendor id (since 3.1)
+#
+# Since: 2.4
+##
+{ 'struct': 'PciDeviceId',
+ 'data': {'device': 'int', 'vendor': 'int', '*subsystem': 'int',
+ '*subsystem-vendor': 'int'} }
+
+##
+# @PciDeviceInfo:
+#
+# Information about a PCI device
+#
+# @bus: the bus number of the device
+#
+# @slot: the slot the device is located in
+#
+# @function: the function of the slot used by the device
+#
+# @class_info: the class of the device
+#
+# @id: the PCI device id
+#
+# @irq: if an IRQ is assigned to the device, the IRQ number
+#
+# @irq_pin: the IRQ pin, zero means no IRQ (since 5.1)
+#
+# @qdev_id: the device name of the PCI device
+#
+# @pci_bridge: if the device is a PCI bridge, the bridge information
+#
+# @regions: a list of the PCI I/O regions associated with the device
+#
+# Notes: the contents of @class_info.desc are not stable and should only be
+# treated as informational.
+#
+# Since: 0.14.0
+##
+{ 'struct': 'PciDeviceInfo',
+ 'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
+ 'class_info': 'PciDeviceClass', 'id': 'PciDeviceId',
+ '*irq': 'int', 'irq_pin': 'int', 'qdev_id': 'str',
+ '*pci_bridge': 'PciBridgeInfo', 'regions': ['PciMemoryRegion'] }}
+
+##
+# @PciInfo:
+#
+# Information about a PCI bus
+#
+# @bus: the bus index
+#
+# @devices: a list of devices on this bus
+#
+# Since: 0.14.0
+##
+{ 'struct': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
+
+##
+# @query-pci:
+#
+# Return information about the PCI bus topology of the guest.
+#
+# Returns: a list of @PciInfo for each PCI bus. Each bus is
+# represented by a json-object, which has a key with a json-array of
+# all PCI devices attached to it. Each device is represented by a
+# json-object.
+#
+# Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-pci" }
+# <- { "return": [
+# {
+# "bus": 0,
+# "devices": [
+# {
+# "bus": 0,
+# "qdev_id": "",
+# "slot": 0,
+# "class_info": {
+# "class": 1536,
+# "desc": "Host bridge"
+# },
+# "id": {
+# "device": 32902,
+# "vendor": 4663
+# },
+# "function": 0,
+# "regions": [
+# ]
+# },
+# {
+# "bus": 0,
+# "qdev_id": "",
+# "slot": 1,
+# "class_info": {
+# "class": 1537,
+# "desc": "ISA bridge"
+# },
+# "id": {
+# "device": 32902,
+# "vendor": 28672
+# },
+# "function": 0,
+# "regions": [
+# ]
+# },
+# {
+# "bus": 0,
+# "qdev_id": "",
+# "slot": 1,
+# "class_info": {
+# "class": 257,
+# "desc": "IDE controller"
+# },
+# "id": {
+# "device": 32902,
+# "vendor": 28688
+# },
+# "function": 1,
+# "regions": [
+# {
+# "bar": 4,
+# "size": 16,
+# "address": 49152,
+# "type": "io"
+# }
+# ]
+# },
+# {
+# "bus": 0,
+# "qdev_id": "",
+# "slot": 2,
+# "class_info": {
+# "class": 768,
+# "desc": "VGA controller"
+# },
+# "id": {
+# "device": 4115,
+# "vendor": 184
+# },
+# "function": 0,
+# "regions": [
+# {
+# "prefetch": true,
+# "mem_type_64": false,
+# "bar": 0,
+# "size": 33554432,
+# "address": 4026531840,
+# "type": "memory"
+# },
+# {
+# "prefetch": false,
+# "mem_type_64": false,
+# "bar": 1,
+# "size": 4096,
+# "address": 4060086272,
+# "type": "memory"
+# },
+# {
+# "prefetch": false,
+# "mem_type_64": false,
+# "bar": 6,
+# "size": 65536,
+# "address": -1,
+# "type": "memory"
+# }
+# ]
+# },
+# {
+# "bus": 0,
+# "qdev_id": "",
+# "irq": 11,
+# "slot": 4,
+# "class_info": {
+# "class": 1280,
+# "desc": "RAM controller"
+# },
+# "id": {
+# "device": 6900,
+# "vendor": 4098
+# },
+# "function": 0,
+# "regions": [
+# {
+# "bar": 0,
+# "size": 32,
+# "address": 49280,
+# "type": "io"
+# }
+# ]
+# }
+# ]
+# }
+# ]
+# }
+#
+# Note: This example has been shortened as the real response is too long.
+#
+##
+{ 'command': 'query-pci', 'returns': ['PciInfo'] }
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index f03ff91..0c6ca5c 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -21,8 +21,10 @@
#
# Example:
#
-# | -> data issued by the Client
-# | <- Server data response
+# ::
+#
+# -> data issued by the Client
+# <- Server data response
#
# Please, refer to the QMP specification (docs/interop/qmp-spec.txt) for
# detailed information on the Server command and response formats.
@@ -85,3 +87,5 @@
{ 'include': 'misc.json' }
{ 'include': 'misc-target.json' }
{ 'include': 'audio.json' }
+{ 'include': 'acpi.json' }
+{ 'include': 'pci.json' }
diff --git a/qga/meson.build b/qga/meson.build
index e5c5778..1c312b5 100644
--- a/qga/meson.build
+++ b/qga/meson.build
@@ -16,7 +16,7 @@ qga_qapi_outputs = [
]
qga_qapi_files = custom_target('QGA QAPI files',
- output: qga_qapi_outputs + ['qga-qapi-doc.texi'],
+ output: qga_qapi_outputs,
input: 'qapi-schema.json',
command: [ qapi_gen, '-o', 'qga', '-p', 'qga-', '@INPUT0@' ],
depend_files: qapi_gen_depends)
@@ -27,7 +27,6 @@ foreach output: qga_qapi_outputs
qga_ss.add(qga_qapi_files[i])
i = i + 1
endforeach
-qga_qapi_doc_texi = qga_qapi_files[i]
qga_ss.add(files(
'commands.c',
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index d2ea744..cec98c7 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -2,14 +2,16 @@
# vim: filetype=python
##
-#
-# General note concerning the use of guest agent interfaces:
+# = General note concerning the use of guest agent interfaces
#
# "unsupported" is a higher-level error than the errors that individual
# commands might document. The caller should always be prepared to receive
# QERR_UNSUPPORTED, even if the given command doesn't specify it, or doesn't
# document any failure mode at all.
-#
+##
+
+##
+# = QEMU guest agent protocol commands and structs
##
{ 'pragma': { 'doc-required': true } }
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 5091089..1ba8a38 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1659,7 +1659,7 @@ sub process {
# tabs are only allowed in assembly source code, and in
# some scripts we imported from other projects.
next if ($realfile =~ /\.(s|S)$/);
- next if ($realfile =~ /(checkpatch|get_maintainer|texi2pod)\.pl$/);
+ next if ($realfile =~ /(checkpatch|get_maintainer)\.pl$/);
if ($rawline =~ /^\+.*\t/) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
diff --git a/scripts/coverity-scan/coverity-scan.docker b/scripts/coverity-scan/coverity-scan.docker
index 018c03d..501ac67 100644
--- a/scripts/coverity-scan/coverity-scan.docker
+++ b/scripts/coverity-scan/coverity-scan.docker
@@ -110,7 +110,6 @@ ENV PACKAGES \
systemd-devel \
systemtap-sdt-devel \
tar \
- texinfo \
usbredir-devel \
virglrenderer-devel \
vte291-devel \
diff --git a/scripts/git.orderfile b/scripts/git.orderfile
index a021afc..3736c1d 100644
--- a/scripts/git.orderfile
+++ b/scripts/git.orderfile
@@ -12,7 +12,6 @@
# Documentation
docs/*
*.rst
-*.texi
# build system
configure
diff --git a/scripts/qapi-gen.py b/scripts/qapi-gen.py
index 4b03f7d..541e8c1 100644
--- a/scripts/qapi-gen.py
+++ b/scripts/qapi-gen.py
@@ -10,7 +10,6 @@ import re
import sys
from qapi.commands import gen_commands
-from qapi.doc import gen_doc
from qapi.events import gen_events
from qapi.introspect import gen_introspect
from qapi.schema import QAPIError, QAPISchema
@@ -51,7 +50,6 @@ def main(argv):
gen_commands(schema, args.output_dir, args.prefix)
gen_events(schema, args.output_dir, args.prefix)
gen_introspect(schema, args.output_dir, args.prefix, args.unmask)
- gen_doc(schema, args.output_dir, args.prefix)
if __name__ == '__main__':
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
deleted file mode 100644
index 92f584e..0000000
--- a/scripts/qapi/doc.py
+++ /dev/null
@@ -1,301 +0,0 @@
-# QAPI texi generator
-#
-# This work is licensed under the terms of the GNU LGPL, version 2+.
-# See the COPYING file in the top-level directory.
-"""This script produces the documentation of a qapi schema in texinfo format"""
-
-import re
-from qapi.gen import QAPIGenDoc, QAPISchemaVisitor
-
-
-MSG_FMT = """
-@deftypefn {type} {{}} {name}
-
-{body}{members}{features}{sections}
-@end deftypefn
-
-""".format
-
-TYPE_FMT = """
-@deftp {{{type}}} {name}
-
-{body}{members}{features}{sections}
-@end deftp
-
-""".format
-
-EXAMPLE_FMT = """@example
-{code}
-@end example
-""".format
-
-
-def subst_strong(doc):
- """Replaces *foo* by @strong{foo}"""
- return re.sub(r'\*([^*\n]+)\*', r'@strong{\1}', doc)
-
-
-def subst_emph(doc):
- """Replaces _foo_ by @emph{foo}"""
- return re.sub(r'\b_([^_\n]+)_\b', r'@emph{\1}', doc)
-
-
-def subst_vars(doc):
- """Replaces @var by @code{var}"""
- return re.sub(r'@([\w-]+)', r'@code{\1}', doc)
-
-
-def subst_braces(doc):
- """Replaces {} with @{ @}"""
- return doc.replace('{', '@{').replace('}', '@}')
-
-
-def texi_example(doc):
- """Format @example"""
- # TODO: Neglects to escape @ characters.
- # We should probably escape them in subst_braces(), and rename the
- # function to subst_special() or subs_texi_special(). If we do that, we
- # need to delay it until after subst_vars() in texi_format().
- doc = subst_braces(doc).strip('\n')
- return EXAMPLE_FMT(code=doc)
-
-
-def texi_format(doc):
- """
- Format documentation
-
- Lines starting with:
- - |: generates an @example
- - =: generates @section
- - ==: generates @subsection
- - 1. or 1): generates an @enumerate @item
- - */-: generates an @itemize list
- """
- ret = ''
- doc = subst_braces(doc)
- doc = subst_vars(doc)
- doc = subst_emph(doc)
- doc = subst_strong(doc)
- inlist = ''
- lastempty = False
- for line in doc.split('\n'):
- empty = line == ''
-
- # FIXME: Doing this in a single if / elif chain is
- # problematic. For instance, a line without markup terminates
- # a list if it follows a blank line (reaches the final elif),
- # but a line with some *other* markup, such as a = title
- # doesn't.
- #
- # Make sure to update section "Documentation markup" in
- # docs/devel/qapi-code-gen.txt when fixing this.
- if line.startswith('| '):
- line = EXAMPLE_FMT(code=line[2:])
- elif line.startswith('= '):
- line = '@section ' + line[2:]
- elif line.startswith('== '):
- line = '@subsection ' + line[3:]
- elif re.match(r'^([0-9]*\.) ', line):
- if not inlist:
- ret += '@enumerate\n'
- inlist = 'enumerate'
- ret += '@item\n'
- line = line[line.find(' ')+1:]
- elif re.match(r'^[*-] ', line):
- if not inlist:
- ret += '@itemize %s\n' % {'*': '@bullet',
- '-': '@minus'}[line[0]]
- inlist = 'itemize'
- ret += '@item\n'
- line = line[2:]
- elif lastempty and inlist:
- ret += '@end %s\n\n' % inlist
- inlist = ''
-
- lastempty = empty
- ret += line + '\n'
-
- if inlist:
- ret += '@end %s\n\n' % inlist
- return ret
-
-
-def texi_body(doc):
- """Format the main documentation body"""
- return texi_format(doc.body.text)
-
-
-def texi_if(ifcond, prefix='\n', suffix='\n'):
- """Format the #if condition"""
- if not ifcond:
- return ''
- return '%s@b{If:} @code{%s}%s' % (prefix, ', '.join(ifcond), suffix)
-
-
-def texi_enum_value(value, desc, suffix):
- """Format a table of members item for an enumeration value"""
- return '@item @code{%s}\n%s%s' % (
- value.name, desc, texi_if(value.ifcond, prefix='@*'))
-
-
-def texi_member(member, desc, suffix):
- """Format a table of members item for an object type member"""
- typ = member.type.doc_type()
- membertype = ': ' + typ if typ else ''
- return '@item @code{%s%s}%s%s\n%s%s' % (
- member.name, membertype,
- ' (optional)' if member.optional else '',
- suffix, desc, texi_if(member.ifcond, prefix='@*'))
-
-
-def texi_members(doc, what, base=None, variants=None,
- member_func=texi_member):
- """Format the table of members"""
- items = ''
- for section in doc.args.values():
- # TODO Drop fallbacks when undocumented members are outlawed
- if section.text:
- desc = texi_format(section.text)
- elif (variants and variants.tag_member == section.member
- and not section.member.type.doc_type()):
- values = section.member.type.member_names()
- members_text = ', '.join(['@t{"%s"}' % v for v in values])
- desc = 'One of ' + members_text + '\n'
- else:
- desc = 'Not documented\n'
- items += member_func(section.member, desc, suffix='')
- if base:
- items += '@item The members of @code{%s}\n' % base.doc_type()
- if variants:
- for v in variants.variants:
- when = ' when @code{%s} is @t{"%s"}%s' % (
- variants.tag_member.name, v.name, texi_if(v.ifcond, " (", ")"))
- if v.type.is_implicit():
- assert not v.type.base and not v.type.variants
- for m in v.type.local_members:
- items += member_func(m, desc='', suffix=when)
- else:
- items += '@item The members of @code{%s}%s\n' % (
- v.type.doc_type(), when)
- if not items:
- return ''
- return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
-
-
-def texi_arguments(doc, boxed_arg_type):
- if boxed_arg_type:
- assert not doc.args
- return ('\n@b{Arguments:} the members of @code{%s}\n'
- % boxed_arg_type.name)
- return texi_members(doc, 'Arguments')
-
-
-def texi_features(doc):
- """Format the table of features"""
- items = ''
- for section in doc.features.values():
- desc = texi_format(section.text)
- items += '@item @code{%s}\n%s' % (section.name, desc)
- if not items:
- return ''
- return '\n@b{Features:}\n@table @asis\n%s@end table\n' % (items)
-
-
-def texi_sections(doc, ifcond):
- """Format additional sections following arguments"""
- body = ''
- for section in doc.sections:
- if section.name:
- # prefer @b over @strong, so txt doesn't translate it to *Foo:*
- body += '\n@b{%s:}\n' % section.name
- if section.name and section.name.startswith('Example'):
- body += texi_example(section.text)
- else:
- body += texi_format(section.text)
- body += texi_if(ifcond, suffix='')
- return body
-
-
-def texi_type(typ, doc, ifcond, members):
- return TYPE_FMT(type=typ,
- name=doc.symbol,
- body=texi_body(doc),
- members=members,
- features=texi_features(doc),
- sections=texi_sections(doc, ifcond))
-
-
-def texi_msg(typ, doc, ifcond, members):
- return MSG_FMT(type=typ,
- name=doc.symbol,
- body=texi_body(doc),
- members=members,
- features=texi_features(doc),
- sections=texi_sections(doc, ifcond))
-
-
-class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
- def __init__(self, prefix):
- self._prefix = prefix
- self._gen = QAPIGenDoc(self._prefix + 'qapi-doc.texi')
- self.cur_doc = None
-
- def write(self, output_dir):
- self._gen.write(output_dir)
-
- def visit_enum_type(self, name, info, ifcond, features, members, prefix):
- doc = self.cur_doc
- self._gen.add(texi_type('Enum', doc, ifcond,
- texi_members(doc, 'Values',
- member_func=texi_enum_value)))
-
- def visit_object_type(self, name, info, ifcond, features,
- base, members, variants):
- doc = self.cur_doc
- if base and base.is_implicit():
- base = None
- self._gen.add(texi_type('Object', doc, ifcond,
- texi_members(doc, 'Members', base, variants)))
-
- def visit_alternate_type(self, name, info, ifcond, features, variants):
- doc = self.cur_doc
- self._gen.add(texi_type('Alternate', doc, ifcond,
- texi_members(doc, 'Members')))
-
- def visit_command(self, name, info, ifcond, features,
- arg_type, ret_type, gen, success_response, boxed,
- allow_oob, allow_preconfig):
- doc = self.cur_doc
- self._gen.add(texi_msg('Command', doc, ifcond,
- texi_arguments(doc,
- arg_type if boxed else None)))
-
- def visit_event(self, name, info, ifcond, features, arg_type, boxed):
- doc = self.cur_doc
- self._gen.add(texi_msg('Event', doc, ifcond,
- texi_arguments(doc,
- arg_type if boxed else None)))
-
- def symbol(self, doc, entity):
- if self._gen._body:
- self._gen.add('\n')
- self.cur_doc = doc
- entity.visit(self)
- self.cur_doc = None
-
- def freeform(self, doc):
- assert not doc.args
- if self._gen._body:
- self._gen.add('\n')
- self._gen.add(texi_body(doc) + texi_sections(doc, None))
-
-
-def gen_doc(schema, output_dir, prefix):
- vis = QAPISchemaGenDocVisitor(prefix)
- vis.visit_begin(schema)
- for doc in schema.docs:
- if doc.symbol:
- vis.symbol(doc, schema.lookup_entity(doc.symbol))
- else:
- vis.freeform(doc)
- vis.write(output_dir)
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
index bf5552a..ca66c82 100644
--- a/scripts/qapi/gen.py
+++ b/scripts/qapi/gen.py
@@ -178,13 +178,6 @@ def ifcontext(ifcond, *args):
arg.end_if()
-class QAPIGenDoc(QAPIGen):
-
- def _top(self):
- return (super()._top()
- + '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')
-
-
class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):
def __init__(self, prefix, what, blurb, pydoc):
diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py
index 165925c..9d1a3e2 100644
--- a/scripts/qapi/parser.py
+++ b/scripts/qapi/parser.py
@@ -319,17 +319,32 @@ class QAPIDoc:
"""
class Section:
- def __init__(self, name=None):
+ def __init__(self, parser, name=None, indent=0):
+ # parser, for error messages about indentation
+ self._parser = parser
# optional section name (argument/member or section name)
self.name = name
self.text = ''
+ # the expected indent level of the text of this section
+ self._indent = indent
def append(self, line):
+ # Strip leading spaces corresponding to the expected indent level
+ # Blank lines are always OK.
+ if line:
+ indent = re.match(r'\s*', line).end()
+ if indent < self._indent:
+ raise QAPIParseError(
+ self._parser,
+ "unexpected de-indent (expected at least %d spaces)" %
+ self._indent)
+ line = line[self._indent:]
+
self.text += line.rstrip() + '\n'
class ArgSection(Section):
- def __init__(self, name):
- super().__init__(name)
+ def __init__(self, parser, name, indent=0):
+ super().__init__(parser, name, indent)
self.member = None
def connect(self, member):
@@ -343,7 +358,7 @@ class QAPIDoc:
self._parser = parser
self.info = info
self.symbol = None
- self.body = QAPIDoc.Section()
+ self.body = QAPIDoc.Section(parser)
# dict mapping parameter name to ArgSection
self.args = OrderedDict()
self.features = OrderedDict()
@@ -427,10 +442,10 @@ class QAPIDoc:
self._append_line = self._append_various_line
self._append_various_line(line)
else:
- self._append_freeform(line.strip())
+ self._append_freeform(line)
else:
# This is a free-form documentation block
- self._append_freeform(line.strip())
+ self._append_freeform(line)
def _append_args_line(self, line):
"""
@@ -447,8 +462,21 @@ class QAPIDoc:
name = line.split(' ', 1)[0]
if name.startswith('@') and name.endswith(':'):
- line = line[len(name)+1:]
- self._start_args_section(name[1:-1])
+ # If line is "@arg: first line of description", find
+ # the index of 'f', which is the indent we expect for any
+ # following lines. We then remove the leading "@arg:"
+ # from line and replace it with spaces so that 'f' has the
+ # same index as it did in the original line and can be
+ # handled the same way we will handle following lines.
+ indent = re.match(r'@\S*:\s*', line).end()
+ line = line[indent:]
+ if not line:
+ # Line was just the "@arg:" header; following lines
+ # are not indented
+ indent = 0
+ else:
+ line = ' ' * indent + line
+ self._start_args_section(name[1:-1], indent)
elif self._is_section_tag(name):
self._append_line = self._append_various_line
self._append_various_line(line)
@@ -463,14 +491,27 @@ class QAPIDoc:
self._append_various_line(line)
return
- self._append_freeform(line.strip())
+ self._append_freeform(line)
def _append_features_line(self, line):
name = line.split(' ', 1)[0]
if name.startswith('@') and name.endswith(':'):
- line = line[len(name)+1:]
- self._start_features_section(name[1:-1])
+ # If line is "@arg: first line of description", find
+ # the index of 'f', which is the indent we expect for any
+ # following lines. We then remove the leading "@arg:"
+ # from line and replace it with spaces so that 'f' has the
+ # same index as it did in the original line and can be
+ # handled the same way we will handle following lines.
+ indent = re.match(r'@\S*:\s*', line).end()
+ line = line[indent:]
+ if not line:
+ # Line was just the "@arg:" header; following lines
+ # are not indented
+ indent = 0
+ else:
+ line = ' ' * indent + line
+ self._start_features_section(name[1:-1], indent)
elif self._is_section_tag(name):
self._append_line = self._append_various_line
self._append_various_line(line)
@@ -482,7 +523,7 @@ class QAPIDoc:
self._append_various_line(line)
return
- self._append_freeform(line.strip())
+ self._append_freeform(line)
def _append_various_line(self, line):
"""
@@ -502,16 +543,25 @@ class QAPIDoc:
"'%s' can't follow '%s' section"
% (name, self.sections[0].name))
if self._is_section_tag(name):
- line = line[len(name)+1:]
- self._start_section(name[:-1])
-
- if (not self._section.name or
- not self._section.name.startswith('Example')):
- line = line.strip()
+ # If line is "Section: first line of description", find
+ # the index of 'f', which is the indent we expect for any
+ # following lines. We then remove the leading "Section:"
+ # from line and replace it with spaces so that 'f' has the
+ # same index as it did in the original line and can be
+ # handled the same way we will handle following lines.
+ indent = re.match(r'\S*:\s*', line).end()
+ line = line[indent:]
+ if not line:
+ # Line was just the "Section:" header; following lines
+ # are not indented
+ indent = 0
+ else:
+ line = ' ' * indent + line
+ self._start_section(name[:-1], indent)
self._append_freeform(line)
- def _start_symbol_section(self, symbols_dict, name):
+ def _start_symbol_section(self, symbols_dict, name, indent):
# FIXME invalid names other than the empty string aren't flagged
if not name:
raise QAPIParseError(self._parser, "invalid parameter name")
@@ -520,21 +570,21 @@ class QAPIDoc:
"'%s' parameter name duplicated" % name)
assert not self.sections
self._end_section()
- self._section = QAPIDoc.ArgSection(name)
+ self._section = QAPIDoc.ArgSection(self._parser, name, indent)
symbols_dict[name] = self._section
- def _start_args_section(self, name):
- self._start_symbol_section(self.args, name)
+ def _start_args_section(self, name, indent):
+ self._start_symbol_section(self.args, name, indent)
- def _start_features_section(self, name):
- self._start_symbol_section(self.features, name)
+ def _start_features_section(self, name, indent):
+ self._start_symbol_section(self.features, name, indent)
- def _start_section(self, name=None):
+ def _start_section(self, name=None, indent=0):
if name in ('Returns', 'Since') and self.has_section(name):
raise QAPIParseError(self._parser,
"duplicated '%s' section" % name)
self._end_section()
- self._section = QAPIDoc.Section(name)
+ self._section = QAPIDoc.Section(self._parser, name, indent)
self.sections.append(self._section)
def _end_section(self):
@@ -557,7 +607,8 @@ class QAPIDoc:
def connect_member(self, member):
if member.name not in self.args:
# Undocumented TODO outlaw
- self.args[member.name] = QAPIDoc.ArgSection(member.name)
+ self.args[member.name] = QAPIDoc.ArgSection(self._parser,
+ member.name)
self.args[member.name].connect(member)
def connect_feature(self, feature):
diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl
deleted file mode 100755
index 8bfc6f6..0000000
--- a/scripts/texi2pod.pl
+++ /dev/null
@@ -1,536 +0,0 @@
-#! /usr/bin/env perl
-
-# Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
-
-# This file is part of GCC.
-
-# GCC is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# GCC is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with GCC; see the file COPYING. If not,
-# see <http://www.gnu.org/licenses/>.
-
-# This does trivial (and I mean _trivial_) conversion of Texinfo
-# markup to Perl POD format. It's intended to be used to extract
-# something suitable for a manpage from a Texinfo document.
-
-use warnings;
-
-$output = 0;
-$skipping = 0;
-%sects = ();
-$section = "";
-@icstack = ();
-@endwstack = ();
-@skstack = ();
-@instack = ();
-$shift = "";
-%defs = ();
-$fnno = 1;
-$inf = "";
-$ibase = "";
-@ipath = ();
-$encoding = undef;
-@args = ();
-
-while ($_ = shift) {
- if (/^-D(.*)$/) {
- if ($1 ne "") {
- $flag = $1;
- } else {
- $flag = shift;
- }
- $value = "";
- ($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
- die "no flag specified for -D\n"
- unless $flag ne "";
- die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
- unless $flag =~ /^[a-zA-Z0-9_-]+$/;
- $defs{$flag} = $value;
- } elsif (/^-I(.*)$/) {
- if ($1 ne "") {
- $flag = $1;
- } else {
- $flag = shift;
- }
- push (@ipath, $flag);
- } elsif (/^-/) {
- usage();
- } else {
- $in = $_, next unless defined $in;
- $out = $_, next unless defined $out;
- usage();
- }
-}
-
-if (defined $in) {
- $inf = gensym();
- open($inf, "<$in") or die "opening \"$in\": $!\n";
- $ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
-} else {
- $inf = \*STDIN;
-}
-
-if (defined $out) {
- open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
-}
-
-while(defined $inf) {
-while(<$inf>) {
- # Certain commands are discarded without further processing.
- /^\@(?:
- [a-z]+index # @*index: useful only in complete manual
- |need # @need: useful only in printed manual
- |(?:end\s+)?group # @group .. @end group: ditto
- |page # @page: ditto
- |node # @node: useful only in .info file
- |(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents
- )\b/x and next;
-
- chomp;
-
- # Look for filename and title markers.
- /^\@setfilename\s+([^.]+)/ and $fn = $1, next;
- /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
-
- # Look for document encoding
- /^\@documentencoding\s+([^.]+)/ and do {
- $encoding = $1 unless defined $encoding;
- next;
- };
-
- # Identify a man title but keep only the one we are interested in.
- /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
- if (exists $defs{$1}) {
- $fn = $1;
- $tl = postprocess($2);
- }
- next;
- };
-
- # Look for blocks surrounded by @c man begin SECTION ... @c man end.
- # This really oughta be @ifman ... @end ifman and the like, but such
- # would require rev'ing all other Texinfo translators.
- /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
- $output = 1 if exists $defs{$2};
- $sect = $1;
- next;
- };
- /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
- /^\@c\s+man\s+end/ and do {
- $sects{$sect} = "" unless exists $sects{$sect};
- $sects{$sect} .= postprocess($section);
- $section = "";
- $output = 0;
- next;
- };
-
- # handle variables
- /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
- $defs{$1} = $2;
- next;
- };
- /^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
- delete $defs{$1};
- next;
- };
-
- # Single line command handlers.
-
- /^\@include\s+(.+)$/ and do {
- push @instack, $inf;
- $inf = gensym();
- $file = postprocess($1);
-
- # Try cwd and $ibase, then explicit -I paths.
- $done = 0;
- foreach $path ("", $ibase, @ipath) {
- $mypath = $file;
- $mypath = $path . "/" . $mypath if ($path ne "");
- open($inf, "<" . $mypath) and ($done = 1, last);
- }
- die "cannot find $file" if !$done;
- next;
- };
-
- next unless $output;
-
- # Discard comments. (Can't do it above, because then we'd never see
- # @c man lines.)
- /^\@c\b/ and next;
-
- # End-block handler goes up here because it needs to operate even
- # if we are skipping.
- /^\@end\s+([a-z]+)/ and do {
- # Ignore @end foo, where foo is not an operation which may
- # cause us to skip, if we are presently skipping.
- my $ended = $1;
- next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex|copying)$/;
-
- die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
- die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
-
- $endw = pop @endwstack;
-
- if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
- $skipping = pop @skstack;
- next;
- } elsif ($ended =~ /^(?:example|smallexample|display
- |quotation|deftp|deftypefn)$/x) {
- $shift = "";
- $_ = ""; # need a paragraph break
- } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
- $_ = "\n=back\n";
- $ic = pop @icstack;
- } elsif ($ended eq "multitable") {
- $_ = "\n=back\n";
- } else {
- die "unknown command \@end $ended at line $.\n";
- }
- };
-
- # We must handle commands which can cause skipping even while we
- # are skipping, otherwise we will not process nested conditionals
- # correctly.
- /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
- push @endwstack, $endw;
- push @skstack, $skipping;
- $endw = "ifset";
- $skipping = 1 unless exists $defs{$1};
- next;
- };
-
- /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
- push @endwstack, $endw;
- push @skstack, $skipping;
- $endw = "ifclear";
- $skipping = 1 if exists $defs{$1};
- next;
- };
-
- /^\@(ignore|menu|iftex|copying)\b/ and do {
- push @endwstack, $endw;
- push @skstack, $skipping;
- $endw = $1;
- $skipping = 1;
- next;
- };
-
- next if $skipping;
-
- # Character entities. First the ones that can be replaced by raw text
- # or discarded outright:
- s/\@copyright\{\}/(c)/g;
- s/\@dots\{\}/.../g;
- s/\@enddots\{\}/..../g;
- s/\@([.!? ])/$1/g;
- s/\@[:-]//g;
- s/\@bullet(?:\{\})?/*/g;
- s/\@TeX\{\}/TeX/g;
- s/\@pounds\{\}/\#/g;
- s/\@minus(?:\{\})?/-/g;
- s/\\,/,/g;
-
- # Now the ones that have to be replaced by special escapes
- # (which will be turned back into text by unmunge())
- s/&/&amp;/g;
- s/\@\{/&lbrace;/g;
- s/\@\}/&rbrace;/g;
- s/\@\@/&at;/g;
-
- # Inside a verbatim block, handle @var specially.
- if ($shift ne "") {
- s/\@var\{([^\}]*)\}/<$1>/g;
- }
-
- # POD doesn't interpret E<> inside a verbatim block.
- if ($shift eq "") {
- s/</&lt;/g;
- s/>/&gt;/g;
- } else {
- s/</&LT;/g;
- s/>/&GT;/g;
- }
-
- /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
- and $_ = "\n=head2 $1\n";
- /^\@subsection\s+(.+)$/
- and $_ = "\n=head3 $1\n";
- /^\@subsubsection\s+(.+)$/
- and $_ = "\n=head4 $1\n";
-
- # Block command handlers:
- /^\@itemize(?:\s+(\@[a-z]+|\*|-))?/ and do {
- push @endwstack, $endw;
- push @icstack, $ic;
- if (defined $1) {
- $ic = $1;
- } else {
- $ic = '*';
- }
- $_ = "\n=over 4\n";
- $endw = "itemize";
- };
-
- /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
- push @endwstack, $endw;
- push @icstack, $ic;
- if (defined $1) {
- $ic = $1 . ".";
- } else {
- $ic = "1.";
- }
- $_ = "\n=over 4\n";
- $endw = "enumerate";
- };
-
- /^\@multitable\s.*/ and do {
- push @endwstack, $endw;
- $endw = "multitable";
- $_ = "\n=over 4\n";
- };
-
- /^\@([fv]?table)\s+(\@[a-z]+)/ and do {
- push @endwstack, $endw;
- push @icstack, $ic;
- $endw = $1;
- $ic = $2;
- $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
- $ic =~ s/\@(?:code|kbd)/C/;
- $ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
- $ic =~ s/\@(?:file)/F/;
- $ic =~ s/\@(?:asis)//;
- $_ = "\n=over 4\n";
- };
-
- /^\@((?:small)?example|display)/ and do {
- push @endwstack, $endw;
- $endw = $1;
- $shift = "\t";
- $_ = ""; # need a paragraph break
- };
-
- /^\@item\s+(.*\S)\s*$/ and $endw eq "multitable" and do {
- @columns = ();
- for $column (split (/\s*\@tab\s*/, $1)) {
- # @strong{...} is used a @headitem work-alike
- $column =~ s/^\@strong\{(.*)\}$/$1/;
- push @columns, $column;
- }
- $_ = "\n=item ".join (" : ", @columns)."\n";
- };
-
- /^\@(quotation)\s*(.+)?$/ and do {
- push @endwstack, $endw;
- $endw = $1;
- $_ = "\n$2:"
- };
-
- /^{(.*)}$|^(.*)$/ and $#args > 0 and do {
- $kind = $args[0];
- $arguments = $1 // "";
- if ($endw eq "deftypefn") {
- $ret = $args[1];
- $fname = "B<$args[2]>";
- $_ = $ret ? "$ret " : "";
- $_ .= "$fname $arguments ($kind)";
- } else {
- $_ = "B<$args[1]> ($kind)\n\n$arguments";
- }
- @args = ();
- };
-
- /^\@(deftp)\s*(.+)?$/ and do {
- push @endwstack, $endw;
- $endw = $1;
- $arg = $2;
- $arg =~ s/{([^}]*)}/$1/g;
- $arg =~ s/\@$//;
- @args = split (/ /, $arg);
- $_ = "";
- };
-
- /^\@(deftypefn)\s*(.+)?$/ and do {
- push @endwstack, $endw;
- $endw = $1;
- $arg = $2;
- $arg =~ s/{([^}]*)}/$1/g;
- $arg =~ s/\@$//;
- @args = split (/ /, $arg);
- $_ = "";
- };
-
- /^\@itemx?\s*(.+)?$/ and do {
- if (defined $1) {
- if ($ic eq "") {
- $_ = "\n=item $1\n";
- } else {
- # Entity escapes prevent munging by the <> processing below.
- $_ = "\n=item $ic\&LT;$1\&GT;\n";
- }
- } else {
- $_ = "\n=item $ic\n";
- $ic =~ y/A-Ya-y/B-Zb-z/;
- $ic =~ s/(\d+)/$1 + 1/eg;
- }
- };
-
- $section .= $shift.$_."\n";
-}
-# End of current file.
-close($inf);
-$inf = pop @instack;
-}
-
-die "No filename or title\n" unless defined $fn && defined $tl;
-
-print "=encoding $encoding\n\n" if defined $encoding;
-
-$sects{NAME} = "$fn \- $tl\n";
-$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
-
-for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
- BUGS NOTES FOOTNOTES EXAMPLES SEEALSO AUTHOR COPYRIGHT)) {
- if(exists $sects{$sect}) {
- $head = $sect;
- $head =~ s/SEEALSO/SEE ALSO/;
- print "=head1 $head\n\n";
- print scalar unmunge ($sects{$sect});
- print "\n";
- }
-}
-
-sub usage
-{
- die "usage: $0 [-D toggle...] [infile [outfile]]\n";
-}
-
-sub postprocess
-{
- local $_ = $_[0];
-
- # @value{foo} is replaced by whatever 'foo' is defined as.
- while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
- if (! exists $defs{$2}) {
- print STDERR "Option $2 not defined\n";
- s/\Q$1\E//;
- } else {
- $value = $defs{$2};
- s/\Q$1\E/$value/;
- }
- }
-
- # Formatting commands.
- # Temporary escape for @r.
- s/\@r\{([^\}]*)\}/R<$1>/g;
- s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
- s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
- s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
- s/\@sc\{([^\}]*)\}/\U$1/g;
- s/\@file\{([^\}]*)\}/F<$1>/g;
- s/\@w\{([^\}]*)\}/S<$1>/g;
- s/\@t\{([^\}]*)\}/$1/g;
- s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
-
- # keep references of the form @ref{...}, print them bold
- s/\@(?:ref)\{([^\}]*)\}/B<$1>/g;
-
- # Change double single quotes to double quotes.
- s/''/"/g;
- s/``/"/g;
-
- # Cross references are thrown away, as are @noindent and @refill.
- # (@noindent is impossible in .pod, and @refill is unnecessary.)
- # @* is also impossible in .pod; we discard it and any newline that
- # follows it. Similarly, our macro @gol must be discarded.
-
- s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
- s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
- s/;\s+\@pxref\{(?:[^\}]*)\}//g;
- s/\@noindent\s*//g;
- s/\@refill//g;
- s/\@gol//g;
- s/\@\*\s*\n?//g;
-
- # Anchors are thrown away
- s/\@anchor\{(?:[^\}]*)\}//g;
-
- # @uref can take one, two, or three arguments, with different
- # semantics each time. @url and @email are just like @uref with
- # one argument, for our purposes.
- s/\@(?:uref|url|email)\{([^\},]*)\}/&lt;B<$1>&gt;/g;
- s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
- s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
-
- # Un-escape <> at this point.
- s/&LT;/</g;
- s/&GT;/>/g;
-
- # Now un-nest all B<>, I<>, R<>. Theoretically we could have
- # indefinitely deep nesting; in practice, one level suffices.
- 1 while s/([BIR])<([^<>]*)([BIR])<([^<>]*)>/$1<$2>$3<$4>$1</g;
-
- # Replace R<...> with bare ...; eliminate empty markup, B<>;
- # shift white space at the ends of [BI]<...> expressions outside
- # the expression.
- s/R<([^<>]*)>/$1/g;
- s/[BI]<>//g;
- s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
- s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
-
- # Extract footnotes. This has to be done after all other
- # processing because otherwise the regexp will choke on formatting
- # inside @footnote.
- while (/\@footnote/g) {
- s/\@footnote\{([^\}]+)\}/[$fnno]/;
- add_footnote($1, $fnno);
- $fnno++;
- }
-
- return $_;
-}
-
-sub unmunge
-{
- # Replace escaped symbols with their equivalents.
- local $_ = $_[0];
-
- s/&lt;/E<lt>/g;
- s/&gt;/E<gt>/g;
- s/&lbrace;/\{/g;
- s/&rbrace;/\}/g;
- s/&at;/\@/g;
- s/&amp;/&/g;
- return $_;
-}
-
-sub add_footnote
-{
- unless (exists $sects{FOOTNOTES}) {
- $sects{FOOTNOTES} = "\n=over 4\n\n";
- }
-
- $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
- $sects{FOOTNOTES} .= $_[0];
- $sects{FOOTNOTES} .= "\n\n";
-}
-
-# stolen from Symbol.pm
-{
- my $genseq = 0;
- sub gensym
- {
- my $name = "GEN" . $genseq++;
- my $ref = \*{$name};
- delete $::{$name};
- return $ref;
- }
-}
diff --git a/softmmu/balloon.c b/softmmu/balloon.c
index 2345229..e0e8969 100644
--- a/softmmu/balloon.c
+++ b/softmmu/balloon.c
@@ -29,7 +29,7 @@
#include "sysemu/kvm.h"
#include "sysemu/balloon.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-machine.h"
#include "qapi/qmp/qerror.h"
#include "trace.h"
diff --git a/storage-daemon/qapi/meson.build b/storage-daemon/qapi/meson.build
index cea618b..cd064ac 100644
--- a/storage-daemon/qapi/meson.build
+++ b/storage-daemon/qapi/meson.build
@@ -1,5 +1,5 @@
qsd_qapi_files = custom_target('QAPI files for qemu-storage-daemon',
- output: qapi_nonmodule_outputs + ['qapi-doc.texi'],
+ output: qapi_nonmodule_outputs,
input: [ files('qapi-schema.json') ],
command: [ qapi_gen, '-o', 'storage-daemon/qapi', '@INPUT@' ],
depend_files: [ qapi_inputs, qapi_gen_depends ])
diff --git a/stubs/uuid.c b/stubs/uuid.c
index 67f182f..e5112eb 100644
--- a/stubs/uuid.c
+++ b/stubs/uuid.c
@@ -1,5 +1,5 @@
#include "qemu/osdep.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-machine.h"
#include "qemu/uuid.h"
UuidInfo *qmp_query_uuid(Error **errp)
diff --git a/stubs/vmgenid.c b/stubs/vmgenid.c
index 568e42b..bfad656 100644
--- a/stubs/vmgenid.c
+++ b/stubs/vmgenid.c
@@ -1,6 +1,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-machine.h"
#include "qapi/qmp/qerror.h"
GuidInfo *qmp_query_vm_generation_id(Error **errp)
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index e3c11a4..1e4188b 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -31,7 +31,6 @@ RUN apt update && \
python3 \
python3-setuptools \
python3-sphinx \
- texinfo \
$(apt-get -s build-dep qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2)
ENV FEATURES docs
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 70b6186..71e4b56 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -96,7 +96,6 @@ ENV PACKAGES \
tar \
tesseract \
tesseract-langpack-eng \
- texinfo \
usbredir-devel \
virglrenderer-devel \
vte291-devel \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index 161806e..b556ed1 100644
--- a/tests/docker/dockerfiles/ubuntu.docker
+++ b/tests/docker/dockerfiles/ubuntu.docker
@@ -63,7 +63,6 @@ ENV PACKAGES \
python3-yaml \
python3-sphinx \
sparse \
- texinfo \
xfslibs-dev
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index a10ea28..a6a7617 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -49,7 +49,6 @@ ENV PACKAGES \
python3-yaml \
python3-sphinx \
sparse \
- texinfo \
xfslibs-dev
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 8d10934..cafe844 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -57,7 +57,6 @@ ENV PACKAGES flex bison \
sparse \
tesseract-ocr \
tesseract-ocr-eng \
- texinfo \
xfslibs-dev\
vim
RUN apt-get update && \
diff --git a/tests/qapi-schema/doc-bad-indent.err b/tests/qapi-schema/doc-bad-indent.err
new file mode 100644
index 0000000..6784453
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-indent.err
@@ -0,0 +1 @@
+doc-bad-indent.json:6:1: unexpected de-indent (expected at least 4 spaces)
diff --git a/tests/qapi-schema/doc-bad-indent.json b/tests/qapi-schema/doc-bad-indent.json
new file mode 100644
index 0000000..edde8f2
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-indent.json
@@ -0,0 +1,8 @@
+# Multiline doc comments should have consistent indentation
+
+##
+# @foo:
+# @a: line one
+# line two is wrongly indented
+##
+{ 'command': 'foo', 'data': { 'a': 'int' } }
diff --git a/tests/qapi-schema/doc-bad-indent.out b/tests/qapi-schema/doc-bad-indent.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-indent.out
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 9da72a1..e9af085 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -10,27 +10,27 @@
#
# == Subsection
#
-# *strong* _with emphasis_
+# *with emphasis*
# @var {in braces}
+#
# * List item one
-# - Two, multiple
+# * Two, multiple
# lines
#
-# 3. Three
-# Still in list
+# * Three
+# Still in list
+#
+# Not in list
#
-# Not in list
# - Second list
-# Note: still in list
+# Note: still in list
#
# Note: not in list
+#
# 1. Third list
# is numbered
#
-# - another item
-#
-# | example
-# | multiple lines
+# 2. another item
#
# Returns: the King
# Since: the first age
@@ -68,7 +68,7 @@
##
# @Base:
# @base1:
-# the first member
+# the first member
##
{ 'struct': 'Base', 'data': { 'base1': 'Enum' } }
@@ -116,7 +116,7 @@
##
# @Alternate:
# @i: an integer
-# @b is undocumented
+# @b is undocumented
#
# Features:
# @alt-feat: a feature
@@ -134,7 +134,7 @@
# @arg1: the first argument
#
# @arg2: the second
-# argument
+# argument
#
# Features:
# @cmd-feat1: a feature
@@ -143,6 +143,7 @@
# Returns: @Object
# TODO: frobnicate
# Notes:
+#
# - Lorem ipsum dolor sit amet
# - Ut enim ad minim veniam
#
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index d78a424..419284d 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -73,27 +73,27 @@ doc freeform
body=
== Subsection
-*strong* _with emphasis_
+*with emphasis*
@var {in braces}
+
* List item one
-- Two, multiple
-lines
+* Two, multiple
+ lines
-3. Three
-Still in list
+* Three
+ Still in list
Not in list
+
- Second list
-Note: still in list
+ Note: still in list
Note: not in list
-1. Third list
-is numbered
-- another item
+1. Third list
+ is numbered
-| example
-| multiple lines
+2. another item
Returns: the King
Since: the first age
diff --git a/tests/qapi-schema/doc-good.rst b/tests/qapi-schema/doc-good.rst
new file mode 100644
index 0000000..1e4c233
--- /dev/null
+++ b/tests/qapi-schema/doc-good.rst
@@ -0,0 +1,5 @@
+..
+ Test Sphinx manual that pulls in the test schema file. We will generate
+ a plain-text output file and compare it against a reference.
+
+.. qapi-doc:: tests/qapi-schema/doc-good.json
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
deleted file mode 100644
index 7f28fb7..0000000
--- a/tests/qapi-schema/doc-good.texi
+++ /dev/null
@@ -1,319 +0,0 @@
-@c AUTOMATICALLY GENERATED, DO NOT MODIFY
-
-@section Section
-
-@subsection Subsection
-
-@strong{strong} @emph{with emphasis}
-@code{var} @{in braces@}
-@itemize @bullet
-@item
-List item one
-@item
-Two, multiple
-lines
-
-@item
-Three
-Still in list
-
-@end itemize
-
-Not in list
-@itemize @minus
-@item
-Second list
-Note: still in list
-
-@end itemize
-
-Note: not in list
-@enumerate
-@item
-Third list
-is numbered
-
-@item
-another item
-
-@example
-example
-@end example
-
-@example
-multiple lines
-@end example
-
-
-@end enumerate
-
-Returns: the King
-Since: the first age
-Notes:
-
-@enumerate
-@item
-Lorem ipsum dolor sit amet
-
-@item
-Ut enim ad minim veniam
-
-@end enumerate
-
-Duis aute irure dolor
-
-Example:
-
--> in
-<- out
-Examples:
-@itemize @minus
-@item
-@strong{verbatim}
-@item
-@{braces@}
-@end itemize
-
-
-
-@deftp {Enum} Enum
-
-
-
-@b{Values:}
-@table @asis
-@item @code{one}
-The @emph{one} @{and only@}
-@*@b{If:} @code{defined(IFONE)}
-@item @code{two}
-Not documented
-@end table
-
-@b{Features:}
-@table @asis
-@item @code{enum-feat}
-Also @emph{one} @{and only@}
-@end table
-@code{two} is undocumented
-
-@b{If:} @code{defined(IFCOND)}
-@end deftp
-
-
-
-@deftp {Object} Base
-
-
-
-@b{Members:}
-@table @asis
-@item @code{base1: Enum}
-the first member
-@end table
-
-@end deftp
-
-
-
-@deftp {Object} Variant1
-
-A paragraph
-
-Another paragraph (but no @code{var}: line)
-
-@b{Members:}
-@table @asis
-@item @code{var1: string}
-Not documented
-@*@b{If:} @code{defined(IFSTR)}
-@end table
-
-@b{Features:}
-@table @asis
-@item @code{variant1-feat}
-a feature
-@item @code{member-feat}
-a member feature
-@end table
-
-@end deftp
-
-
-
-@deftp {Object} Variant2
-
-
-
-@end deftp
-
-
-
-@deftp {Object} Object
-
-
-
-@b{Members:}
-@table @asis
-@item The members of @code{Base}
-@item The members of @code{Variant1} when @code{base1} is @t{"one"}
-@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{IFTWO})
-@end table
-
-@b{Features:}
-@table @asis
-@item @code{union-feat1}
-a feature
-@end table
-
-@end deftp
-
-
-
-@deftp {Object} SugaredUnion
-
-
-
-@b{Members:}
-@table @asis
-@item @code{type}
-One of @t{"one"}, @t{"two"}
-@item @code{data: Variant1} when @code{type} is @t{"one"}
-@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{IFTWO})
-@end table
-
-@b{Features:}
-@table @asis
-@item @code{union-feat2}
-a feature
-@end table
-
-@end deftp
-
-
-
-@deftp {Alternate} Alternate
-
-
-
-@b{Members:}
-@table @asis
-@item @code{i: int}
-an integer
-@code{b} is undocumented
-@item @code{b: boolean}
-Not documented
-@end table
-
-@b{Features:}
-@table @asis
-@item @code{alt-feat}
-a feature
-@end table
-
-@end deftp
-
-
-@subsection Another subsection
-
-
-@deftypefn Command {} cmd
-
-
-
-@b{Arguments:}
-@table @asis
-@item @code{arg1: int}
-the first argument
-@item @code{arg2: string} (optional)
-the second
-argument
-@item @code{arg3: boolean}
-Not documented
-@end table
-
-@b{Features:}
-@table @asis
-@item @code{cmd-feat1}
-a feature
-@item @code{cmd-feat2}
-another feature
-@end table
-
-@b{Note:}
-@code{arg3} is undocumented
-
-@b{Returns:}
-@code{Object}
-
-@b{TODO:}
-frobnicate
-
-@b{Notes:}
-@itemize @minus
-@item
-Lorem ipsum dolor sit amet
-@item
-Ut enim ad minim veniam
-
-@end itemize
-
-Duis aute irure dolor
-
-@b{Example:}
-@example
--> in
-<- out
-@end example
-
-@b{Examples:}
-@example
-- *verbatim*
-- @{braces@}
-@end example
-
-@b{Since:}
-2.10
-
-@end deftypefn
-
-
-
-@deftypefn Command {} cmd-boxed
-
-If you're bored enough to read this, go see a video of boxed cats
-
-@b{Arguments:} the members of @code{Object}
-
-@b{Features:}
-@table @asis
-@item @code{cmd-feat1}
-a feature
-@item @code{cmd-feat2}
-another feature
-@end table
-
-@b{Example:}
-@example
--> in
-
-<- out
-@end example
-
-@end deftypefn
-
-
-
-@deftypefn Event {} EVT-BOXED
-
-
-
-@b{Arguments:} the members of @code{Object}
-
-@b{Features:}
-@table @asis
-@item @code{feat3}
-a feature
-@end table
-
-@end deftypefn
-
diff --git a/tests/qapi-schema/doc-good.txt b/tests/qapi-schema/doc-good.txt
new file mode 100644
index 0000000..6ca03d4
--- /dev/null
+++ b/tests/qapi-schema/doc-good.txt
@@ -0,0 +1,288 @@
+Section
+*******
+
+
+Subsection
+==========
+
+*with emphasis* "var" {in braces}
+
+* List item one
+
+* Two, multiple lines
+
+* Three Still in list
+
+Not in list
+
+* Second list Note: still in list
+
+Note: not in list
+
+1. Third list is numbered
+
+2. another item
+
+Returns: the King Since: the first age Notes:
+
+1. Lorem ipsum dolor sit amet
+
+2. Ut enim ad minim veniam
+
+Duis aute irure dolor
+
+Example:
+
+-> in <- out Examples: - *verbatim* - {braces}
+
+
+"Enum" (Enum)
+-------------
+
+
+Values
+~~~~~~
+
+"one" (**If: **"defined(IFONE)")
+ The _one_ {and only}
+
+"two"
+ Not documented
+
+
+Features
+~~~~~~~~
+
+"enum-feat"
+ Also _one_ {and only}
+
+"two" is undocumented
+
+
+If
+~~
+
+"defined(IFCOND)"
+
+
+"Base" (Object)
+---------------
+
+
+Members
+~~~~~~~
+
+"base1": "Enum"
+ the first member
+
+
+"Variant1" (Object)
+-------------------
+
+A paragraph
+
+Another paragraph (but no "var": line)
+
+
+Members
+~~~~~~~
+
+"var1": "string" (**If: **"defined(IFSTR)")
+ Not documented
+
+
+Features
+~~~~~~~~
+
+"variant1-feat"
+ a feature
+
+"member-feat"
+ a member feature
+
+
+"Variant2" (Object)
+-------------------
+
+
+"Object" (Object)
+-----------------
+
+
+Members
+~~~~~~~
+
+The members of "Base"
+The members of "Variant1" when "base1" is ""one""
+The members of "Variant2" when "base1" is ""two"" (**If: **"IFTWO")
+
+Features
+~~~~~~~~
+
+"union-feat1"
+ a feature
+
+
+"SugaredUnion" (Object)
+-----------------------
+
+
+Members
+~~~~~~~
+
+"type"
+ One of "one", "two"
+
+"data": "Variant1" when "type" is ""one""
+"data": "Variant2" when "type" is ""two"" (**If: **"IFTWO")
+
+Features
+~~~~~~~~
+
+"union-feat2"
+ a feature
+
+
+"Alternate" (Alternate)
+-----------------------
+
+
+Members
+~~~~~~~
+
+"i": "int"
+ an integer "b" is undocumented
+
+"b": "boolean"
+ Not documented
+
+
+Features
+~~~~~~~~
+
+"alt-feat"
+ a feature
+
+
+Another subsection
+==================
+
+
+"cmd" (Command)
+---------------
+
+
+Arguments
+~~~~~~~~~
+
+"arg1": "int"
+ the first argument
+
+"arg2": "string" (optional)
+ the second argument
+
+"arg3": "boolean"
+ Not documented
+
+
+Features
+~~~~~~~~
+
+"cmd-feat1"
+ a feature
+
+"cmd-feat2"
+ another feature
+
+
+Note
+~~~~
+
+"arg3" is undocumented
+
+
+Returns
+~~~~~~~
+
+"Object"
+
+
+TODO
+~~~~
+
+frobnicate
+
+
+Notes
+~~~~~
+
+* Lorem ipsum dolor sit amet
+
+* Ut enim ad minim veniam
+
+Duis aute irure dolor
+
+
+Example
+~~~~~~~
+
+ -> in
+ <- out
+
+
+Examples
+~~~~~~~~
+
+ - *verbatim*
+ - {braces}
+
+
+Since
+~~~~~
+
+2.10
+
+
+"cmd-boxed" (Command)
+---------------------
+
+If you're bored enough to read this, go see a video of boxed cats
+
+
+Arguments
+~~~~~~~~~
+
+The members of "Object"
+
+Features
+~~~~~~~~
+
+"cmd-feat1"
+ a feature
+
+"cmd-feat2"
+ another feature
+
+
+Example
+~~~~~~~
+
+ -> in
+
+ <- out
+
+
+"EVT-BOXED" (Event)
+-------------------
+
+
+Arguments
+~~~~~~~~~
+
+The members of "Object"
+
+Features
+~~~~~~~~
+
+"feat3"
+ a feature
diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
index f144929..f08c902 100644
--- a/tests/qapi-schema/meson.build
+++ b/tests/qapi-schema/meson.build
@@ -53,6 +53,7 @@ schemas = [
'doc-bad-enum-member.json',
'doc-bad-event-arg.json',
'doc-bad-feature.json',
+ 'doc-bad-indent.json',
'doc-bad-section.json',
'doc-bad-symbol.json',
'doc-bad-union-member.json',
@@ -205,8 +206,7 @@ test('QAPI schema regression tests', python, args: files('test-qapi.py', schemas
diff = find_program('diff')
qapi_doc = custom_target('QAPI doc',
- output: ['doc-good-qapi-doc.texi',
- 'doc-good-qapi-commands.c', 'doc-good-qapi-commands.h',
+ output: ['doc-good-qapi-commands.c', 'doc-good-qapi-commands.h',
'doc-good-qapi-emit-events.c', 'doc-good-qapi-emit-events.h',
'doc-good-qapi-events.c', 'doc-good-qapi-events.h',
'doc-good-qapi-init-commands.c', 'doc-good-qapi-init-commands.h',
@@ -218,8 +218,57 @@ qapi_doc = custom_target('QAPI doc',
'-p', 'doc-good-', '@INPUT0@' ],
depend_files: qapi_gen_depends)
-# "full_path()" needed here to work around
-# https://github.com/mesonbuild/meson/issues/7585
-test('QAPI doc', diff, args: ['-b', '-u', files('doc-good.texi'), qapi_doc[0].full_path()],
- depends: qapi_doc,
- suite: ['qapi-schema', 'qapi-doc'])
+# Test the document-comment document generation code by running a test schema
+# file through Sphinx's plain-text builder and comparing the result against
+# a golden reference. This is in theory susceptible to failures if Sphinx
+# changes its output, but the text output has historically been very stable
+# (no changes between Sphinx 1.6 and 3.0), so it is a better bet than
+# texinfo or HTML generation, both of which have had changes. We might
+# need to add more sophisticated logic here in future for some sort of
+# fuzzy comparison if future Sphinx versions produce different text,
+# but for now the simple comparison suffices.
+qapi_doc_out = custom_target('QAPI rST doc',
+ output: ['doc-good.txt'],
+ input: files('doc-good.json', 'doc-good.rst'),
+ build_by_default: build_docs,
+ depend_files: sphinx_extn_depends,
+ # We use -E to suppress Sphinx's caching, because
+ # we want it to always really run the QAPI doc
+ # generation code. It also means we don't
+ # clutter up the build dir with the cache.
+ command: [SPHINX_ARGS,
+ '-b', 'text', '-E',
+ '-c', meson.source_root() / 'docs',
+ '-D', 'master_doc=doc-good',
+ meson.current_source_dir(),
+ meson.current_build_dir()])
+
+# Fix possible inconsistency in line endings in generated output and
+# in the golden reference (which could otherwise cause test failures
+# on Windows hosts). Unfortunately diff --strip-trailing-cr
+# is GNU-diff only. The odd-looking perl is because we must avoid
+# using an explicit '\' character in the command arguments to
+# a custom_target(), as Meson will unhelpfully replace it with a '/'
+# (https://github.com/mesonbuild/meson/issues/1564)
+qapi_doc_out_nocr = custom_target('QAPI rST doc newline-sanitized',
+ output: ['doc-good.txt.nocr'],
+ input: qapi_doc_out[0],
+ build_by_default: build_docs,
+ command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'],
+ capture: true)
+
+qapi_doc_ref_nocr = custom_target('QAPI rST doc reference newline-sanitized',
+ output: ['doc-good.ref.nocr'],
+ input: files('doc-good.txt'),
+ build_by_default: build_docs,
+ command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'],
+ capture: true)
+
+if build_docs
+ # "full_path()" needed here to work around
+ # https://github.com/mesonbuild/meson/issues/7585
+ test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0].full_path(),
+ qapi_doc_out_nocr[0].full_path()],
+ depends: [qapi_doc_ref_nocr, qapi_doc_out_nocr],
+ suite: ['qapi-schema', 'qapi-doc'])
+endif