Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
From 5674337d5a610b47465445071a9164e19a3d0eab Mon Sep 17 00:00:00 2001
From: isrc-riscv-port <riscv-port@isrc.iscas.ac.cn>
Date: Wed, 13 May 2026 03:16:38 +0000
Subject: [PATCH 1/3] 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>
---
hypervisor/src/kvm/mod.rs | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs
index 259009151..95d673597 100644
--- a/hypervisor/src/kvm/mod.rs
+++ b/hypervisor/src/kvm/mod.rs
@@ -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(())
}

--
2.50.1 (Apple Git-155)

Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
From f4e394133021e9eec516a6e1175a5d6dce492628 Mon Sep 17 00:00:00 2001
From: isrc-riscv-port <riscv-port@isrc.iscas.ac.cn>
Date: Wed, 13 May 2026 03:16:39 +0000
Subject: [PATCH 2/3] 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>
---
arch/src/riscv64/fdt.rs | 4 ++--
hypervisor/src/arch/riscv64/aia.rs | 3 +++
hypervisor/src/kvm/riscv64/aia.rs | 22 ++++++++++++++++++++--
3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/src/riscv64/fdt.rs b/arch/src/riscv64/fdt.rs
index f97e6d6b5..b4a6160f3 100644
--- a/arch/src/riscv64/fdt.rs
+++ b/arch/src/riscv64/fdt.rs
@@ -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();
diff --git a/hypervisor/src/arch/riscv64/aia.rs b/hypervisor/src/arch/riscv64/aia.rs
index 2ba8d70eb..0172f4b39 100644
--- a/hypervisor/src/arch/riscv64/aia.rs
+++ b/hypervisor/src/arch/riscv64/aia.rs
@@ -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;

diff --git a/hypervisor/src/kvm/riscv64/aia.rs b/hypervisor/src/kvm/riscv64/aia.rs
index 67857c6ae..bb10767fd 100644
--- a/hypervisor/src/kvm/riscv64/aia.rs
+++ b/hypervisor/src/kvm/riscv64/aia.rs
@@ -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.50.1 (Apple Git-155)

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
From 70461c559e5510e36523ff7f5feb5c0bcfb5ebae Mon Sep 17 00:00:00 2001
From: isrc-riscv-port <riscv-port@isrc.iscas.ac.cn>
Date: Wed, 13 May 2026 03:16:39 +0000
Subject: [PATCH 3/3] vmm: Allow unlinkat on riscv64 seccomp filters

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>
---
vmm/src/seccomp_filters.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs
index bb40b99f6..657fa7f6b 100644
--- a/vmm/src/seccomp_filters.rs
+++ b/vmm/src/seccomp_filters.rs
@@ -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![]),
--
2.50.1 (Apple Git-155)

143 changes: 73 additions & 70 deletions SPECS/cloud-hypervisor/cloud-hypervisor.spec
Original file line number Diff line number Diff line change
@@ -1,107 +1,110 @@
# SPDX-FileCopyrightText: (C) 2025 Institute of Software, Chinese Academy of Sciences (ISCAS)
# SPDX-FileCopyrightText: (C) 2025 openRuyi Project Contributors
# SPDX-FileContributor: Ruoqing He <heruoqing@iscas.ac.cn>
# SPDX-FileContributor: Zheng Junjie <zhengjunjie@iscas.ac.cn>
# SPDX-FileCopyrightText: (C) 2026 Institute of Software, Chinese Academy of Sciences (ISCAS)
# SPDX-FileCopyrightText: (C) 2026 openRuyi Project Contributors
Comment on lines +1 to +2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please do not change the year information.

# SPDX-FileContributor: isrc-riscv-port <riscv-port@isrc.iscas.ac.cn>
#
# SPDX-License-Identifier: MulanPSL-2.0

%global gitver 51.0
%global gitnum 0

%global obs_packaging_commit 29a097e3e793e0f88053fa9b090a15c1333aa2cc
%global upstream_tag 51.1
%global vendor_dir %{name}-%{version}-vendor

