Skip to content

Rework fw_cfg and add bootorder entry#170

Open
scholzp wants to merge 9 commits into
cyberus-technology:gardenlinuxfrom
scholzp:fw_config_v52
Open

Rework fw_cfg and add bootorder entry#170
scholzp wants to merge 9 commits into
cyberus-technology:gardenlinuxfrom
scholzp:fw_config_v52

Conversation

@scholzp

@scholzp scholzp commented Jun 12, 2026

Copy link
Copy Markdown

We need the bootorder entry in fw_cfg to provide boot order hints to OVMF. This way we make OpenStack's rescue boot work and solve https://github.com/cobaltcore-dev/cobaltcore/issues/491.

Pipeline: https://gitlab.cyberus-technology.de/cyberus/cloud/libvirt/-/merge_requests/234

Maybe we can discuss what to do with the fw_cfg feature here. Currently the X-commit serves the purpose to enable the pipeline, so ignore it. We agreed with upstream to first work on making fw_cfg a default feature and then implementing the bootorder feature. For us, this should make no difference.

scholzp added 9 commits June 12, 2026 12:02
Some entries are also 2 and 8 bytes in size. We therefore add the
missing content sizes.

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
If the guest reads a specific amount of bytes through MMIO, the read
should be served with the respective amount of bytes.

Because the array is initialized with a slice of length 0, the current
implementation returned success without any byte written to the guest
buffer, which might be unexpected by the guest. We fix this by setting a
default value of the respective byte length.

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
We would do it analogous for `NetConfig`.

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Qemu has the ability to pass boot order hints via the `fw_cfg` device to
firmware. EDK2/OVMF, for instance, respect these hints. [0]
To support this, we need to be able to collect open firmware device
paths form the device tree.

[0] https://github.com/tianocore/edk2/blob/2816ff0ab0d6505bf580aa8eec02cc2b89f04230/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c#L1222

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
For consumption by the `fw_cfg` device, we make `DeviceManager` collect
and expose the firmware device paths of devices for which the `
bootorder` attribute is defined, in an ordered list.

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Qemu's implementation does not provide any default binary blobs for
initrd, kernel and command line. We therefore also refrain from doing
so.

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Using `bootorder` in device configs requires a `fw_cfg` device to be
present. The current way of instantiating one is by explicitly adding
one to the command line. In cases one wasn't created this way, we need
to implicitly add one to make the `bootorder` applicable.

Adding it in the `device_manager` if we require one works for both
cases, VM instantiation via an API call and via the CLI.

Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
@scholzp scholzp requested review from Coffeeri and phip1611 June 12, 2026 13:08
@scholzp scholzp self-assigned this Jun 12, 2026

@Coffeeri Coffeeri left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work! Thank you for implementing this feature!

Comment thread vmm/src/config.rs
image_type=<raw,qcow2,vhd,vhdx>,lock_granularity=byte-range|full";

#[cfg(feature = "fw_cfg")]
pub const SYNTAX: &'static str = "Disk parameters \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer a concatenation to the existing DiskConfig::SYNTAX, instead of duplicating and having to maintain both.

Comment thread vmm/src/device_tree.rs

#[cfg(feature = "fw_cfg")]
pub fn fw_cfg_path_by_id(&self, id: &str) -> String {
self.get(id).unwrap().openfw_device_path().unwrap()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we handle the error cases DeviceNodePathError::{NoPciDevice,DeviceNotBootable,NoBusDevice} here instead of unwraping? If not and you'd like to panic early, maybe consider .expect(...).

Comment thread vmm/src/vm.rs
name: "bootorder".to_string(),
content: FwCfgContent::Bytes(content),
};
fw_cfg_item_list.push(bootorder_item);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we still push the bootorder_item when bootitems is empty?

known_items[FW_CFG_ID as usize] = FwCfgContent::Slice(&FW_CFG_FEATURE);
let file_buf = Vec::from(FwCfgFilesHeader { count_be: 0 }.as_mut_bytes());
known_items[FW_CFG_FILE_DIR as usize] = FwCfgContent::Bytes(file_buf);
known_items[FW_CFG_UUID as usize] = FwCfgContent::Bytes(Default::default()); /* TODO? */

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are all these TODO's? Do we need those?

Comment thread vmm/src/device_manager.rs

#[cfg(feature = "fw_cfg")]
{
// if we have a boot order but no fw_cfg device, we must create on

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// if we have a boot order but no fw_cfg device, we must create on
// if we have a boot order but no fw_cfg device, we must create one

Comment thread vmm/src/device_tree.rs
///
/// [0] https://github.com/tianocore/edk2/blob/2816ff0ab0d6505bf580aa8eec02cc2b89f04230/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c#L1222
#[cfg(feature = "fw_cfg")]
pub fn openfw_device_path(&self) -> Result<String, DeviceNodePathError> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, feel free to resolve: if we flatten the nested clause, it will lower the cognitive load to read this function.

e.g. use guard clauses in the beginning

 #[cfg(feature = "fw_cfg")]
 pub fn openfw_device_path(&self) -> Result<String, DeviceNodePathError> {
    let Some(handle) = &self.pci_device_handle else {
        return Err(DeviceNodePathError::NoBusDevice);
    };

    let PciDeviceHandle::Virtio(virtio_handle) = handle else {
        return Err(DeviceNodePathError::NoPciDevice);
    };

    let bdf = self.pci_bdf.expect("PCI devices should have a bdf!");

    let device_type = virtio_handle
        .lock()
        .unwrap()
        .virtio_device()
        .lock()
        .unwrap()
        .device_type();

    match device_type {
        0x2 /* VirtioBlk */ => Ok(format!("/pci@i0cf8/scsi@{:x}/disk@0,0", bdf.device())),
        _ => Err(DeviceNodePathError::DeviceNotBootable),
    }

@phip1611

Copy link
Copy Markdown
Member

What is your plan regarding upstream?

  • Develop this feature here and upstream eventually?
  • Just get some early feedback and then continue development upstream?

I think this also depends on how urgent this is.

@scholzp

scholzp commented Jun 15, 2026

Copy link
Copy Markdown
Author

What is your plan regarding upstream?

  • Develop this feature here and upstream eventually?
  • Just get some early feedback and then continue development upstream?

I think this also depends on how urgent this is.

My plan is to develop a minimal version that fits our needs for the feature as this has a relative high priority and then begin working on making the fw_cfg feature complete for upstreaming altogether.

The last means bringing all in a state that it works reliably without breaking anything in the firmware or guest. The latter reaching full compatibility with Qemu and implementing all it's defined defaults.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants