Skip to content
Merged
207 changes: 149 additions & 58 deletions hikami_core/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
pub mod aclint;
mod axi_sdc;
pub mod clint;
mod initrd;
pub mod pci;
pub mod plic;
mod rtc;
mod sdhci;
pub mod uart;
mod virtio;

use crate::memmap::page_table::{PteFlag, constants::PAGE_SIZE, g_stage_trans_addr};
use crate::memmap::{GuestPhysicalAddress, HostPhysicalAddress, MemoryMap, page_table};

use alloc::string::{String, ToString};
use alloc::vec::Vec;
use fdt::Fdt;
use fdt::standard_nodes::MemoryRegion;
Expand Down Expand Up @@ -197,6 +195,7 @@
) -> Option<Self>
where
Self: Sized;

/// Create page table
fn create_page_table(
root_page_table_addr: HostPhysicalAddress,
Expand Down Expand Up @@ -226,8 +225,50 @@
.collect();
page_table::sv39x4::generate_page_table(root_page_table_addr, &memory_maps);
}
/// Return memory maps between physical to physical (identity map) for crate page table.
fn memmap(&self) -> Vec<MemoryMap>;

/// Return device tree node name
fn name(&self) -> &str;
}

/// Other memory mapped divice
///
/// The all devices which aren't managed by the hypervisor is mapped identically.
#[derive(Debug)]
pub struct OtherMmioDevice {
/// Device tree name
pub name: String,
/// Memory maps for memory mapped register.
pub register_map_regions: Vec<MemoryRegion>,
}

/// Create page table for `OtherMmioDevice`
fn create_page_table_for_other_devices(
root_page_table_addr: HostPhysicalAddress,
memory_regions: &[MemoryRegion],
node_name: &str,
) {
for map in memory_regions {
crate::println!(
"[Other MMIO Device Map] {}: {:#x}..{:#x}",
node_name,
map.starting_address as usize,
map.starting_address as usize + map.size.unwrap(),
)
}
let memory_maps: Vec<MemoryMap> = memory_regions
.iter()
.cloned()
.map(|mut region| {
if region.starting_address as usize % PAGE_SIZE == 0 {
MemoryMap::from(region)
} else {
region.starting_address =
((region.starting_address as usize) & !(PAGE_SIZE - 1)) as *const u8;
MemoryMap::from(region)
}
})
.collect();
page_table::sv39x4::generate_page_table(root_page_table_addr, &memory_maps);
}

/// Manage devices sush as uart, plic, etc...
Expand All @@ -236,16 +277,13 @@
/// Each devices **must** be implemented Device trait.
#[derive(Debug)]
#[allow(clippy::doc_markdown)]
pub struct Devices {

Check warning on line 280 in hikami_core/src/device.rs

View workflow job for this annotation

GitHub Actions / lint

[clippy] reported by reviewdog 🐶 field `other_mmio_devices` is never read Raw Output: hikami_core/src/device.rs:280:12: warning: field `other_mmio_devices` is never read (dead_code)
/// UART: Universal Asynchronous Receiver-Transmitter
pub uart: uart::Uart,

/// Lists of Virtio.
pub virtio_list: virtio::VirtIoList,

/// initrd: INITial RamDisk
pub initrd: Option<initrd::Initrd>,

/// PLIC: Platform-Level Interrupt Controller
pub plic: plic::Plic,

Expand All @@ -255,17 +293,14 @@
/// aclint: Advanced Core Local INTerrupt
pub aclint: Option<aclint::Aclint>,

/// RTC: Real Time Clock.
pub rtc: Option<rtc::Rtc>,

/// PCI: Peripheral Component Interconnect
pub pci: Option<pci::Pci>,

/// Axi SD card
pub axi_sdc: Option<axi_sdc::Mmc>,

/// SDHCI: SD Host Controller Interface
pub sdhci: Option<sdhci::Mmc>,
/// Other mmio devices
other_mmio_devices: Vec<OtherMmioDevice>,
}