Name: cloud-hypervisor
Url: https://github.com/cloud-hypervisor/cloud-hypervisor
Summary: Cloud Hypervisor is a Virtual Machine Monitor (VMM) that runs on top of KVM
Version: %{gitver}.%{gitnum}
Version: 51.1.0
Release: %autorelease
License: ASL 2.0 or BSD-3-clause
#!RemoteAsset: sha256:66e2a1b45d1463aab22d763c02bbf8fff5a4c9833c4612a0b717867cd1ebdbbc
Source0: https://github.com/cloud-hypervisor/obs-packaging/raw/%{obs_packaging_commit}/cloud-hypervisor/src/%{name}-%{version}.tar.gz
#!RemoteAsset: sha256:47e97b583ab92503cd588c38ecc92d4fd217012a97ab0748709e16b791bdee65
Source1: https://github.com/cloud-hypervisor/obs-packaging/raw/%{obs_packaging_commit}/cloud-hypervisor/src/%{name}-%{version}-vendor.tar.gz
#!RemoteAsset: sha256:9ffccf72f43efaa6e6434be68da53e7ad6ffbe332149f44a4d99405d58da1dc2
Source2: https://github.com/cloud-hypervisor/obs-packaging/raw/%{obs_packaging_commit}/cloud-hypervisor/src/config.toml
Summary: Virtual Machine Monitor that runs on top of KVM
License: (Apache-2.0 OR BSD-3-Clause) AND CC-BY-4.0
URL: https://github.com/cloud-hypervisor/cloud-hypervisor
VCS: git:https://github.com/cloud-hypervisor/cloud-hypervisor.git
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the URL tag already directs to the source repository, the VCS tag may be omitted.

#!RemoteAsset: sha256:a2393046c0230f6360792ed2ef1b60968aa4e04d12b6be419c86306774e2e4ef
Source0: %{url}/archive/refs/tags/v%{upstream_tag}.tar.gz#/%{name}-%{version}.tar.gz
#!RemoteAsset: sha256:b3b388773a8cd6e4c06750ab77b858a00201fc8a52e204dcedb46959a049ad5d
Source1: https://git.openruyi.cn/jiayi/cloud-hypervisor/releases/download/vendor-v%{upstream_tag}/%{name}-%{version}-vendor.tar.zst
ExclusiveArch: x86_64 riscv64
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There's no need to do this.

BuildSystem: rust

# RISC-V KVM AIA and seccomp fixes validated with Kata Containers.
Patch0: 0001-riscv64-Enable-sstateen0-for-KVM-vCPUs.patch
Patch1: 0002-riscv64-Report-KVM-IMSIC-interrupt-IDs.patch
Patch2: 0003-vmm-Allow-unlinkat-on-riscv64-seccomp-filters.patch

BuildRequires: binutils
BuildRequires: cargo >= 1.89.0
BuildRequires: gcc
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is no need for us to explicitly include BuildRequires: gcc.

BuildRequires: glibc-devel
BuildRequires: binutils
BuildRequires: libcap
BuildRequires: make
BuildRequires: openssl-devel
BuildRequires: rust >= 1.89.0
BuildRequires: rust-rpm-macros
BuildRequires: zstd

BuildRequires: rust >= 1.88.0
BuildRequires: cargo >= 1.88.0
Requires: bash
Requires: glibc
Requires: libcap

Requires: bash
Requires: glibc
Requires: libcap
Comment on lines -34 to -36
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please specify the reason for deleting these Requires.


# TODO: Use rva23 rust toolchain to compile
%ifarch x86_64
%define rust_def_target x86_64-unknown-linux-gnu
%define cargo_pkg_feature_opts --no-default-features --features "mshv,kvm" -p cloud-hypervisor
%global rust_def_target x86_64-unknown-linux-gnu
%global cargo_pkg_feature_opts --no-default-features --features "mshv,kvm" -p cloud-hypervisor
%endif

%ifarch riscv64
%define rust_def_target riscv64gc-unknown-linux-gnu
%define cargo_pkg_feature_opts --no-default-features --features "kvm" -p cloud-hypervisor
%global rust_def_target riscv64gc-unknown-linux-gnu
%global cargo_pkg_feature_opts --no-default-features --features "kvm" -p cloud-hypervisor
%endif
Comment on lines 44 to 52
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please position %global variables at the beginning of the Name: section.


%define cargo_offline --offline

%description
Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on
top of KVM. The project focuses on exclusively running modern, cloud workloads,
on top of a limited set of hardware architectures and platforms. Cloud
workloads refers to those that are usually run by customers inside a cloud
provider. For our purposes this means modern Linux* distributions with most I/O
handled by paravirtualised devices (i.e. virtio), no requirement for legacy
devices and recent CPUs and KVM.
Cloud Hypervisor is an open source Virtual Machine Monitor that runs on top of
KVM. The project focuses on modern cloud workloads using paravirtualized
devices, a small device model, and architecture support for x86_64 and RISC-V.
Comment on lines 54 to +57
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please specify the reason for replacing the whole %description block.


