runtime-rs: Enable IBM SE support for QEMU

This commit configures the command line for IBM Secure Execution (SE)
and other TEEs. The following changes are made:

- Add a new item `Se` to ProtectionDeviceConfig and handle it at sandbox
- Introduce `add_se_protection_device()` for SE cmdline config
- Bypass rootfs image/initrd validity checks when SE is configured.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
This commit is contained in:
Hyounggyu Choi 2025-02-28 14:57:30 +01:00
parent f485e52f75
commit 4c8e881a84
5 changed files with 48 additions and 4 deletions

View File

@ -118,9 +118,12 @@ impl ConfigPlugin for QemuConfig {
return Err(eother!("Guest kernel image for qemu is empty"));
}
if qemu.boot_info.image.is_empty() && qemu.boot_info.initrd.is_empty() {
return Err(eother!(
"Both guest boot image and initrd for qemu are empty"
));
// IBM SE (CCW + confidential guest) does not require neither image nor initrd.
if !(qemu.boot_info.vm_rootfs_driver.ends_with("ccw") && qemu.security_info.confidential_guest) {
return Err(eother!(
"Both guest boot image and initrd for qemu are empty"
));
}
}
if (qemu.cpu_info.default_vcpus > 0

View File

@ -13,6 +13,7 @@ use async_trait::async_trait;
#[derive(Debug, Clone)]
pub enum ProtectionDeviceConfig {
SevSnp(SevSnpConfig),
Se,
}
#[derive(Debug, Clone)]

View File

@ -1740,6 +1740,28 @@ impl ToQemuParams for ObjectIoThread {
}
}
#[derive(Debug)]
struct ObjectSeGuest {
id: String,
}
impl ObjectSeGuest {
fn new(id: &str) -> Self {
ObjectSeGuest { id: id.to_owned() }
}
}
#[async_trait]
impl ToQemuParams for ObjectSeGuest {
async fn qemu_params(&self) -> Result<Vec<String>> {
let mut params = Vec::new();
params.push("s390-pv-guest".to_owned());
params.push(format!("id={}", self.id));
Ok(vec!["-object".to_owned(), params.join(",")])
}
}
#[derive(Debug)]
struct ObjectSevSnpGuest {
id: String,
@ -2113,6 +2135,15 @@ impl<'a> QemuCmdLine<'a> {
self.devices.push(Box::new(balloon_device));
}
pub fn add_se_protection_device(&mut self) {
let se_object = ObjectSeGuest::new("pv0");
self.devices.push(Box::new(se_object));
self.machine
.set_confidential_guest_support("pv0")
.set_nvdimm(false);
}
pub fn add_sev_protection_device(&mut self, cbitpos: u32, firmware: &str) {
let sev_object = ObjectSevSnpGuest::new(false, cbitpos);
self.devices.push(Box::new(sev_object));

View File

@ -141,6 +141,7 @@ impl QemuInner {
)
}
}
ProtectionDeviceConfig::Se => cmdline.add_se_protection_device(),
},
_ => info!(sl!(), "qemu cmdline: unsupported device: {:?}", device),
}

View File

@ -273,13 +273,18 @@ impl VirtSandbox {
async fn prepare_rootfs_config(&self) -> Result<Option<BlockConfig>> {
let boot_info = self.hypervisor.hypervisor_config().await.boot_info;
let security_info = self.hypervisor.hypervisor_config().await.security_info;
if !boot_info.initrd.is_empty() {
return Ok(None);
}
if boot_info.image.is_empty() {
return Err(anyhow!("both of image and initrd isn't set"));
if boot_info.vm_rootfs_driver.ends_with("ccw") && security_info.confidential_guest {
return Ok(None);
} else {
return Err(anyhow!("both of image and initrd isn't set"));
}
}
Ok(Some(BlockConfig {
@ -367,6 +372,9 @@ impl VirtSandbox {
certs_path,
})))
}
GuestProtection::Se => {
Ok(Some(ProtectionDeviceConfig::Se))
}
_ => Err(anyhow!("confidential_guest requested by configuration but no supported protection available"))
}
}