impl Devices {
Expand All @@ -275,52 +310,108 @@
/// Panics if UART or PLIC or CLINT are not found in device tree.
#[must_use]
pub fn new(root_page_table_addr: HostPhysicalAddress, device_tree: Fdt) -> Self {
let uart = uart::Uart::try_new(
root_page_table_addr,
&device_tree,
&["ns16550a", "snps,dw-apb-uart"],
)
.expect("uart is not found in fdt");
let virtio_list =
virtio::VirtIoList::new(root_page_table_addr, &device_tree, "/soc/virtio_mmio");
let plic = plic::Plic::try_new(
root_page_table_addr,
&device_tree,
&["riscv,plic0", "sifive,plic-1.0.0"],
)
.expect("plic is not found in fdt");
let clint = clint::Clint::try_new(
root_page_table_addr,
&device_tree,
&["sifive,clint0", "riscv,clint0"],
);
let aclint = aclint::Aclint::try_new_aclint(
root_page_table_addr,
&device_tree,
&["thead,c900-aclint-mswi"],
&["thead,c900-aclint-mtimer"],
);
let pci = pci::Pci::try_new(
root_page_table_addr,
&device_tree,
&["pci-host-ecam-generic"],
);
let axi_sdc = axi_sdc::Mmc::try_new(
root_page_table_addr,
&device_tree,
&["riscv,axi-sd-card-1.0"],
);

// mapping other devices except for devices have already mapped.
let mut exclude_list: Vec<_> = virtio_list.iter().map(|x| x.name()).collect();
exclude_list.extend(&[
uart.name(),
plic.name(),
clint.as_ref().map(|x| x.name()).unwrap_or(""),
aclint.as_ref().map(|x| x.mswi.name()).unwrap_or(""),
aclint.as_ref().map(|x| x.mtimer.name()).unwrap_or(""),
pci.as_ref().map(|x| x.name()).unwrap_or(""),
axi_sdc.as_ref().map(|x| x.name()).unwrap_or(""),
]);
let other_mmio_devices =
Self::get_other_mmio_devices(root_page_table_addr, &device_tree, &exclude_list);

Devices {
uart: uart::Uart::try_new(
root_page_table_addr,
&device_tree,
&["ns16550a", "snps,dw-apb-uart"],
)
.expect("uart is not found in fdt"),
virtio_list: virtio::VirtIoList::new(
root_page_table_addr,
&device_tree,
"/soc/virtio_mmio",
),
initrd: initrd::Initrd::try_new_from_node_path(
root_page_table_addr,
&device_tree,
"/chosen",
),
plic: plic::Plic::try_new(root_page_table_addr, &device_tree, &["riscv,plic0"])
.expect("plic is not found in fdt"),
clint: clint::Clint::try_new(
root_page_table_addr,
&device_tree,
&["sifive,clint0", "riscv,clint0"],
),
aclint: aclint::Aclint::try_new_aclint(
root_page_table_addr,
&device_tree,
&["thead,c900-aclint-mswi"],
&["thead,c900-aclint-mtimer"],
),
rtc: rtc::Rtc::try_new(root_page_table_addr, &device_tree, &["google,goldfish-rtc"]),
pci: pci::Pci::try_new(
root_page_table_addr,
&device_tree,
&["pci-host-ecam-generic"],
),
axi_sdc: axi_sdc::Mmc::try_new(
root_page_table_addr,
&device_tree,
&["riscv,axi-sd-card-1.0"],
),
sdhci: sdhci::Mmc::try_new(
root_page_table_addr,
&device_tree,
&["eswin,emmc-sdhci-5.1"],
),
uart,
virtio_list,
plic,
clint,
aclint,
pci,
axi_sdc,
other_mmio_devices,
}
}

fn get_other_mmio_devices(
root_page_table_addr: HostPhysicalAddress,
device_tree: &Fdt,
exclude_list: &[&str],
) -> Vec<OtherMmioDevice> {
let mut other_devices = Vec::new();
if let Some(soc) = device_tree.find_node("/soc") {
for node in soc.children() {
// skip if it marked as disabled.
if let Some(status) = node.property("status") {
if status.as_str() == Some("disabled") {
continue;
}
}

// skip if it has already mapped.
if exclude_list.contains(&node.name) {
continue;
}

// skip if it isn't memory mapped device.
if !node.reg().is_some() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ [clippy] clippy::nonminimal_bool reported by reviewdog 🐶
this boolean expression can be simplified

continue;
}

let register_map_regions: Vec<MemoryRegion> = node.reg().unwrap().collect();

create_page_table_for_other_devices(
root_page_table_addr,
&register_map_regions,
node.name,
);

other_devices.push(OtherMmioDevice {
name: node.name.to_string(),
register_map_regions,
});
}
}

other_devices
}
}
16 changes: 6 additions & 10 deletions hikami_core/src/device/aclint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
mod mswi;
mod mtimer;

use super::{MmioDevice, PTE_FLAGS_FOR_DEVICE};
use crate::memmap::{HostPhysicalAddress, MemoryMap};
use super::MmioDevice;
use crate::memmap::HostPhysicalAddress;