%prep

%setup -q
tar xf %{SOURCE1}
%setup -q -n %{name}-%{upstream_tag}
%patch -P 0 -p1
%patch -P 1 -p1
%patch -P 2 -p1
Comment on lines +60 to +63
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can't you use %autosetup?

tar -I zstd -xf %{SOURCE1}
mkdir -p .cargo
cp %{SOURCE2} .cargo/
cat > .cargo/config.toml <<EOF
[source.crates-io]
replace-with = "vendored-sources"

%build
cargo_version=$(cargo --version)
if [[ $? -ne 0 ]]; then
echo "Cargo not found, please install cargo. exiting"
exit 0
fi
[source."git+https://github.com/firecracker-microvm/micro-http?branch=main"]
git = "https://github.com/firecracker-microvm/micro-http"
branch = "main"
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "%{vendor_dir}"

[net]
offline = true
EOF

%build
export OPENSSL_NO_VENDOR=1
cargo build --release --target=%{rust_def_target} %{cargo_pkg_feature_opts} %{cargo_offline}
cargo build --release --target=%{rust_def_target} --package vhost_user_net %{cargo_offline}
cargo build --release --target=%{rust_def_target} --package vhost_user_block %{cargo_offline}
cargo build --release --locked --offline --target=%{rust_def_target} %{cargo_pkg_feature_opts}
cargo build --release --locked --offline --target=%{rust_def_target} --package vhost_user_net
cargo build --release --locked --offline --target=%{rust_def_target} --package vhost_user_block

%install
rm -rf %{buildroot}
install -d %{buildroot}%{_bindir}
install -D -m755 ./target/%{rust_def_target}/release/cloud-hypervisor %{buildroot}%{_bindir}
install -D -m755 ./target/%{rust_def_target}/release/ch-remote %{buildroot}%{_bindir}
install -d %{buildroot}%{_libdir}
install -d %{buildroot}%{_libdir}/cloud-hypervisor
install -D -m755 target/%{rust_def_target}/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor
install -D -m755 target/%{rust_def_target}/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor
install -Dpm0755 target/%{rust_def_target}/release/cloud-hypervisor %{buildroot}%{_bindir}/cloud-hypervisor
install -Dpm0755 target/%{rust_def_target}/release/ch-remote %{buildroot}%{_bindir}/ch-remote
install -Dpm0755 target/%{rust_def_target}/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor/vhost_user_block
install -Dpm0755 target/%{rust_def_target}/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor/vhost_user_net

%check
# Upstream integration tests require KVM device access and are not suitable for
# the default package build chroot.

%files
%defattr(-,root,root,-)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please specify the reason for deleting this line.

%license LICENSES/Apache-2.0.txt
%license LICENSES/BSD-3-Clause.txt
%license LICENSES/CC-BY-4.0.txt
%doc README.md
Comment on lines +99 to +102
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
%license LICENSES/Apache-2.0.txt
%license LICENSES/BSD-3-Clause.txt
%license LICENSES/CC-BY-4.0.txt
%doc README.md
%doc README.md
%license LICENSES/Apache-2.0.txt
%license LICENSES/BSD-3-Clause.txt
%license LICENSES/CC-BY-4.0.txt

%{_bindir}/ch-remote
%caps(cap_net_admin=ep) %{_bindir}/cloud-hypervisor
%dir %{_libdir}/cloud-hypervisor
%{_libdir}/cloud-hypervisor/vhost_user_block
%caps(cap_net_admin=ep) %{_libdir}/cloud-hypervisor/vhost_user_net
%if 0%{?using_musl_libc}
%{_libdir}/cloud-hypervisor/static/ch-remote
%caps(cap_net_admim=ep) %{_libdir}/cloud-hypervisor/static/cloud-hypervisor
%{_libdir}/cloud-hypervisor/static/vhost_user_block
%caps(cap_net_admin=ep) %{_libdir}/cloud-hypervisor/static/vhost_user_net
%endif
%license LICENSES/Apache-2.0.txt
%license LICENSES/BSD-3-Clause.txt
%license LICENSES/CC-BY-4.0.txt

%changelog
%autochangelog