Sorry for the length of this memo. I tried to make it as concise as I
could. And there's working mock-up source code to go with it.
Configuration should be data
----------------------------
A QEMU machine (selected with -M) is described by a struct QEMUMachine.
Which contains almost nothing of interest. Pretty much everything,
including all the buses and devices is instead created by the machine's
initialization function.
Init functions consider a plethora of ad hoc configuration parameters
set by command line options. Plenty of stuff remains hard-coded all
the same.
Configuration should be data, not code.
A machine's buses and devices can be expressed as a device tree. More
on that below.
The need for a configuration file
---------------------------------
The command line is a rather odd place to define a virtual machine.
Command line is fine for manipulating a particular run of the machine,
but the machine description belongs into a configuration file.
Once configuration is data, we should be able to initialize it from a
configuration file with relative ease.
However, this memo is only about the *internal* representation of
configuration. How we get there from a configuration file is a separate
question. It's without doubt a relevant question, but I feel I need to
limit my scope to have a chance of getting anywhere.
The need for an abstract device interface
-----------------------------------------
Currently, each virtual device is created, configured and initialized in
its own idiosyncratic way. Some configuration is received as arguments,
some is passed in global variables.
This is workable as long as the machine is constructed by ad hoc init
function code. The resulting init function tends to be quite a
hairball, though.
I'd like to propose an abstract device interface, so we can build a
machine from its (tree-structured) configuration using just this
interface. Device idiosyncrasies are to be hidden in the driver code
behind the interface.
What I propose to do
--------------------
A. Configuration as data
Define an internal machine configuration data structure. Needs to be
sufficiently generic to be able to support even oddball machine
types. Make it a decorated tree, i.e. a tree of named nodes with
named properties.
Create an instance for a prototype machine type. Make it a PC,
because that's the easiest to test.
Define an abstract device interface, initially covering just device
configuration and initialization.
Implement the device interface for the devices used by the prototype
machine type.
Do not break existing machine types here. This means we need to keep
legacy interfaces until their last user is gone (step B). Could
become somewhat messy in places for a while.
B. Convert all the existing machine configurations to data.
This can and should be done incrementally, each machine by people who
care and know about it.
Clean up the legacy interfaces now unused, and any messes we made
behind them.
C. Read (and maybe write) machine configuration
The external format to use is debatable. Compared to the rest of the
task, its choice looks like detail to me, but I'm biased ;)
Writing the data could be useful for debugging.
D. Command line options to modify the configuration tree
If we want them.
E. Make legacy command line modify the configuration tree
For compatibility. This is my "favourite" part.
We need to start with A. The other tasks are largely independent.
What I've already done
----------------------
Show me the code, they say. Find attached a working prototype of step
A. It passes the "Linux boots" test for me. I didn't bother to rebase
to current HEAD, happy do to that on request.
Instead of hacking up machine "pc", I created a new machine "pcdt". I
took a number of shortcuts:
* I put the "pcdt" code into the new file dt.c, and copied code from
pc.c there. I could have avoided that by putting my code in pc.c
instead. Putting it in a new file helped me pick apart the pc.c
hairball. To be cleaned up.
* I copied code from net.c. Trivial to fix, just give it external
linkage there.
* I hard-coded the configuration tree in the wrong place (tree.c), out of
laziness.
* I didn't implement all the devices of the "pc" original. The devices
I implemented might not support all existing command line options.
Notable qualities:
* Device drivers are cleanly separated from each other, and from the
device-agnostic configuration code.
* Each driver specifies the configurable properties in a single place.
* Device configuration is gotten from the configuration tree, which is
fully checked. Unknown properties are rejected.