Skip to content

Support RISC-V architecture #5227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
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
9 changes: 8 additions & 1 deletion src/firecracker/src/api_server/request/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use vmm::rpc_interface::VmmAction;

use super::super::parsed_request::{ParsedRequest, RequestError};
use super::Body;
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
use super::StatusCode;

// The names of the members from this enum must precisely correspond (as a string) to the possible
Expand Down Expand Up @@ -45,6 +45,13 @@ pub(crate) fn parse_put_actions(body: &Body) -> Result<ParsedRequest, RequestErr
"SendCtrlAltDel does not supported on aarch64.".to_string(),
));

// SendCtrlAltDel not supported on riscv64.
#[cfg(target_arch = "riscv64")]
return Err(RequestError::Generic(
StatusCode::BadRequest,
"SendCtrlAltDel is not supported on riscv64.".to_string(),
));

#[cfg(target_arch = "x86_64")]
Ok(ParsedRequest::new_sync(VmmAction::SendCtrlAltDel))
}
Expand Down
1 change: 1 addition & 0 deletions src/seccompiler/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub struct scmp_arg_cmp {

pub const SCMP_ARCH_X86_64: u32 = 0xc000003e;
pub const SCMP_ARCH_AARCH64: u32 = 0xc00000b7;
pub const SCMP_ARCH_RISCV64: u32 = 0xc00000f3;
/// Kill the process
pub const SCMP_ACT_KILL_PROCESS: u32 = 0x80000000;
/// Kill the thread
Expand Down
3 changes: 3 additions & 0 deletions src/seccompiler/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,15 @@ pub struct BpfJson(pub BTreeMap<String, Filter>);
pub enum TargetArch {
X86_64,
Aarch64,
Riscv64,
}

impl TargetArch {
pub fn to_scmp_type(&self) -> u32 {
match self {
TargetArch::X86_64 => SCMP_ARCH_X86_64,
TargetArch::Aarch64 => SCMP_ARCH_AARCH64,
TargetArch::Riscv64 => SCMP_ARCH_RISCV64,
}
}
}
Expand All @@ -186,6 +188,7 @@ impl FromStr for TargetArch {
match s.to_lowercase().as_str() {
"x86_64" => Ok(TargetArch::X86_64),
"aarch64" => Ok(TargetArch::Aarch64),
"riscv64" => Ok(TargetArch::Riscv64),
_ => Err(s.to_string()),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/vmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ vm-superio = "0.8.0"
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] }
zerocopy = { version = "0.8.25" }

[target.'cfg(target_arch = "aarch64")'.dependencies]
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
vm-fdt = "0.3.0"

[dev-dependencies]
Expand Down
21 changes: 20 additions & 1 deletion src/vmm/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ pub use aarch64::{
load_kernel,
};

/// Module for riscv64 related functionality.
#[cfg(target_arch = "riscv64")]
pub mod riscv64;

#[cfg(target_arch = "riscv64")]
pub use riscv64::kvm::{Kvm, KvmArchError};
#[cfg(target_arch = "riscv64")]
pub use riscv64::vcpu::*;
#[cfg(target_arch = "riscv64")]
pub use riscv64::vm::{ArchVm, ArchVmError, VmState};
#[cfg(target_arch = "riscv64")]
pub use riscv64::{
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions,
configure_system_for_boot, get_kernel_start, initrd_load_addr, layout::CMDLINE_MAX_SIZE,
layout::IRQ_BASE, layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START,
load_kernel,
};

/// Module for x86_64 related functionality.
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
Expand All @@ -51,12 +69,13 @@ pub enum DeviceType {
/// Device Type: Virtio.
Virtio(u32),
/// Device Type: Serial.
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
Serial,
/// Device Type: RTC.
#[cfg(target_arch = "aarch64")]
Rtc,
/// Device Type: BootTimer.
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
BootTimer,
}

Expand Down
213 changes: 213 additions & 0 deletions src/vmm/src/arch/riscv64/aia/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// Copyright © 2025 Computing Systems Laboratory (CSLab), ECE, NTUA. All rights reserved.
//
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

mod regs;

use kvm_ioctls::{DeviceFd, VmFd};
pub use regs::AiaState;

/// Represent an AIA device
#[derive(Debug)]
pub struct AIADevice {
fd: DeviceFd,
vcpu_count: u64,
}

impl AIADevice {
const VERSION: u32 = kvm_bindings::kvm_device_type_KVM_DEV_TYPE_RISCV_AIA;

/// Return whether the device is MSI compatible.
pub fn msi_compatible(&self) -> bool {
true
}

/// Return the FDT `compatible` property string for IMSIC.
pub fn imsic_compatibility(&self) -> &str {
"riscv,imsics"
}

/// Return IMSIC properties.
pub fn imsic_properties(&self) -> [u32; 4] {
[
0,
AIADevice::get_imsic_addr() as u32,
0,
super::layout::IMSIC_SZ_PH * self.vcpu_count as u32,
]
}

/// Return the FDT `compatible` property string for APLIC.
pub fn aplic_compatibility(&self) -> &str {
"riscv,aplic"
}

/// Return APLIC properties.
pub fn aplic_properties(&self) -> [u32; 4] {
[
0,
AIADevice::get_aplic_addr() as u32,
0,
::kvm_bindings::KVM_DEV_RISCV_APLIC_SIZE,
]
}

/// Return the file descriptor of the AIA device.
pub fn device_fd(&self) -> &DeviceFd {
&self.fd
}

/// Returns the number vCPUs this AIA device handles.
pub fn vcpu_count(&self) -> u64 {
self.vcpu_count
}

fn get_aplic_addr() -> u64 {
super::layout::APLIC_START
}

fn get_imsic_addr() -> u64 {
super::layout::IMSIC_START
}

/// Create the AIA device object.
pub fn create_device(fd: DeviceFd, vcpu_count: u64) -> Self {
Self { fd, vcpu_count }
}

/// Initialize an AIA device.
pub fn init_device(vm: &VmFd) -> Result<DeviceFd, AiaError> {
let mut aia_device = kvm_bindings::kvm_create_device {
type_: Self::VERSION,
fd: 0,
flags: 0,
};

vm.create_device(&mut aia_device)
.map_err(AiaError::CreateAIA)
}

fn init_device_attributes(aia_device: &Self) -> Result<(), AiaError> {
// Set attributes.
let nr_irqs: u32 = super::layout::IRQ_MAX;
let aia_nr_sources: u32 = nr_irqs;
Self::set_device_attribute(
aia_device.device_fd(),
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_SRCS),
&aia_nr_sources as *const u32 as u64,
0,
)?;

let aia_hart_bits = u64::from(aia_device.vcpu_count) - 1;
let aia_hart_bits = ::std::cmp::max(64 - aia_hart_bits.leading_zeros(), 1);
Self::set_device_attribute(
aia_device.device_fd(),
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_HART_BITS),
&aia_hart_bits as *const u32 as u64,
0,
)?;

// Set APLIC address.
let aia_addr_aplic: u64 = AIADevice::get_aplic_addr();
Self::set_device_attribute(
aia_device.device_fd(),
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_ADDR,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_ADDR_APLIC),
&aia_addr_aplic as *const u64 as u64,
0,
)?;

