Selaa lähdekoodia

feat(hal): impl basic cpu for riscv64

Heinz 8 kuukautta sitten
vanhempi
commit
35d94146e9

+ 190 - 0
crates/eonix_hal/src/arch/riscv64/cpu.rs

@@ -0,0 +1,190 @@
+use core::pin::Pin;
+use riscv::register::{
+    mhartid,
+    sscratch,
+    sstatus
+};
+use sbi::PhysicalAddress;
+use eonix_preempt::PreemptGuard;
+use eonix_sync_base::LazyLock;
+
+/// TODO:
+/// CPU 的一些函数
+/// 
+
+#[eonix_percpu::define_percpu]
+static LOCAL_CPU: LazyLock<CPU> = LazyLock::new(CPU::new);
+
+use super::{
+    config::smp::get_num_harts,
+    mm::setup_kernel_satp,
+    trap::setup_kernel_trap,
+    interrupt::InterruptControl
+};
+
+#[derive(Debug, Clone)]
+pub enum UserTLS {
+    Base(u32),
+}
+
+/// RISC-V Hart
+pub struct CPU {
+    hart_id: usize,
+    interrupt: InterruptControl,
+}
+
+impl UserTLS {
+    #[allow(unused_variables)]
+    pub fn new32(base: u32, _limit: u32, _is_limit_in_pages: bool) -> (Self, u32) {
+        (Self::Base(base), 0)
+    }
+}
+
+impl CPU {
+    pub fn new() -> Self {
+        let hart_id = read_hart_id();
+        Self {
+            hart_id: hart_id,
+            interrupt: InterruptControl::new(hart_id),
+        }
+    }
+
+    /// Load CPU specific configurations for the current Hart.
+    ///
+    /// # Safety
+    /// This function performs low-level hardware initialization and should
+    /// only be called once per Hart during its boot sequence.
+    pub unsafe fn init(self: Pin<&mut Self>) {
+        let self_mut = self.get_unchecked_mut();
+
+        sscratch::write(self_mut.hart_id as usize);
+
+        setup_kernel_trap();
+
+        // CLINT, 10_000 ms
+        self_mut.interrupt.setup_timer(10_000);
+
+        // Supervisor Mode Status Register (sstatus)
+        // SUM (Supervisor User Memory access): support S-mode access user memory
+        // MXR (Make Executable Readable)
+        // SIE (Supervisor Interrupt Enable): enable S-mode interrupt
+        let mut current_sstatus = sstatus::read();
+        current_sstatus.set_spp(sstatus::SPP::Supervisor);
+        current_sstatus.set_sum(true);
+        current_sstatus.set_mxr(true);
+        current_sstatus.set_sie(true);
+        sstatus::write(current_sstatus);
+
+        // setup kernel page table and flush tlb
+        setup_kernel_satp();
+    }
+
+    /// Boot all other hart.
+    pub unsafe fn bootstrap_cpus(&self) {
+        unsafe extern "C" {
+        fn ap_boot_entry();
+        }
+        let total_harts = get_num_harts();
+
+        let ap_entry_point = PhysicalAddress::new(ap_boot_entry as usize);
+
+        for i in 1..total_harts {
+            sbi::hsm::hart_start(i, ap_entry_point, 0)
+                .expect("Failed to start secondary hart via SBI");
+        }
+    }
+
+    // TODO: 
+    pub unsafe fn load_interrupt_stack(self: Pin<&mut Self>, rsp: u64) {
+        /*unsafe {
+            self.map_unchecked_mut(|me| &mut me.tss).set_rsp0(rsp);
+        }*/
+    }
+
+    pub fn end_of_interrupt(self: Pin<&mut Self>) {
+        unsafe {
+            // TODO: 不知道写的对不对。。。
+            self.map_unchecked_mut(|me| &mut me.interrupt)
+                .clear_soft_interrupt_pending();
+        }
+    }
+
+    pub fn local() -> PreemptGuard<Pin<&'static mut Self>> {
+        unsafe {
+            // SAFETY: We pass the reference into a `PreemptGuard`, which ensures
+            //         that preemption is disabled.
+            PreemptGuard::new(Pin::new_unchecked(LOCAL_CPU.as_mut().get_mut()))
+        }
+    }
+
+
+    pub fn cpuid(&self) -> usize {
+        self.hart_id
+    }
+}
+
+fn read_hart_id() -> usize {
+    mhartid::read()
+}
+
+#[macro_export]
+macro_rules! define_smp_bootstrap {
+    ($cpu_count:literal, $ap_entry:ident, $alloc_kstack:tt) => {
+        #[no_mangle]
+        static BOOT_SEMAPHORE: core::sync::atomic::AtomicU64 =
+            core::sync::atomic::AtomicU64::new(0);
+        #[no_mangle]
+        static BOOT_STACK: core::sync::atomic::AtomicU64 =
+            core::sync::atomic::AtomicU64::new(0);
+
+        #[no_mangle]
+        static CPU_COUNT: core::sync::atomic::AtomicU64 =
+            core::sync::atomic::AtomicU64::new(0);
+
+        core::arch::global_asm!(
+            r#"
+        .section .text.ap_boot
+        .globl ap_boot_entry
+
+        ap_boot_entry:
+            csrr a0, mhartid
+
+        1:
+            lw t0, AP_BOOT_STACK.addr
+            beqz t0, 1b
+            li t1, 0
+            sw t1, AP_BOOT_STACK.addr
+            mv sp, t0
+
+        2:
+            lw t0, AP_BOOT_SEMAPHORE.addr
+            beqz t0, 2b
+
+            li t1, 0
+            sw t1, AP_BOOT_SEMAPHORE.addr
+
+            li t0, 1
+            amoswap.w.aq rl t0, a0, ONLINE_HART_COUNT.addr
+
+            call $ap_entry
+            j .
+            "#,
+            BOOT_SEMAPHORE = sym BOOT_SEMAPHORE,
+            BOOT_STACK = sym BOOT_STACK,
+            CPU_COUNT = sym CPU_COUNT,
+            AP_ENTRY = sym $ap_entry,
+        );
+
+        pub unsafe fn wait_cpus_online() {
+            use core::sync::atomic::Ordering;
+            while CPU_COUNT.load(Ordering::Acquire) != $cpu_count - 1 {
+                if BOOT_STACK.load(Ordering::Acquire) == 0 {
+                    let stack_bottom = $alloc_kstack as u64;
+                    BOOT_STACK.store(stack_bottom, Ordering::Release);
+                }
+                $crate::pause();
+            }
+        }
+    };
+}
+

