Parcourir la source

feat(hal): impl basic single hart bootstrap for riscv64

Heinz il y a 7 mois
Parent
commit
191877a3ac
1 fichiers modifiés avec 225 ajouts et 0 suppressions
  1. 225 0
      crates/eonix_hal/src/arch/riscv64/bootstrap.rs

+ 225 - 0
crates/eonix_hal/src/arch/riscv64/bootstrap.rs

@@ -0,0 +1,225 @@
+use crate::{
+    arch::{
+        cpu::CPU, fdt::init_dtb_and_fdt, mm::{ArchPhysAccess, PageAttribute64, PagingModeSv39, GLOBAL_PAGE_TABLE, V_KERNEL_BSS_START}
+    },
+    bootstrap::BootStrapData,
+    mm::{ArchMemory, ArchPagingMode, BasicPageAlloc, BasicPageAllocRef, ScopedAllocator},
+};
+use acpi::{platform::ProcessorState, AcpiHandler, AcpiTables, PhysicalMapping, PlatformInfo};
+use riscv::{asm::sfence_vma_all, register::{satp, sstatus::{self, FS}}};
+use core::{
+    alloc::Allocator,
+    arch::{asm, global_asm},
+    cell::RefCell,
+    hint::spin_loop,
+    sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering},
+};
+use eonix_hal_traits::mm::Memory;
+use eonix_mm::{
+    address::{Addr as _, PAddr, PRange, PhysAccess, VAddr, VRange},
+    page_table::{PageAttribute, PagingMode, PTE as _},
+    paging::{Page, PageAccess, PageAlloc, PAGE_SIZE, PFN},
+};
+use eonix_percpu::PercpuArea;
+
+use super::{
+    config::{self, mm::*},
+    fdt::get_num_harts,
+};
+
+use core::arch::naked_asm;
+
+#[unsafe(link_section = ".bootstack")]
+static mut BOOT_STACK: [u8; 4096 * 16] = [0; 4096 * 16];
+
+#[repr(C, align(4096))]
+struct BootPageTable([u64; PTES_PER_PAGE]);
+
+/// map 0x8000 0000 to itself and 0xffff ffff 8000 0000
+#[unsafe(link_section = ".bootdata")]
+static mut BOOT_PAGE_TABLE: BootPageTable = {
+    let mut arr: [u64; PTES_PER_PAGE] = [0; PTES_PER_PAGE];
+    arr[2] = (0x80000 << 10) | 0xcf;
+    arr[510] = (0x80000 << 10) | 0xcf;
+    BootPageTable(arr)
+};
+
+static AP_COUNT: AtomicUsize = AtomicUsize::new(0);
+static AP_STACK: AtomicUsize = AtomicUsize::new(0);
+static AP_SEM: AtomicBool = AtomicBool::new(false);
+
+unsafe extern "Rust" {
+    fn kernel_init();
+}
+
+/// bootstrap in rust
+#[unsafe(naked)]
+#[unsafe(no_mangle)]
+#[unsafe(link_section = ".text.entry")]
+unsafe extern "C" fn _start(hart_id: usize, dtb_addr: usize) -> ! {
+    naked_asm!(
+        "
+            la    sp, {boot_stack}
+            la    t0, {page_table}
+            srli  t0, t0, 12
+            li    t1, 8 << 60
+            or    t0, t0, t1
+            csrw  satp, t0
+            sfence.vma
+            li    t2, {virt_ram_offset}
+            or    sp, sp, t2
+            la    t3, riscv64_start
+            or    t3, t3, t2
+            jalr  t3                      // call riscv64_start
+        ",
+        boot_stack = sym BOOT_STACK,
+        page_table = sym BOOT_PAGE_TABLE,
+        virt_ram_offset = const KIMAGE_OFFSET,
+    )
+}
+
+/// TODO: 
+/// linker,现在VMA和LMA不对
+/// 设置中断
+/// 启动所有的cpu
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn riscv64_start(hart_id: usize, dtb_addr: usize) -> ! {
+    let real_allocator = RefCell::new(BasicPageAlloc::new());
+    let alloc = BasicPageAllocRef::new(&real_allocator);
+
+    for range in ArchMemory::free_ram() {
+        real_allocator.borrow_mut().add_range(range);
+    }
+
+    setup_kernel_page_table(&alloc);
+    unsafe {
+        init_dtb_and_fdt(dtb_addr)
+    };
+    enable_sse();
+    
+    let num_harts = get_num_harts();
+    config::smp::set_num_harts(num_harts);
+
+    setup_cpu(&alloc, hart_id);
+
+    // TODO: set up interrupt, smp
+    //ScopedAllocator::new(&mut [0; 1024])
+    //    .with_alloc(|mem_alloc| bootstrap_smp(mem_alloc, &real_allocator));
+
+    unsafe extern "Rust" {
+        fn _eonix_hal_main(_: BootStrapData) -> !;
+    }
+
+    let start = &raw mut BOOT_STACK as usize + KIMAGE_OFFSET;
+    let bootstrap_data = BootStrapData {
+        early_stack: PRange::new(
+            PAddr::from(start),
+            PAddr::from(start + 4096 * 16)),
+        allocator: Some(real_allocator),
+    };
+
+    unsafe {
+        _eonix_hal_main(bootstrap_data);
+    }
+}
+
+unsafe extern "C" {
+    fn BSS_LENGTH();
+    fn KIMAGE_PAGES();
+}
+
+/// TODO:
+/// 对kernel image添加更细的控制,或者不加也行
+pub fn setup_kernel_page_table(alloc: impl PageAlloc) {
+    let global_page_table = &GLOBAL_PAGE_TABLE;
+
+    let attr = PageAttribute::WRITE
+        | PageAttribute::READ
+        | PageAttribute::EXECUTE
+        | PageAttribute::GLOBAL
+        | PageAttribute::PRESENT;
+
+    // Map Physical memory 128Gb, add a 0xFFFF_FFC0_0000_0000 offset
+    // use 1 Gb size page
+    for (idx, pte) in global_page_table
+        .iter_kernel_levels(VRange::from(VAddr::from(PHYS_MAP_VIRT)).grow(MEMORY_SIZE), &PagingModeSv39::LEVELS[..=0])
+        .enumerate()
+    {
+        pte.set(PFN::from(idx * 0x40000), PageAttribute64::from(attr));
+    }
+
+    // Map 2 MB kernel image
+    for (idx, pte) in global_page_table
+        .iter_kernel(VRange::from(VAddr::from(KIMAGE_VIRT_BASE)).grow(KIMAGE_PAGES as usize * 0x1000))
+        .enumerate()
+    {
+        pte.set(PFN::from(idx + 0x80200), PageAttribute64::from(attr));
+    }
+
+    // Map kernel BSS
+    for pte in global_page_table.iter_kernel_in(
+        VRange::from(V_KERNEL_BSS_START).grow(BSS_LENGTH as usize),
+        ArchPagingMode::LEVELS,
+        &alloc,
+    ) {
+        let page = Page::alloc_in(&alloc);
+        pte.set(page.into_raw(), attr.into());
+    }
+
+    unsafe {
+        core::ptr::write_bytes(V_KERNEL_BSS_START.addr() as *mut (), 0, BSS_LENGTH as usize);
+    }
+
+    unsafe {
+        satp::set(
+            satp::Mode::Sv39,
+            0,
+            usize::from(PFN::from(global_page_table.addr())),
+        );
+    }
+    sfence_vma_all();
+}
+
+pub fn enable_sse() {
+    unsafe {
+        // FS (Floating-point Status) Initial (0b01)
+        sstatus::set_fs(FS::Initial);
+    }
+}
+
+/// set up tp register to percpu
+fn setup_cpu(alloc: impl PageAlloc, hart_id: usize) {
+    let mut percpu_area = PercpuArea::new(|layout| {
+        let page_count = layout.size().div_ceil(PAGE_SIZE);
+        let page = Page::alloc_at_least_in(page_count, alloc);
+
+        let ptr = ArchPhysAccess::get_ptr_for_page(&page).cast();
+        page.into_raw();
+
+        ptr
+    });
+
+    // set tp(x4) register
+    percpu_area.setup(|pointer| {
+        let percpu_base_addr = pointer.addr().get();
+        unsafe {
+            asm!(
+                "mv tp, {0}",
+                in(reg) percpu_base_addr,
+                options(nostack, preserves_flags)
+            );
+        }
+    });
+
+    let mut cpu = CPU::local();
+    unsafe {
+        cpu.as_mut().init(hart_id);
+    }
+    
+    percpu_area.register(cpu.cpuid());
+}
+
+/// TODO
+fn bootstrap_smp(alloc: impl Allocator, page_alloc: &RefCell<BasicPageAlloc>) {
+
+}