mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
arch: Introduce RISC-V architecture
Integrate fdt setup and layout for `riscv64` to `arch` crate, provide definitions of `riscv64` platform specific error and reuse `MmioDeviceInfo`, `PciSpaceInfo` structures and `DeviceInfoForFdt` impl block for `riscv64`. Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
This commit is contained in:
parent
7b5f06788a
commit
bd8db86b0c
@ -1,3 +1,4 @@
|
|||||||
|
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
|
||||||
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
||||||
// Copyright © 2020, Oracle and/or its affiliates.
|
// Copyright © 2020, Oracle and/or its affiliates.
|
||||||
//
|
//
|
||||||
@ -5,7 +6,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
//! Implements platform specific functionality.
|
//! Implements platform specific functionality.
|
||||||
//! Supported platforms: x86_64, aarch64.
|
//! Supported platforms: x86_64, aarch64, riscv64.
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
@ -32,6 +33,9 @@ pub enum Error {
|
|||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
#[error("Platform specific error (aarch64): {0:?}")]
|
#[error("Platform specific error (aarch64): {0:?}")]
|
||||||
PlatformSpecific(aarch64::Error),
|
PlatformSpecific(aarch64::Error),
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
#[error("Platform specific error (riscv64): {0:?}")]
|
||||||
|
PlatformSpecific(riscv64::Error),
|
||||||
#[error("The memory map table extends past the end of guest memory")]
|
#[error("The memory map table extends past the end of guest memory")]
|
||||||
MemmapTablePastRamEnd,
|
MemmapTablePastRamEnd,
|
||||||
#[error("Error writing memory map table to guest memory")]
|
#[error("Error writing memory map table to guest memory")]
|
||||||
@ -85,6 +89,17 @@ pub use aarch64::{
|
|||||||
layout::IRQ_BASE, uefi, EntryPoint, _NSIG,
|
layout::IRQ_BASE, uefi, EntryPoint, _NSIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Module for riscv64 related functionality.
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub mod riscv64;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use riscv64::{
|
||||||
|
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
|
||||||
|
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
|
||||||
|
layout::IRQ_BASE, EntryPoint, _NSIG,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
|
|
||||||
@ -132,7 +147,7 @@ pub enum DeviceType {
|
|||||||
/// Device Type: Virtio.
|
/// Device Type: Virtio.
|
||||||
Virtio(u32),
|
Virtio(u32),
|
||||||
/// Device Type: Serial.
|
/// Device Type: Serial.
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||||
Serial,
|
Serial,
|
||||||
/// Device Type: RTC.
|
/// Device Type: RTC.
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
@ -153,7 +168,7 @@ impl fmt::Display for DeviceType {
|
|||||||
|
|
||||||
/// Structure to describe MMIO device information
|
/// Structure to describe MMIO device information
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||||
pub struct MmioDeviceInfo {
|
pub struct MmioDeviceInfo {
|
||||||
pub addr: u64,
|
pub addr: u64,
|
||||||
pub len: u64,
|
pub len: u64,
|
||||||
@ -162,7 +177,7 @@ pub struct MmioDeviceInfo {
|
|||||||
|
|
||||||
/// Structure to describe PCI space information
|
/// Structure to describe PCI space information
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||||
pub struct PciSpaceInfo {
|
pub struct PciSpaceInfo {
|
||||||
pub pci_segment_id: u16,
|
pub pci_segment_id: u16,
|
||||||
pub mmio_config_address: u64,
|
pub mmio_config_address: u64,
|
||||||
@ -170,7 +185,7 @@ pub struct PciSpaceInfo {
|
|||||||
pub pci_device_space_size: u64,
|
pub pci_device_space_size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||||
impl DeviceInfoForFdt for MmioDeviceInfo {
|
impl DeviceInfoForFdt for MmioDeviceInfo {
|
||||||
fn addr(&self) -> u64 {
|
fn addr(&self) -> u64 {
|
||||||
self.addr
|
self.addr
|
||||||
|
173
arch/src/riscv64/mod.rs
Normal file
173
arch/src/riscv64/mod.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
|
||||||
|
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
/// Module for the flattened device tree.
|
||||||
|
pub mod fdt;
|
||||||
|
/// Layout for this riscv64 system.
|
||||||
|
pub mod layout;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use hypervisor::arch::riscv64::aia::Vaia;
|
||||||
|
use log::{log_enabled, Level};
|
||||||
|
use thiserror::Error;
|
||||||
|
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
|
||||||
|
|
||||||
|
pub use self::fdt::DeviceInfoForFdt;
|
||||||
|
use crate::{DeviceType, GuestMemoryMmap, PciSpaceInfo, RegionType};
|
||||||
|
|
||||||
|
pub const _NSIG: i32 = 65;
|
||||||
|
|
||||||
|
/// Errors thrown while configuring riscv64 system.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Failed to create a FDT.
|
||||||
|
#[error("Failed to create a FDT")]
|
||||||
|
SetupFdt,
|
||||||
|
|
||||||
|
/// Failed to write FDT to memory.
|
||||||
|
#[error("Failed to write FDT to memory: {0}")]
|
||||||
|
WriteFdtToMemory(fdt::Error),
|
||||||
|
|
||||||
|
/// Failed to create a AIA.
|
||||||
|
#[error("Failed to create a AIA")]
|
||||||
|
SetupAia,
|
||||||
|
|
||||||
|
/// Failed to compute the initramfs address.
|
||||||
|
#[error("Failed to compute the initramfs address")]
|
||||||
|
InitramfsAddress,
|
||||||
|
|
||||||
|
/// Error configuring the general purpose registers
|
||||||
|
#[error("Error configuring the general purpose registers: {0}")]
|
||||||
|
RegsConfiguration(hypervisor::HypervisorCpuError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for super::Error {
|
||||||
|
fn from(e: Error) -> super::Error {
|
||||||
|
super::Error::PlatformSpecific(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
/// Specifies the entry point address where the guest must start
|
||||||
|
/// executing code.
|
||||||
|
pub struct EntryPoint {
|
||||||
|
/// Address in guest memory where the guest must start execution
|
||||||
|
pub entry_addr: GuestAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the specified VCPU, and return its MPIDR.
|
||||||
|
pub fn configure_vcpu(
|
||||||
|
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
||||||
|
id: u8,
|
||||||
|
boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>,
|
||||||
|
) -> super::Result<()> {
|
||||||
|
if let Some((kernel_entry_point, _guest_memory)) = boot_setup {
|
||||||
|
vcpu.setup_regs(
|
||||||
|
id,
|
||||||
|
kernel_entry_point.entry_addr.raw_value(),
|
||||||
|
layout::FDT_START.raw_value(),
|
||||||
|
)
|
||||||
|
.map_err(Error::RegsConfiguration)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
||||||
|
vec![
|
||||||
|
// 0 MiB ~ 256 MiB: AIA and legacy devices
|
||||||
|
(
|
||||||
|
GuestAddress(0),
|
||||||
|
layout::MEM_32BIT_DEVICES_START.0 as usize,
|
||||||
|
RegionType::Reserved,
|
||||||
|
),
|
||||||
|
// 256 MiB ~ 768 MiB: MMIO space
|
||||||
|
(
|
||||||
|
layout::MEM_32BIT_DEVICES_START,
|
||||||
|
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
||||||
|
RegionType::SubRegion,
|
||||||
|
),
|
||||||
|
// 768 MiB ~ 1 GiB: reserved. The leading 256M for PCIe MMCONFIG space
|
||||||
|
(
|
||||||
|
layout::PCI_MMCONFIG_START,
|
||||||
|
layout::PCI_MMCONFIG_SIZE as usize,
|
||||||
|
RegionType::Reserved,
|
||||||
|
),
|
||||||
|
// 1GiB ~ inf: RAM
|
||||||
|
(layout::RAM_START, usize::MAX, RegionType::Ram),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||||
|
guest_mem: &GuestMemoryMmap,
|
||||||
|
cmdline: &str,
|
||||||
|
num_vcpu: u32,
|
||||||
|
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||||
|
initrd: &Option<super::InitramfsConfig>,
|
||||||
|
pci_space_info: &[PciSpaceInfo],
|
||||||
|
aia_device: &Arc<Mutex<dyn Vaia>>,
|
||||||
|
) -> super::Result<()> {
|
||||||
|
let fdt_final = fdt::create_fdt(
|
||||||
|
guest_mem,
|
||||||
|
cmdline,
|
||||||
|
num_vcpu,
|
||||||
|
device_info,
|
||||||
|
aia_device,
|
||||||
|
initrd,
|
||||||
|
pci_space_info,
|
||||||
|
)
|
||||||
|
.map_err(|_| Error::SetupFdt)?;
|
||||||
|
|
||||||
|
if log_enabled!(Level::Debug) {
|
||||||
|
fdt::print_fdt(&fdt_final);
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt::write_fdt_to_memory(fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the memory address where the initramfs could be loaded.
|
||||||
|
pub fn initramfs_load_addr(
|
||||||
|
guest_mem: &GuestMemoryMmap,
|
||||||
|
initramfs_size: usize,
|
||||||
|
) -> super::Result<u64> {
|
||||||
|
let round_to_pagesize = |size| (size + (super::PAGE_SIZE - 1)) & !(super::PAGE_SIZE - 1);
|
||||||
|
match guest_mem
|
||||||
|
.last_addr()
|
||||||
|
.checked_sub(round_to_pagesize(initramfs_size) as u64 - 1)
|
||||||
|
{
|
||||||
|
Some(offset) => {
|
||||||
|
if guest_mem.address_in_range(offset) {
|
||||||
|
Ok(offset.raw_value())
|
||||||
|
} else {
|
||||||
|
Err(super::Error::PlatformSpecific(Error::InitramfsAddress))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Err(super::Error::PlatformSpecific(Error::InitramfsAddress)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_host_cpu_phys_bits(_hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
|
||||||
|
40
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_arch_memory_regions_dram() {
|
||||||
|
let regions = arch_memory_regions();
|
||||||
|
assert_eq!(4, regions.len());
|
||||||
|
assert_eq!(layout::RAM_START, regions[3].0);
|
||||||
|
assert_eq!(RegionType::Ram, regions[3].2);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user