+ 0 - 53
crates/eonix_hal/src/arch/riscv64/fence.rs

@@ -1,53 +0,0 @@
-use core::arch::asm;
-
-#[doc(hidden)]
-/// Issues a full memory barrier.
-///
-/// Ensures all memory operations issued before the fence are globally
-/// visible before any memory operations issued after the fence.
-///
-/// **NO COMPILER BARRIERS** are emitted by this function.
-pub fn memory_barrier() {
-    unsafe {
-        // rw for both predecessor and successor: read-write, read-write
-        asm!("fence rw, rw", options(nostack, nomem, preserves_flags));
-    }
-}
-
-#[doc(hidden)]
-/// Issues a read memory barrier.
-///
-/// Ensures all memory loads issued before the fence are globally
-/// visible before any memory loads issued after the fence.
-///
-/// **NO COMPILER BARRIERS** are emitted by this function.
-pub fn read_memory_barrier() {
-    unsafe {
-        // r for both predecessor and successor: read, read
-        asm!("fence r, r", options(nostack, nomem, preserves_flags));
-    }
-}
-
-#[doc(hidden)]
-/// Issues a write memory barrier.
-///
-/// Ensures all memory stores issued before the fence are globally
-/// visible before any memory stores issued after the fence.
-///
-/// **NO COMPILER BARRIERS** are emitted by this function.
-pub fn write_memory_barrier() {
-    unsafe {
-        // w for both predecessor and successor: write, write
-        asm!("fence w, w", options(nostack, nomem, preserves_flags));
-    }
-}
-
-#[doc(hidden)]
-/// Issues a TLB invalidation memory barrier.
-///
-/// Typically used after modifying page tables.
-pub fn tlb_flush() {
-    unsafe {
-        asm!("sfence.vma zero, zero", options(nostack, nomem, preserves_flags));
-    }
-}

+ 0 - 59
crates/eonix_hal/src/arch/riscv64/io.rs

@@ -1,59 +0,0 @@
-use core::ptr::{read_volatile, write_volatile};
-use riscv::register::sstatus::{self, FS};
-
-pub fn enable_sse() {
-    unsafe {
-        // FS (Floating-point Status) Initial (0b01)
-        sstatus::set_fs(FS::Initial);
-    }
-}
-
-// MMIO
-
-pub fn inb(addr: usize) -> u8 {
-    unsafe {
-        read_volatile(addr as *const u8)
-    }
-}
-
-pub fn inw(addr: usize) -> u16 {
-    unsafe {
-        read_volatile(addr as *const u16)
-    }
-}
-
-pub fn inl(addr: usize) -> u32 {
-    unsafe {
-        read_volatile(addr as *const u32)
-    }
-}
-
-pub fn inu64(addr: usize) -> u64 {
-    unsafe {
-        read_volatile(addr as *const u64)
-    }
-}
-
-pub fn outb(addr: usize, data: u8) {
-    unsafe {
-        write_volatile(addr as *mut u8, data)
-    }
-}
-
-pub fn outw(addr: usize, data: u16) {
-    unsafe {
-        write_volatile(addr as *mut u16, data)
-    }
-}
-
-pub fn outl(addr: usize, data: u32) {
-    unsafe {
-        write_volatile(addr as *mut u32, data)
-    }
-}
-
-pub fn outu64(addr: usize, data: u64) {
-    unsafe {
-        write_volatile(addr as *mut u64, data)
-    }
-}

+ 12 - 0
crates/eonix_hal/src/arch/riscv64/mod.rs

@@ -0,0 +1,12 @@
+pub mod bootstrap;
+pub mod cpu;
+pub mod fdt;
+pub mod mm;
+pub mod context;
+pub mod trap;
+pub mod interrupt;
+mod config;
+
+// TODO:
+// linker
+// 开始做适配