I'm coming around to your way of thinking. How about this:
vm has two mutually exclusive groups: "pv", and "hvm", with the fields
vm.pv.bootloader
vm.pv.entry
vm.pv.kernel
vm.pv.ramdisk
vm.pv.args
vm.hvm.boot
pv means "use the PV domain builder, and pass the entry, kernel, ramdisk, and
args to the specified bootloader".
If bootloader is empty but kernel is specified, then this means take the
kernel and ramdisk from domain 0. Otherwise, bootloader is a path to the
bootloading script.
The semantics of entry, kernel, ramdisk, and args are specific to the
bootloader in use. You get given all those options, and it's up to the
bootloader to do something sensible, including ignoring some or all of the
specified options.
If the bootloader is pygrub, then the menu.lst is parsed if present, the
specified entry is selected if that makes sense, and if the the menu.lst is
not present, the specified kernel/ramdisk is used, or an autodetected kernel
is used if nothing is specified. The given args are appended to the kernel
command line, no matter which mechanism is used for finding the kernel.
hvm means "use the HVM domain builder, hvmloader and boot using a BIOS", with
hvm.boot specifying the order of boot devices.
How does that sound?
Ewan.