Skip to content

Commit

Permalink
add x86 support
Browse files Browse the repository at this point in the history
  • Loading branch information
ZR233 committed Jan 2, 2025
1 parent c68bb86 commit f6745bf
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 52 deletions.
101 changes: 85 additions & 16 deletions modules/axhal/src/arch/aarch64/cache.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -12,28 +20,28 @@ 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<u8>, 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,
}
}
}

impl Iterator for DCacheIter {
type Item = usize;
type Item = VirtAddr;

fn next(&mut self) -> Option<Self::Item> {
if self.aligned_addr < self.end {
Expand All @@ -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<u8>, 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<u8>, 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");
}
}
8 changes: 1 addition & 7 deletions modules/axhal/src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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).
Expand Down
7 changes: 7 additions & 0 deletions modules/axhal/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ cfg_if::cfg_if! {
pub use self::aarch64::*;
}
}

#[derive(Debug, Clone, Copy)]
pub enum CacheOp {
Clean,
Invalidate,
CleanAndInvalidate,
}
18 changes: 18 additions & 0 deletions modules/axhal/src/arch/riscv/cache.rs
Original file line number Diff line number Diff line change
@@ -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) {}
18 changes: 2 additions & 16 deletions modules/axhal/src/arch/riscv/mod.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand Down Expand Up @@ -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<u8>, _size: usize) {
// generic no cache and no need op
// TODO: some cpu specific
}

/// Flush data cache
#[inline]
pub fn dcache_flush_range(_addr: NonNull<u8>, _size: usize) {
// generic no cache and no need op
// TODO: some cpu specific
}
15 changes: 15 additions & 0 deletions modules/axhal/src/arch/x86_64/cache.rs
Original file line number Diff line number Diff line change
@@ -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) {}
16 changes: 3 additions & 13 deletions modules/axhal/src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
mod cache;
mod context;
mod gdt;
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};
Expand All @@ -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.
Expand Down Expand Up @@ -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<u8>, size: usize) {
unimplemented!()
}

/// Flush data cache
#[inline]
pub fn dcache_flush_range(addr: NonNull<u8>, size: usize) {
unimplemented!()
}

0 comments on commit f6745bf

Please sign in to comment.