use alloc::vec::Vec;
use fdt::{Fdt, standard_nodes::MemoryRegion};
use fdt::Fdt;

#[allow(clippy::doc_markdown)]
/// ACLINT: Advanced Core Local INTerrupt
Expand All @@ -17,7 +16,7 @@ pub struct Aclint {
/// MSWI
pub mswi: mswi::Mswi,
/// MTIMER
mtimer: mtimer::Mtimer,
pub mtimer: mtimer::Mtimer,
}

impl Aclint {
Expand All @@ -43,10 +42,7 @@ impl MmioDevice for Aclint {
unreachable!("Use `Aclint::try_new_aclint` instead");
}

fn memmap(&self) -> Vec<MemoryMap> {
let mut memory_maps = self.mswi.memmap();
memory_maps.append(&mut self.mtimer.memmap());

memory_maps
fn name(&self) -> &str {
unreachable!("call `Mswi::name` and `Mtimer::name` directly")
}
}
14 changes: 7 additions & 7 deletions hikami_core/src/device/aclint/mswi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
//! It has an IPI register (MSIP) for each HART connected to the MSWI device.

use super::super::{DeviceEmulateError, MmioDevice};
use crate::memmap::{HostPhysicalAddress, MemoryMap};
use crate::memmap::HostPhysicalAddress;

use alloc::string::{String, ToString};
use alloc::vec::Vec;
use fdt::{Fdt, standard_nodes::MemoryRegion};

Expand All @@ -15,6 +16,8 @@ const MSWI_REG_SIZE: usize = 0x4;
/// MSWI: Machine level SoftWare Interrupt device
#[derive(Debug)]
pub struct Mswi {
/// Device tree name
name: String,
/// Memory maps for memory mapped register.
register_map_regions: Vec<MemoryRegion>,
}
Expand Down Expand Up @@ -96,15 +99,12 @@ impl MmioDevice for Mswi {
let register_map_regions: Vec<MemoryRegion> = clint_node.reg().unwrap().collect();

Some(Mswi {
name: clint_node.name.to_string(),
register_map_regions,
})
}

fn memmap(&self) -> Vec<MemoryMap> {
self.register_map_regions
.clone()
.into_iter()
.map(MemoryMap::from)
.collect()
fn name(&self) -> &str {
&self.name
}
}
35 changes: 8 additions & 27 deletions hikami_core/src/device/aclint/mtimer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
//! It has a single fixed-frequency monotonic time counter (MTIME) register and a time compare register (MTIMECMP) for each HART connected to the MTIMER device.
//! A MTIMER device not connected to any HART should only have a MTIME register and no MTIMECMP registers.

use super::{MmioDevice, PTE_FLAGS_FOR_DEVICE};
use crate::memmap::{
GuestPhysicalAddress, HostPhysicalAddress, MemoryMap, page_table::constants::PAGE_SIZE,
};
use super::MmioDevice;
use crate::memmap::HostPhysicalAddress;

use alloc::string::{String, ToString};
use alloc::vec::Vec;
use fdt::{Fdt, standard_nodes::MemoryRegion};

/// MTIMER: Machine level TIMER device
#[derive(Debug)]
pub struct Mtimer {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ [clippy] <dead_code> reported by reviewdog 🐶
field register_map_regions is never read

/// Device tree name
name: String,
/// Memory maps for memory mapped register.
register_map_regions: Vec<MemoryRegion>,
}
Expand All @@ -30,32 +31,12 @@ impl MmioDevice for Mtimer {
Self::create_page_table(root_page_table_addr, &register_map_regions, clint_node.name);

Some(Mtimer {
name: clint_node.name.to_string(),
register_map_regions,
})
}

fn memmap(&self) -> Vec<MemoryMap> {
self.register_map_regions
.clone()
.into_iter()
.map(|region| {
let mut size = region.size.unwrap();
let mut virt_start = GuestPhysicalAddress(region.starting_address as usize);
let mut phys_start = HostPhysicalAddress(region.starting_address as usize);

// change memory map region if region size is less than the page size.
if phys_start % PAGE_SIZE != 0 && size < PAGE_SIZE {
size = PAGE_SIZE;
virt_start = virt_start - (virt_start % PAGE_SIZE);
phys_start = phys_start - (phys_start % PAGE_SIZE);
}

MemoryMap::new(
virt_start..virt_start + size,
phys_start..phys_start + size,
&PTE_FLAGS_FOR_DEVICE,
)
})
.collect()
fn name(&self) -> &str {
&self.name
}
}
Loading
Loading