let aia_imsic_addr = |hart| -> u64 {
AIADevice::get_imsic_addr() + u64::from(hart) * u64::from(super::layout::IMSIC_SZ_PH)
};
for i in 0..aia_device.vcpu_count {
let aia_addr_imsic = aia_imsic_addr(i);
let aia_addr_imsic_attr = 1 + u64::from(i);
Self::set_device_attribute(
aia_device.device_fd(),
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_ADDR,
u64::from(aia_addr_imsic_attr),
&aia_addr_imsic as *const u64 as u64,
0,
)?;
}

Ok(())
}

/// Create an AIA device.
pub fn create_aia(vm: &VmFd, vcpu_count: u64) -> Result<AIADevice, AiaError> {
let aia_fd = Self::init_device(vm)?;

let device = Self::create_device(aia_fd, vcpu_count);

Self::init_device_attributes(&device)?;

Self::finalize_device(&device)?;

Ok(device)
}

/// Finalize the setup of an AIA device.
pub fn finalize_device(aia_device: &Self) -> Result<(), AiaError> {
// Finalize the AIA.
Self::set_device_attribute(
aia_device.device_fd(),
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CTRL,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CTRL_INIT),
0,
0,
)?;

Ok(())
}

/// Set an AIA device attribute.
pub fn set_device_attribute(
fd: &DeviceFd,
group: u32,
attr: u64,
addr: u64,
flags: u32,
) -> Result<(), AiaError> {
let attr = kvm_bindings::kvm_device_attr {
flags,
group,
attr,
addr,
};
fd.set_device_attr(&attr)
.map_err(|err| AiaError::DeviceAttribute(err, true, group))?;

Ok(())
}

/// A safe wrapper over unsafe kvm_ioctl::get_device_attr()
pub fn get_device_attribute(
&self,
attr: &mut ::kvm_bindings::kvm_device_attr,
) -> Result<(), AiaError> {
// SAFETY: attr.addr is safe to write to.
unsafe {
self.fd
.get_device_attr(attr)
.map_err(|err| AiaError::DeviceAttribute(err, true, attr.group))?
};

Ok(())
}
}

/// Errors thrown while setting up the AIA.
#[derive(Debug, thiserror::Error, displaydoc::Display, PartialEq, Eq)]
pub enum AiaError {
/// Error while calling KVM ioctl for setting up the global interrupt controller: {0}
CreateAIA(kvm_ioctls::Error),
/// Error while setting or getting device attributes for the AIA: {0}, {1}, {2}
DeviceAttribute(kvm_ioctls::Error, bool, u32),
}
11 changes: 11 additions & 0 deletions src/vmm/src/arch/riscv64/aia/regs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright © 2025 Computing Systems Laboratory (CSLab), ECE, NTUA. All rights reserved.
//
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use serde::{Deserialize, Serialize};

/// Structure used for serializing the state of the AIA registers.
/// For now, it is just a placeholder.
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct AiaState;
Loading