mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-10-03 13:30:36 +00:00
libkrun: fix riscv64-linux build (#545448)
This commit is contained in:
@@ -71,6 +71,13 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
rustc
|
||||
];
|
||||
|
||||
patches = lib.optionals stdenv.hostPlatform.isRiscV64 [
|
||||
# https://github.com/libkrun/libkrun/commit/d4bb6e0
|
||||
# Fix riscv64 non-TEE memory region setup
|
||||
# Remove in next release (Not included in 1.19.4)
|
||||
./riscv64-non-tee-memory.patch
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
libcap_ng
|
||||
libkrunfw'
|
||||
|
||||
357
pkgs/by-name/li/libkrun/riscv64-non-tee-memory.patch
Normal file
357
pkgs/by-name/li/libkrun/riscv64-non-tee-memory.patch
Normal file
@@ -0,0 +1,357 @@
|
||||
From d4bb6e040ad7b6e6a6cf68ffced3b895c2753a18 Mon Sep 17 00:00:00 2001
|
||||
From: Zewei Yang <yangzewei@loongson.cn>
|
||||
Date: Thu, 19 Mar 2026 09:40:43 +0800
|
||||
Subject: [PATCH] vmm: fix riscv64 non-TEE memory region setup
|
||||
|
||||
In non-x86 builds that don't use TEE features, vstate.rs used cfg!() to
|
||||
distinguish between TEE and non-TEE memory setup paths.
|
||||
|
||||
cfg!() only evaluates to a compile-time constant; code in both branches
|
||||
still participates in compilation and type checking. As a result, normal
|
||||
riscv64 builds still type-check guest_memfd and memory attribute code,
|
||||
which leads to build failures.
|
||||
|
||||
Refactor the memory-region setup into cfg-gated helpers so non-TEE builds
|
||||
do not compile TEE-only memory setup code, and reject unsupported
|
||||
TEE+architecture combinations during VM setup instead of during memory
|
||||
initialization.
|
||||
|
||||
Upstream: https://github.com/libkrun/libkrun/commit/d4bb6e040ad7b6e6a6cf68ffced3b895c2753a18
|
||||
Backported to v1.19.0: the upstream diff does not apply as-is because of
|
||||
the intervening Rust 2024 edition migration / cargo fmt reordering of the
|
||||
`use kvm_bindings::{...}` blocks. Only those import hunks were adjusted;
|
||||
no functional change.
|
||||
|
||||
Signed-off-by: Zewei Yang <yangzewei@loongson.cn>
|
||||
---
|
||||
diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs
|
||||
index 6d50e7f..c0521b1 100644
|
||||
--- a/src/vmm/src/builder.rs
|
||||
+++ b/src/vmm/src/builder.rs
|
||||
@@ -1562,6 +1562,23 @@ pub(crate) fn setup_vm(
|
||||
.map_err(StartMicrovmError::Internal)?;
|
||||
Ok(vm)
|
||||
}
|
||||
+
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
+fn validate_tee_config(tee: Tee) -> std::result::Result<(), StartMicrovmError> {
|
||||
+ match tee {
|
||||
+ #[cfg(feature = "amd-sev")]
|
||||
+ Tee::Snp => Ok(()),
|
||||
+ #[cfg(feature = "tdx")]
|
||||
+ Tee::Tdx => Ok(()),
|
||||
+ _ => Err(StartMicrovmError::InvalidTee),
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#[cfg(all(feature = "tee", not(target_arch = "x86_64")))]
|
||||
+fn validate_tee_config(_tee: Tee) -> std::result::Result<(), StartMicrovmError> {
|
||||
+ Err(StartMicrovmError::InvalidTee)
|
||||
+}
|
||||
+
|
||||
#[cfg(all(target_os = "linux", feature = "tee"))]
|
||||
pub(crate) fn setup_vm(
|
||||
kvm: &KvmContext,
|
||||
@@ -1569,6 +1586,8 @@ pub(crate) fn setup_vm(
|
||||
resources: &super::resources::VmResources,
|
||||
#[cfg(feature = "tdx")] _sender: Sender<WorkerMessage>,
|
||||
) -> std::result::Result<Vm, StartMicrovmError> {
|
||||
+ validate_tee_config(resources.tee_config().tee)?;
|
||||
+
|
||||
let mut vm = Vm::new(
|
||||
kvm.fd(),
|
||||
resources.tee_config(),
|
||||
diff --git a/src/vmm/src/linux/vstate.rs b/src/vmm/src/linux/vstate.rs
|
||||
index 05e58fb..d87b743 100644
|
||||
--- a/src/vmm/src/linux/vstate.rs
|
||||
+++ b/src/vmm/src/linux/vstate.rs
|
||||
@@ -41,7 +41,9 @@ use kbs_types::Tee;
|
||||
use crate::resources::TeeConfig;
|
||||
use crate::vmm_config::machine_config::CpuFeaturesTemplate;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
-use cpuid::{c3, filter_cpuid, t2, VmSpec};
|
||||
+use cpuid::{VmSpec, c3, filter_cpuid, t2};
|
||||
+#[cfg(not(feature = "tee"))]
|
||||
+use kvm_bindings::kvm_userspace_memory_region;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use kvm_bindings::{
|
||||
kvm_clock_data, kvm_debugregs, kvm_irqchip, kvm_lapic_state, kvm_mp_state, kvm_pit_state2,
|
||||
@@ -49,14 +51,14 @@ use kvm_bindings::{
|
||||
KVM_CLOCK_TSC_STABLE, KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE,
|
||||
KVM_MAX_CPUID_ENTRIES,
|
||||
};
|
||||
+use kvm_bindings::{KVM_API_VERSION, KVM_SYSTEM_EVENT_RESET, KVM_SYSTEM_EVENT_SHUTDOWN};
|
||||
+#[cfg(feature = "tee")]
|
||||
+use kvm_bindings::{KVM_CAP_EXIT_HYPERCALL, KVM_MEMORY_EXIT_FLAG_PRIVATE, kvm_enable_cap};
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
use kvm_bindings::{
|
||||
- kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2,
|
||||
- KVM_API_VERSION, KVM_MEM_GUEST_MEMFD, KVM_SYSTEM_EVENT_RESET, KVM_SYSTEM_EVENT_SHUTDOWN,
|
||||
+ KVM_MEM_GUEST_MEMFD, KVM_MEMORY_ATTRIBUTE_PRIVATE, kvm_create_guest_memfd,
|
||||
+ kvm_memory_attributes, kvm_userspace_memory_region2,
|
||||
};
|
||||
-#[cfg(feature = "tee")]
|
||||
-use kvm_bindings::{kvm_enable_cap, KVM_CAP_EXIT_HYPERCALL, KVM_MEMORY_EXIT_FLAG_PRIVATE};
|
||||
-#[cfg(not(target_arch = "riscv64"))]
|
||||
-use kvm_bindings::{kvm_memory_attributes, KVM_MEMORY_ATTRIBUTE_PRIVATE};
|
||||
use kvm_ioctls::{Cap::*, *};
|
||||
use utils::eventfd::EventFd;
|
||||
use utils::signal::{register_signal_handler, sigrtmin, Killable};
|
||||
@@ -661,90 +663,121 @@ impl Vm {
|
||||
None
|
||||
}
|
||||
|
||||
- #[allow(unused_mut)]
|
||||
- fn memory_region_set(
|
||||
+ // GuestMemfd is generally intended for either of two purposes:
|
||||
+ // * sharing the memory with out-of-process components, and conversely,
|
||||
+ // * hiding the memory completely from the VMM process (Confidential Computing).
|
||||
+ //
|
||||
+ // We only use it for the second use case currently, so don't even try to use it
|
||||
+ // outside of TEE builds. Software-protected VMs are only available on x86_64 and
|
||||
+ // are marked with strongly-worded warnings about them being for development only,
|
||||
+ // as of late 2025. Also, on other architectures like aarch64, guest_memfd in
|
||||
+ // general is unstable for now, so don't try to use it without a reason.
|
||||
+
|
||||
+ #[cfg(not(feature = "tee"))]
|
||||
+ fn create_guest_physical_memory_slot(
|
||||
&mut self,
|
||||
- guest_mem: &GuestMemoryMmap,
|
||||
+ host_addr: u64,
|
||||
+ start: u64,
|
||||
region: &GuestRegionMmap,
|
||||
) -> Result<()> {
|
||||
- let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap();
|
||||
- let start = region.start_addr().raw_value();
|
||||
- let end = start + region.len();
|
||||
+ let memory_region = kvm_userspace_memory_region {
|
||||
+ slot: self.next_mem_slot,
|
||||
+ guest_phys_addr: start,
|
||||
+ memory_size: region.len(),
|
||||
+ userspace_addr: host_addr,
|
||||
+ flags: 0,
|
||||
+ };
|
||||
|
||||
- // GuestMemfd is generally intended for either of two purposes:
|
||||
- // * sharing the memory with out-of-process components, and conversely,
|
||||
- // * hiding the memory completely from the VMM process (Confidential Computing).
|
||||
- //
|
||||
- // We only use it for the second use case currently, so don't even try to use it
|
||||
- // outside of TEE builds. Software-protected VMs are only available on x86_64 and
|
||||
- // are marked with strongly-worded warnings about them being for development only,
|
||||
- // as of late 2025. Also, on other architectures like aarch64, guest_memfd in
|
||||
- // general is unstable for now, so don't try to use it without a reason.
|
||||
-
|
||||
- if cfg!(not(feature = "tee")) {
|
||||
- let memory_region = kvm_userspace_memory_region {
|
||||
- slot: self.next_mem_slot,
|
||||
- guest_phys_addr: start,
|
||||
- memory_size: region.len(),
|
||||
- userspace_addr: host_addr as u64,
|
||||
- flags: 0,
|
||||
- };
|
||||
+ // Safe because we mapped the memory region and ensured regions do not overlap.
|
||||
+ unsafe {
|
||||
+ self.fd
|
||||
+ .set_user_memory_region(memory_region)
|
||||
+ .map_err(Error::SetUserMemoryRegion)?;
|
||||
+ };
|
||||
|
||||
- // Safe because we mapped the memory region, we made sure that the regions
|
||||
- // are not overlapping.
|
||||
- unsafe {
|
||||
- self.fd
|
||||
- .set_user_memory_region(memory_region)
|
||||
- .map_err(Error::SetUserMemoryRegion)?;
|
||||
- };
|
||||
- } else {
|
||||
- if !self.fd.check_extension(GuestMemfd) {
|
||||
- return Err(Error::KvmCap(GuestMemfd));
|
||||
- }
|
||||
+ Ok(())
|
||||
+ }
|
||||
|
||||
- // Create a guest_memfd and set the region.
|
||||
- let guest_memfd = self
|
||||
- .fd
|
||||
- .create_guest_memfd(kvm_create_guest_memfd {
|
||||
- size: region.size() as u64,
|
||||
- flags: 0,
|
||||
- reserved: [0; 6],
|
||||
- })
|
||||
- .map_err(Error::CreateGuestMemfd)?;
|
||||
-
|
||||
- let memory_region = kvm_userspace_memory_region2 {
|
||||
- slot: self.next_mem_slot,
|
||||
- flags: KVM_MEM_GUEST_MEMFD,
|
||||
- guest_phys_addr: start,
|
||||
- memory_size: region.len(),
|
||||
- userspace_addr: host_addr as u64,
|
||||
- guest_memfd_offset: 0,
|
||||
- guest_memfd: guest_memfd as u32,
|
||||
- pad1: 0,
|
||||
- pad2: [0; 14],
|
||||
- };
|
||||
-
|
||||
- // Safe because we mapped the memory region, we made sure that the regions
|
||||
- // are not overlapping.
|
||||
- unsafe {
|
||||
- self.fd
|
||||
- .set_user_memory_region2(memory_region)
|
||||
- .map_err(Error::SetUserMemoryRegion)?;
|
||||
- };
|
||||
-
|
||||
- let attr = kvm_memory_attributes {
|
||||
- address: start,
|
||||
- size: region.len(),
|
||||
- attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64,
|
||||
+ #[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
+ fn create_guest_physical_memory_slot(
|
||||
+ &mut self,
|
||||
+ host_addr: u64,
|
||||
+ start: u64,
|
||||
+ region: &GuestRegionMmap,
|
||||
+ ) -> Result<()> {
|
||||
+ let end = start + region.len();
|
||||
+
|
||||
+ if !self.fd.check_extension(GuestMemfd) {
|
||||
+ return Err(Error::KvmCap(GuestMemfd));
|
||||
+ }
|
||||
+
|
||||
+ // GuestMemfd is only used for confidential-memory setups in TEE builds.
|
||||
+ let guest_memfd = self
|
||||
+ .fd
|
||||
+ .create_guest_memfd(kvm_create_guest_memfd {
|
||||
+ size: region.size() as u64,
|
||||
flags: 0,
|
||||
- };
|
||||
+ reserved: [0; 6],
|
||||
+ })
|
||||
+ .map_err(Error::CreateGuestMemfd)?;
|
||||
+
|
||||
+ let memory_region = kvm_userspace_memory_region2 {
|
||||
+ slot: self.next_mem_slot,
|
||||
+ flags: KVM_MEM_GUEST_MEMFD,
|
||||
+ guest_phys_addr: start,
|
||||
+ memory_size: region.len(),
|
||||
+ userspace_addr: host_addr,
|
||||
+ guest_memfd_offset: 0,
|
||||
+ guest_memfd: guest_memfd as u32,
|
||||
+ pad1: 0,
|
||||
+ pad2: [0; 14],
|
||||
+ };
|
||||
|
||||
+ // Safe because we mapped the memory region and ensured regions do not overlap.
|
||||
+ unsafe {
|
||||
self.fd
|
||||
- .set_memory_attributes(attr)
|
||||
- .map_err(Error::SetMemoryAttributes)?;
|
||||
+ .set_user_memory_region2(memory_region)
|
||||
+ .map_err(Error::SetUserMemoryRegion)?;
|
||||
+ };
|
||||
|
||||
- self.guest_memfds.push((Range { start, end }, guest_memfd));
|
||||
- }
|
||||
+ let attr = kvm_memory_attributes {
|
||||
+ address: start,
|
||||
+ size: region.len(),
|
||||
+ attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64,
|
||||
+ flags: 0,
|
||||
+ };
|
||||
+
|
||||
+ self.fd
|
||||
+ .set_memory_attributes(attr)
|
||||
+ .map_err(Error::SetMemoryAttributes)?;
|
||||
+
|
||||
+ self.guest_memfds.push((Range { start, end }, guest_memfd));
|
||||
+
|
||||
+ Ok(())
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(all(feature = "tee", not(target_arch = "x86_64")))]
|
||||
+ fn create_guest_physical_memory_slot(
|
||||
+ &mut self,
|
||||
+ _host_addr: u64,
|
||||
+ _start: u64,
|
||||
+ _region: &GuestRegionMmap,
|
||||
+ ) -> Result<()> {
|
||||
+ // TEE support should be rejected during VM setup on non-x86_64 targets.
|
||||
+ // Do not silently fall back to the non-TEE path here, because that would
|
||||
+ // ignore an invalid TEE configuration and create a normal VM instead.
|
||||
+ Err(Error::InvalidTee)
|
||||
+ }
|
||||
+
|
||||
+ fn memory_region_set(
|
||||
+ &mut self,
|
||||
+ guest_mem: &GuestMemoryMmap,
|
||||
+ region: &GuestRegionMmap,
|
||||
+ ) -> Result<()> {
|
||||
+ let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap() as u64;
|
||||
+ let start = region.start_addr().raw_value();
|
||||
+
|
||||
+ self.create_guest_physical_memory_slot(host_addr, start, region)?;
|
||||
|
||||
self.next_mem_slot += 1;
|
||||
|
||||
diff --git a/src/vmm/src/worker.rs b/src/vmm/src/worker.rs
|
||||
index d0131b9..a28ed55 100644
|
||||
--- a/src/vmm/src/worker.rs
|
||||
+++ b/src/vmm/src/worker.rs
|
||||
@@ -1,20 +1,20 @@
|
||||
use std::io;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
-#[cfg(feature = "tee")]
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
use utils::worker_message::MemoryProperties;
|
||||
use utils::worker_message::WorkerMessage;
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
-#[cfg(feature = "tee")]
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
use crossbeam_channel::Sender;
|
||||
-#[cfg(feature = "tee")]
|
||||
-use kvm_bindings::{kvm_memory_attributes, KVM_MEMORY_ATTRIBUTE_PRIVATE};
|
||||
-#[cfg(feature = "tee")]
|
||||
-use libc::{fallocate, madvise, FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE, MADV_DONTNEED};
|
||||
-#[cfg(feature = "tee")]
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
+use kvm_bindings::{KVM_MEMORY_ATTRIBUTE_PRIVATE, kvm_memory_attributes};
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
+use libc::{FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE, MADV_DONTNEED, fallocate, madvise};
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
use std::ffi::c_void;
|
||||
-#[cfg(feature = "tee")]
|
||||
+#[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
use vm_memory::{
|
||||
guest_memory::GuestMemory, Address, GuestAddress, GuestMemoryRegion, MemoryRegionAddress,
|
||||
};
|
||||
@@ -59,15 +59,21 @@ impl super::Vmm {
|
||||
.send(self.vm.fd().set_irq_line(irq, active).is_ok())
|
||||
.unwrap();
|
||||
}
|
||||
- WorkerMessage::ConvertMemory(_sender, _properties) =>
|
||||
- {
|
||||
- #[cfg(feature = "tee")]
|
||||
- self.convert_memory(_sender, _properties)
|
||||
+ WorkerMessage::ConvertMemory(_sender, _properties) => {
|
||||
+ #[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
+ {
|
||||
+ self.convert_memory(_sender, _properties);
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(not(all(feature = "tee", target_arch = "x86_64")))]
|
||||
+ {
|
||||
+ let _ = _sender.send(false);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- #[cfg(feature = "tee")]
|
||||
+ #[cfg(all(feature = "tee", target_arch = "x86_64"))]
|
||||
fn convert_memory(&self, sender: Sender<bool>, properties: MemoryProperties) {
|
||||
let Some((guest_memfd, region_start)) = self.kvm_vm().guest_memfd_get(properties.gpa)
|
||||
else {
|
||||
--
|
||||
2.51.0
|
||||
Reference in New Issue
Block a user