- 1 Code Transitions
- 2 Ongoing transitions
- 2.1 Making all devices QOM objects
- 2.2 Use DeviceClass::realize rather than SysBusDeviceClass::init
- 2.3 Using VMStateDescription rather than load and save functions
- 2.4 Coding whitespace and brace style
- 2.5 Error reporting
- 2.6 QMP legacy interface to the QAPI
- 2.7 Makefile
- 2.8 .gitignore
- 2.9 Modern shell scripting
- 2.10 I/O error reporting
- 2.11 I/O accounting
- 2.12 Command line option --readconfig
- 2.13 Guest CPUs should use do_transaction_failed, not do_unassigned_access
- 3 Completed transitions
This page exists to keep a record of API and style transitions in the QEMU codebase. It's quite common for us to introduce a new API or design guideline, but not be able to convert the whole of QEMU's existing code over to it at once. So at any point in time some of QEMU will still be using the old deprecated approaches.
The aim of this page is twofold:
- as a quick reference for less frequent contributors, to give an idea of things to avoid copying from old code
- to embarrass ourselves into maybe finishing off some of these transitions
If you add a new transition to this page, please also briefly mention it in the DeveloperNews page with a link to here.
Making all devices QOM objects
Ideally all device models should be QOM objects (usually deriving from DeviceState or one of its subclasses). However we still have a fairly large number of devices which are coded in an ad-hoc way. These should all be converted to QOM but it is a big job. See Documentation/QOMConventions for the latest guidance on how to structure a QOM device.
Use DeviceClass::realize rather than SysBusDeviceClass::init
All new devices derived from SysBusDevice should use QOM realize (DeviceClass::realize) rather than SysBusDeviceClass::init. Work is under way to convert existing devices. It is permissable to implement neither realize nor init. We have about 25 devices remaining in-tree which still use SysBusDeviceClass::init; best to convert a few at a time in collections that would go through the same submaintainer tree (eg convert three arm-board devices, not one arm, one ppc and one alpha).
(QOM realize was first presented by Anthony on the 2012-01-31 KVM call and after much debate of scope minimally implemented for DeviceState by Andreas for v1.4. Some extensions by Paolo (recursive realization) are still pending device preparations.)
Using VMStateDescription rather than load and save functions
The preferred way to implement state save/load for migration is to describe the device state using a VMStateDescription struct. Some devices are still using the old vmstate_register() API, however; these all need converting. (This is often going to involve also converting the device to use QOM.)
Coding whitespace and brace style
New QEMU code should follow the style guidelines in CODING_STYLE, and in particular this means 4-space indent, no hardcoded tab, braces on all if() statements. However much of the codebase is old and doesn't follow this. Changes to areas of existing code should generally update the lines of code they're touching anyway, but we prefer to avoid wholesale "fix coding style" patches because they obscure the change history for tools like "git blame".
Several transitions are in flight here:
- Avoid ErrorClass values other than ERROR_CLASS_GENERIC_ERROR unless you have a specific reason. Prefer error_setg() & friends over error_set() & friends.
- The QError macros QERR_ are a hack to help with the transition to the current error.h API (human-readable message rather than JSON argument, see commit df1e608). Avoid them in new code, use simple message strings instead.
- Use error_report() & friends instead of fprintf(stderr, ...). Unlike fprintf(), it does the right thing in human monitor context. It also adds program name and error location when appropriate, and supports timestamps (-msg timestamp=on).
QMP legacy interface to the QAPI
There are only a few QMP commands missing to be converted from the QMP legacy interface to the QAPI. The most important of them are do_device_add() and do_qmp_capabilities() (which may or may not need session support to be converted). You can find more details in the QMP TODO page.
Although object specific options are traditionally implemented with Target-specific Variable Values, such as
$(obj)/arm-a64.o: QEMU_CFLAGS += -I$(libvixldir)
, currently the cflags and libs should be specified as per-object variable in Makefile.objs and friends, which will be automatically expanded into the compiling and the linking commands. E.g. in block/Makefile.objs:
... iscsi.o-cflags := $(LIBISCSI_CFLAGS) iscsi.o-libs := $(LIBISCSI_LIBS) curl.o-cflags := $(CURL_CFLAGS) curl.o-libs := $(CURL_LIBS) ...
where $(obj)/ is not needed compared to the old way.
While CVS required an ignore file per directory, git allows for a single ignore file at the top of the tree to describe the entire project. We have an unfortunate mix of using the top file to ignore files in subdirectories, while using nested files to ignore other files. Ideally, there should be only a single top-level gitignore that covers everything for the project.
Modern shell scripting
Various shell files contain a mix between obsolete `` and modern $(); use of `` is only required when using /bin/sh on Solaris. It would be nice to convert to using $() everywhere, or at least in all bash scripts, as well as in all scripts that are known to not be run on Solaris. While at it, there are some other places we can simplify to rely on POSIX shell semantics, such as using $PWD instead of $(pwd).
I/O error reporting
[rw]error lets management take action upon I/O error, for example pausing the VM or taking some action in the host to enlarge a thin-provisioned volume. Not yet supported by qdevified devices with a qdev_prop_drive: isa-fdc, sysbus-fdc, SUNW,fdtwo, nand, onenand, cfi.pflash01, cfi.pflash02, spapr-nvram, scsi-generic, nvme. SD isn't in this list, because it still hasn't been qdevified. There may be more.
Even devices that have been qdevified have bugs: SCSI calls bdrv_error_action() when UNMAP fails, but IDE doesn't call it when TRIM fails. IDE and virtio-blk call it for I/O beyond the end of the medium, but SCSI doesn't.
This is also useful because rerror/werror on block jobs requires rerror/werror on the corresponding device. rerror/werror are needed to make reporting of block job error events robust (otherwise, block jobs just disappear and, if management misses BLOCK_JOB_COMPLETED events, it cannot poll to know if the job has completed successfully or not). It is not clear why this is a requirement, though.
I/O accounting collects data for query-blockstats. Device models should call bdrv_acct_start() and bdrv_acct_done() to make this work. Most of them still don't.
Command line option --readconfig
The config file doesn't cover all the command line options so far, only the ones implemented with QemuOpts.
Guest CPUs should use do_transaction_failed, not do_unassigned_access
Guest CPU architectures using the do_unassigned_access hook should be converted to use do_transaction_failed instead. This affects MIPS, Microblaze, m68k and SPARC. Note that this is a difficult conversion and will require familiarity with the target architecture and being able to audit its code to check for load/store accesses that may need changes. Changing the hook implementation itself is fairly straightforward, but the new hook will only cause guest exceptions for accesses made via guest virtual address, whereas the old hook would also cause guest exceptions for accesses made by physical address loads and stores. So all instances of physical address accesses in the target/whatever code need to be examined to determine what the required behaviour is if they get a bus fault, and to either implement this or at least put in a TODO comment documenting it. Commit 6ad4d7eed05a1e235 is an example of this conversion for Alpha (the critical part is the analysis in the commit message and comment!).
- QEMUMachine has been replaced with a QOM hierarchy, details on Features/QOM/Machine.
- Character devices have been replaced with a QOM hierarchy.
- Everything is using the MemoryRegion API now!
- Users of old_portio have all been updated and the support removed
- error_is_set(errp) has been dropped
- MemoryRegionOps old_mmio has been removed