3 Commits

Author SHA1 Message Date
isrc-riscv-port 70461c559e vmm: Allow unlinkat on riscv64 seccomp filters
Lint Dockerfile / Run Hadolint Dockerfile Linter (push) Has been cancelled
REUSE Compliance Check / REUSE Compliance Check (push) Has been cancelled
riscv64 does not provide the legacy unlink syscall, so libc uses unlinkat for file removal paths that are otherwise allowed on other architectures.

Permit unlinkat for the VMM and vCPU seccomp filters on riscv64, matching the existing aarch64 rule.

Signed-off-by: isrc-riscv-port <riscv-port@isrc.iscas.ac.cn>
2026-05-13 03:16:39 +00:00
isrc-riscv-port f4e3941330 riscv64: Report KVM IMSIC interrupt IDs
The RISC-V AIA FDT node currently advertises a fixed riscv,num-ids value. That can diverge from the interrupt identity count configured by KVM, which matters for guests running with an emulated IMSIC.

Initialize the KVM AIA device in emulation mode, record the NR_IDS value reported by KVM, and expose that value through the generated device tree.

Signed-off-by: isrc-riscv-port <riscv-port@isrc.iscas.ac.cn>
2026-05-13 03:16:39 +00:00
isrc-riscv-port 5674337d5a riscv64: Enable sstateen0 for KVM vCPUs
KVM initializes RISC-V vCPUs with sstateen0 cleared. When AIA is exposed to the guest, Linux touches supervisor AIA CSRs while bringing up the IMSIC path, and those accesses fail if the stateen bits remain disabled.

Program sstateen0 for newly created vCPUs and after core register setup so the guest can use the supervisor interrupt state needed by AIA.

Signed-off-by: isrc-riscv-port <riscv-port@isrc.iscas.ac.cn>
2026-05-13 03:16:38 +00:00
5 changed files with 55 additions and 6 deletions
+2 -2
View File
@@ -231,8 +231,8 @@ fn create_aia_node(fdt: &mut FdtWriter, aia_device: &Arc<Mutex<dyn Vaia>>) -> Fd
fdt.property_u32("#interrupt-cells", 0u32)?;
fdt.property_null("interrupt-controller")?;
fdt.property_null("msi-controller")?;
// TODO complete num-ids
fdt.property_u32("riscv,num-ids", 2047u32)?;
let imsic_num_ids = aia_device.lock().unwrap().imsic_num_ids();
fdt.property_u32("riscv,num-ids", imsic_num_ids)?;
fdt.property_u32("phandle", AIA_IMSIC_PHANDLE)?;
let mut irq_cells = Vec::new();
+3
View File
@@ -46,6 +46,9 @@ pub trait Vaia: Send + Sync {
/// Returns an array with IMSIC device properties
fn imsic_properties(&self) -> [u32; 4];
/// Returns the number of IMSIC interrupt identities exposed to the guest
fn imsic_num_ids(&self) -> u32;
/// Returns the number of vCPUs this AIA handles
fn vcpu_count(&self) -> u32;
+28
View File
@@ -570,6 +570,25 @@ impl vm::Vm for KvmVm {
.create_vcpu(id as u64)
.map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
#[cfg(target_arch = "riscv64")]
{
// KVM defaults sstateen0 to zero for new RISC-V vCPUs. When AIA is
// exposed, Linux accesses supervisor AIA CSRs during IMSIC init;
// leave all state enabled so those CSR accesses do not trap as
// illegal instructions in the guest.
let sstateen0 = u64::MAX;
let sstateen0_id = kvm_bindings::KVM_REG_RISCV as u64
| u64::from(kvm_bindings::KVM_REG_SIZE_U64)
| u64::from(kvm_bindings::KVM_REG_RISCV_CSR)
| u64::from(kvm_bindings::KVM_REG_RISCV_CSR_SMSTATEEN);
fd.set_one_reg(sstateen0_id, &sstateen0.to_le_bytes())
.map_err(|e| {
vm::HypervisorVmError::CreateVcpu(anyhow!(
"failed to enable RISC-V sstateen0 for vCPU {id}: {e}"
))
})?;
}
#[cfg(target_arch = "x86_64")]
// Safety: `xsave_size` will not change after vcpu creation because:
// 1. `xsave_size` depends on cpuid
@@ -2303,6 +2322,15 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
let sstateen0 = u64::MAX;
let sstateen0_id = kvm_bindings::KVM_REG_RISCV as u64
| u64::from(kvm_bindings::KVM_REG_SIZE_U64)
| u64::from(kvm_bindings::KVM_REG_RISCV_CSR)
| u64::from(kvm_bindings::KVM_REG_RISCV_CSR_SMSTATEEN);
self.fd
.set_one_reg(sstateen0_id, &sstateen0.to_le_bytes())
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
Ok(())
}
+20 -2
View File
@@ -24,6 +24,9 @@ pub struct KvmAiaImsics {
/// Number of CPUs handled by the device
vcpu_count: u32,
/// Number of IMSIC interrupt identities configured by KVM
imsic_num_ids: u32,
}
#[derive(Clone, Default, Serialize, Deserialize)]
@@ -40,12 +43,21 @@ impl KvmAiaImsics {
// AIA part attributes
// Getting the working mode of RISC-V AIA, defaults to EMUL, passible
// variants are EMUL, HW_ACCL, AUTO
let mut aia_mode = kvm_bindings::KVM_DEV_RISCV_AIA_MODE_EMUL;
let aia_mode = kvm_bindings::KVM_DEV_RISCV_AIA_MODE_EMUL;
Self::set_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_MODE),
&aia_mode as *const u32 as u64,
0,
)?;
let mut aia_mode_readback: u32 = 0;
Self::get_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_MODE),
&mut aia_mode as *mut u32 as u64,
&mut aia_mode_readback as *mut u32 as u64,
0,
)?;
@@ -71,6 +83,7 @@ impl KvmAiaImsics {
)?;
// Report NR_IDS
self.imsic_num_ids = aia_nr_ids;
// Setting up hart_bits
let max_hart_index = self.vcpu_count as u64 - 1;
@@ -191,6 +204,7 @@ impl KvmAiaImsics {
vcpu_count: config.vcpu_count,
aplic_addr: config.aplic_addr,
imsic_addr: config.imsic_addr,
imsic_num_ids: 0,
};
aia_device.init_device_attributes(config.nr_irqs)?;
@@ -226,6 +240,10 @@ impl Vaia for KvmAiaImsics {
]
}
fn imsic_num_ids(&self) -> u32 {
self.imsic_num_ids
}
fn vcpu_count(&self) -> u32 {
self.vcpu_count
}
+2 -2
View File
@@ -689,7 +689,7 @@ fn vmm_thread_rules(
),
#[cfg(target_arch = "x86_64")]
(libc::SYS_unlink, vec![]),
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
(libc::SYS_unlinkat, vec![]),
(libc::SYS_wait4, vec![]),
(libc::SYS_write, vec![]),
@@ -831,7 +831,7 @@ fn vcpu_thread_rules(
(libc::SYS_tkill, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_unlink, vec![]),
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
(libc::SYS_unlinkat, vec![]),
(libc::SYS_write, vec![]),
(libc::SYS_writev, vec![]),