From f6745bfd4a11d03594537f844b0675cb7633de13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 2 Jan 2025 07:33:30 +0000 Subject: [PATCH] add x86 support --- modules/axhal/src/arch/aarch64/cache.rs | 101 ++++++++++++++++++++---- modules/axhal/src/arch/aarch64/mod.rs | 8 +- modules/axhal/src/arch/mod.rs | 7 ++ modules/axhal/src/arch/riscv/cache.rs | 18 +++++ modules/axhal/src/arch/riscv/mod.rs | 18 +---- modules/axhal/src/arch/x86_64/cache.rs | 15 ++++ modules/axhal/src/arch/x86_64/mod.rs | 16 +--- 7 files changed, 131 insertions(+), 52 deletions(-) create mode 100644 modules/axhal/src/arch/riscv/cache.rs create mode 100644 modules/axhal/src/arch/x86_64/cache.rs diff --git a/modules/axhal/src/arch/aarch64/cache.rs b/modules/axhal/src/arch/aarch64/cache.rs index 80b9fc0846..1f4380ba6b 100644 --- a/modules/axhal/src/arch/aarch64/cache.rs +++ b/modules/axhal/src/arch/aarch64/cache.rs @@ -1,4 +1,12 @@ -use core::{arch::asm, ptr::NonNull}; +use core::arch::asm; + +use aarch64_cpu::{ + asm::barrier::{isb, SY}, + registers::*, +}; +use memory_addr::VirtAddr; + +use crate::arch::CacheOp; #[inline(always)] fn cache_line_size() -> usize { @@ -12,20 +20,20 @@ fn cache_line_size() -> usize { } struct DCacheIter { - aligned_addr: usize, - end: usize, + aligned_addr: VirtAddr, + end: VirtAddr, cache_line_size: usize, } impl DCacheIter { - fn new(addr: NonNull, size: usize) -> DCacheIter { - let start = addr.as_ptr() as usize; + fn new(addr: VirtAddr, size: usize) -> DCacheIter { + let start = addr; let end = start + size; let cache_line_size = cache_line_size(); - let aligned_addr = addr.as_ptr() as usize & !(cache_line_size - 1); + let aligned_addr = addr.as_usize() & !(cache_line_size - 1); DCacheIter { - aligned_addr, + aligned_addr: aligned_addr.into(), end, cache_line_size, } @@ -33,7 +41,7 @@ impl DCacheIter { } impl Iterator for DCacheIter { - type Item = usize; + type Item = VirtAddr; fn next(&mut self) -> Option { if self.aligned_addr < self.end { @@ -45,23 +53,84 @@ impl Iterator for DCacheIter { } } } +/// Performs a cache operation on all memory. +pub fn dcache_all(op: CacheOp) { + let clidr = CLIDR_EL1.get(); + + for level in 0..8 { + let ty = (clidr >> (level * 0b111)) & 0b111; + if ty == 0 { + return; + } -/// Invalidate data cache -pub fn dcache_invalidate_range(addr: NonNull, size: usize) { + dcache_level(op, level); + } + unsafe { asm!("dsb sy; isb") }; +} + +/// Performs a cache operation on a range of memory. +#[inline] +pub fn dcache_range(op: CacheOp, addr: VirtAddr, size: usize) { unsafe { for addr in DCacheIter::new(addr, size) { - asm!("dc ivac, {}", in(reg) addr); + _dcache_line(op, addr); } asm!("dsb sy"); } } -/// Flush data cache -pub fn dcache_flush_range(addr: NonNull, size: usize) { +/// Performs a cache operation on a cache line. +#[inline] +fn _dcache_line(op: CacheOp, addr: VirtAddr) { unsafe { - for addr in DCacheIter::new(addr, size) { - asm!("dc civac, {}", in(reg) addr); + match op { + CacheOp::Invalidate => asm!("dc ivac, {0:x}", in(reg) addr.as_usize()), + CacheOp::Clean => asm!("dc cvac, {0:x}", in(reg) addr.as_usize()), + CacheOp::CleanAndInvalidate => asm!("dc civac, {0:x}", in(reg) addr.as_usize()), + } + } +} + +/// Performs a cache operation on a cache line. +#[inline] +pub fn dcache_line(op: CacheOp, addr: VirtAddr) { + _dcache_line(op, addr); + unsafe { + asm!("dsb sy; isb"); + } +} + +/// Performs a cache operation on a cache level. +/// https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Instructions/DC-CISW--Data-or-unified-Cache-line-Clean-and-Invalidate-by-Set-Way +#[inline] +fn dcache_level(op: CacheOp, level: u64) { + assert!(level < 8, "armv8 level range is 0-7"); + + isb(SY); + CSSELR_EL1.write(CSSELR_EL1::InD::Data + CSSELR_EL1::Level.val(level)); + isb(SY); + let lines = CCSIDR_EL1.read(CCSIDR_EL1::LineSize) as u32; + let ways = CCSIDR_EL1.read(CCSIDR_EL1::AssociativityWithCCIDX) as u32; + let sets = CCSIDR_EL1.read(CCSIDR_EL1::NumSetsWithCCIDX) as u32; + + let l = lines + 4; + + // Calculate bit position of number of ways + let way_adjust = ways.leading_zeros(); + + // Loop over sets and ways + for set in 0..sets { + for way in 0..ways { + let set_way = (way << way_adjust) | set << l; + + let cisw = (level << 1) | set_way as u64; + unsafe { + match op { + CacheOp::Invalidate => asm!("dc isw, {0}", in(reg) cisw), + CacheOp::Clean => asm!("dc cisw, {0}", in(reg) cisw), + CacheOp::CleanAndInvalidate => asm!("dc cisw, {0}", in(reg) cisw), + } + } } - asm!("dsb sy"); } } diff --git a/modules/axhal/src/arch/aarch64/mod.rs b/modules/axhal/src/arch/aarch64/mod.rs index 13d456ec97..a109b43a63 100644 --- a/modules/axhal/src/arch/aarch64/mod.rs +++ b/modules/axhal/src/arch/aarch64/mod.rs @@ -9,7 +9,7 @@ use memory_addr::{PhysAddr, VirtAddr}; use tock_registers::interfaces::{Readable, Writeable}; pub use self::context::{FpState, TaskContext, TrapFrame}; -pub use cache::{dcache_flush_range, dcache_invalidate_range}; +pub use cache::*; /// Allows the current CPU to respond to interrupts. #[inline] @@ -112,12 +112,6 @@ pub fn set_exception_vector_base(vbar_el1: usize) { VBAR_EL1.set(vbar_el1 as _); } -/// Flushes the data cache line (64 bytes) at the given virtual address -#[inline] -pub fn flush_dcache_line(vaddr: VirtAddr) { - unsafe { asm!("dc ivac, {0:x}; dsb sy; isb", in(reg) vaddr.as_usize()) }; -} - /// Reads the thread pointer of the current CPU. /// /// It is used to implement TLS (Thread Local Storage). diff --git a/modules/axhal/src/arch/mod.rs b/modules/axhal/src/arch/mod.rs index b8bc0af3d0..71ea3fe7af 100644 --- a/modules/axhal/src/arch/mod.rs +++ b/modules/axhal/src/arch/mod.rs @@ -12,3 +12,10 @@ cfg_if::cfg_if! { pub use self::aarch64::*; } } + +#[derive(Debug, Clone, Copy)] +pub enum CacheOp { + Clean, + Invalidate, + CleanAndInvalidate, +} diff --git a/modules/axhal/src/arch/riscv/cache.rs b/modules/axhal/src/arch/riscv/cache.rs new file mode 100644 index 0000000000..18eefd8006 --- /dev/null +++ b/modules/axhal/src/arch/riscv/cache.rs @@ -0,0 +1,18 @@ +use memory_addr::VirtAddr; + +use crate::arch::CacheOp; + +/// Performs a cache operation on all memory. +pub fn dcache_all(_op: CacheOp) { + // generic riscv cpu does not have data cache. + + // TODO: cpu specific cache operations. +} + +/// Performs a cache operation on a range of memory. +#[inline] +pub fn dcache_range(_op: CacheOp, _addr: VirtAddr, _size: usize) {} + +/// Performs a cache operation on a cache line. +#[inline] +pub fn dcache_line(_op: CacheOp, _addr: VirtAddr) {} diff --git a/modules/axhal/src/arch/riscv/mod.rs b/modules/axhal/src/arch/riscv/mod.rs index 8304cf7cbd..fc39fd4538 100644 --- a/modules/axhal/src/arch/riscv/mod.rs +++ b/modules/axhal/src/arch/riscv/mod.rs @@ -1,16 +1,16 @@ #[macro_use] mod macros; +mod cache; mod context; mod trap; -use core::ptr::NonNull; - use memory_addr::{PhysAddr, VirtAddr}; use riscv::asm; use riscv::register::{satp, sstatus, stvec}; pub use self::context::{GeneralRegisters, TaskContext, TrapFrame}; +pub use cache::*; /// Allows the current CPU to respond to interrupts. #[inline] @@ -109,17 +109,3 @@ pub fn read_thread_pointer() -> usize { pub unsafe fn write_thread_pointer(tp: usize) { core::arch::asm!("mv tp, {}", in(reg) tp) } - -/// Invalidate data cache -#[inline] -pub fn dcache_invalidate_range(_addr: NonNull, _size: usize) { - // generic no cache and no need op - // TODO: some cpu specific -} - -/// Flush data cache -#[inline] -pub fn dcache_flush_range(_addr: NonNull, _size: usize) { - // generic no cache and no need op - // TODO: some cpu specific -} diff --git a/modules/axhal/src/arch/x86_64/cache.rs b/modules/axhal/src/arch/x86_64/cache.rs new file mode 100644 index 0000000000..7aed1e445a --- /dev/null +++ b/modules/axhal/src/arch/x86_64/cache.rs @@ -0,0 +1,15 @@ +use memory_addr::VirtAddr; + +use crate::arch::CacheOp; + +/// Performs a cache operation on all memory. +pub fn dcache_all(_op: CacheOp) { + // The cache coherency in x86 architectures is guaranteed by hardware. +} + +/// Performs a cache operation on a range of memory. +pub fn dcache_range(_op: CacheOp, _addr: VirtAddr, _size: usize) {} + +/// Performs a cache operation on a cache line. +#[inline] +pub fn dcache_line(_op: CacheOp, _addr: VirtAddr) {} diff --git a/modules/axhal/src/arch/x86_64/mod.rs b/modules/axhal/src/arch/x86_64/mod.rs index 7dc889feef..d4feac5fa7 100644 --- a/modules/axhal/src/arch/x86_64/mod.rs +++ b/modules/axhal/src/arch/x86_64/mod.rs @@ -1,3 +1,4 @@ +mod cache; mod context; mod gdt; mod idt; @@ -5,7 +6,7 @@ mod idt; #[cfg(target_os = "none")] mod trap; -use core::{arch::asm, ptr::NonNull}; +use core::arch::asm; use memory_addr::{MemoryAddr, PhysAddr, VirtAddr}; use x86::{controlregs, msr, tlb}; @@ -14,6 +15,7 @@ use x86_64::instructions::interrupts; pub use self::context::{ExtendedState, FxsaveArea, TaskContext, TrapFrame}; pub use self::gdt::GdtStruct; pub use self::idt::IdtStruct; +pub use cache::*; pub use x86_64::structures::tss::TaskStateSegment; /// Allows the current CPU to respond to interrupts. @@ -116,15 +118,3 @@ pub fn read_thread_pointer() -> usize { pub unsafe fn write_thread_pointer(fs_base: usize) { unsafe { msr::wrmsr(msr::IA32_FS_BASE, fs_base as u64) } } - -/// Invalidate data cache -#[inline] -pub fn dcache_invalidate_range(addr: NonNull, size: usize) { - unimplemented!() -} - -/// Flush data cache -#[inline] -pub fn dcache_flush_range(addr: NonNull, size: usize) { - unimplemented!() -}