소스 검색

refactor(arch): refactor riscv64's bootstrap, already be tested

Heinz 8 달 전
부모
커밋
998febde0c
8개의 변경된 파일176개의 추가작업 그리고 75개의 파일을 삭제
  1. 13 4
      arch/src/riscv64/config.rs
  2. 0 12
      arch/src/riscv64/entry.S
  3. 67 0
      arch/src/riscv64/entry/mod.rs
  4. 69 44
      arch/src/riscv64/entry/page.rs
  5. 6 6
      arch/src/riscv64/kernel.ld
  6. 13 0
      arch/src/riscv64/memory.txt
  7. 6 7
      arch/src/riscv64/mm.rs
  8. 2 2
      arch/src/riscv64/mod.rs

+ 13 - 4
arch/src/riscv64/config.rs

@@ -1,12 +1,21 @@
 /// mm
 pub mod mm {
     pub const ROOT_PAGE_TABLE_PHYS_ADDR: usize = 0x8040_0000;
+    pub const PHYS_MAP_VIRT: usize = 0xffff_ffc0_0000_0000;
+    pub const KIMAGE_PHYS_BASE: usize = 0x8020_0000;
+    pub const KIMAGE_OFFSET: usize = 0xffff_ffff_0000_0000;
+    pub const MMIO_VIRT_BASE: usize = KIMAGE_OFFSET;
+    pub const KIMAGE_VIRT_BASE: usize = KIMAGE_OFFSET + KIMAGE_PHYS_BASE;
+    pub const PAGE_SIZE: usize = 1 << PAGE_SIZE_BITS;
+    pub const PAGE_SIZE_BITS: usize = 12;
+    // 127GB
+    pub const MEMORY_SIZE: usize = 0x1F_C000_0000;
+
+    pub const PTE_SIZE: usize = 8;
+    pub const PTES_PER_PAGE: usize = PAGE_SIZE / PTE_SIZE;
     pub const ROOT_PAGE_TABLE_PFN: usize = ROOT_PAGE_TABLE_PHYS_ADDR >> 12;
     pub const PAGE_TABLE_PHYS_END: usize = 0x8080_0000;
-    pub const PHYS_MAP_VIRT: usize = 0xFFFF_FF00_0000_0000;
-    pub const KIMAGE_PHYS_BASE: usize = 0x8020_0000;
-    pub const KIMAGE_VIRT_BASE: usize = 0xFFFF_FFFF_FFC0_0000;
-    pub const PAGE_SIZE: usize = 0x1000;
+
     #[derive(Clone, Copy)]
     pub enum PageSize {
         _4KbPage = 4096,

+ 0 - 12
arch/src/riscv64/entry.S

@@ -1,12 +0,0 @@
-.section .text.entry
-.globl _start
-_start:
-    la sp, boot_stack_top
-    call riscv64_start
-
-.section .bss.stack
-    .globl boot_stack_lower_bound
-boot_stack_lower_bound:
-    .space 4096 * 16
-    .globl boot_stack_top
-boot_stack_top:

+ 67 - 0
arch/src/riscv64/entry/mod.rs

@@ -0,0 +1,67 @@
+mod page;
+
+use page::setup_kernel_page_table;
+
+use super::{
+    config::{self, mm::*},
+    fdt::get_num_harts,
+};
+
+use core::arch::naked_asm;
+
+#[link_section = ".bss.stack"]
+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
+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)
+};
+
+extern "C" {
+    fn kernel_init();
+}
+
+/// bootstrap in rust
+#[naked]
+#[no_mangle]
+#[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不对
+/// kernel_init不知道要干什么
+#[no_mangle]
+pub unsafe extern "C" fn riscv64_start(hart_id: usize, dtb_addr: usize) -> ! {
+    setup_kernel_page_table();
+    let num_harts = get_num_harts(dtb_addr);
+    config::smp::set_num_harts(num_harts);
+    unsafe { kernel_init() };
+
+    unreachable!();
+}

+ 69 - 44
arch/src/riscv64/start.rs → arch/src/riscv64/entry/page.rs

@@ -1,24 +1,22 @@
-use super::{
-    config::{self, mm::*},
+use super::super::{
+    config::mm::*,
     mm::*,
-    fdt::get_num_harts,
 };
 
 use core::{
-    arch::global_asm, ptr::NonNull, sync::atomic::AtomicUsize
+    ptr::NonNull,
+    sync::atomic::AtomicUsize
 };
 use intrusive_list::{container_of, Link};
 use buddy_allocator::{BuddyAllocator, BuddyRawPage};
 use riscv::{asm::sfence_vma_all, register::satp};
 use eonix_mm::{
-    address::{Addr as _, PAddr, VAddr, VRange},
+    address::{Addr as _, AddrOps, PAddr, VAddr, VRange},
     page_table::{PageAttribute, PagingMode, RawAttribute, PTE as _},
     paging::{Page, PageAccess, PageAlloc, PageBlock, RawPage as RawPageTrait, PFN},
 };
 use spin::Mutex;
 
-global_asm!("start.S");
-
 static mut PAGES: [RawPage; 1024] = [const { RawPage::new() }; 1024];
 
 fn page(index: usize) -> &'static mut RawPage {
@@ -149,9 +147,57 @@ impl PageAlloc for BuddyPageAlloc {
     }
 }
 
-type PageTable<'a> = eonix_mm::page_table::PageTable<'a, PagingModeSv48, BuddyPageAlloc, DirectPageAccess>;
+type PageTable<'a> = eonix_mm::page_table::PageTable<'a, PagingModeSv39, BuddyPageAlloc, DirectPageAccess>;
+
+extern "C" {
+    fn _ekernel();
+}
+
+/// TODO:
+/// _ekernel现在还没有,需要在linker里加上
+/// 对kernel image添加更细的控制,或者不加也行
+fn map_area(page_table: &PageTable, attr: PageAttribute, range: VRange, phy_offest: usize, page_size: PageSize) {
+    let (pfn_size, levels) = match page_size {
+        PageSize::_4KbPage => (0x1, &PagingModeSv39::LEVELS[..=0]),
+        PageSize::_2MbPage => (0x200, &PagingModeSv39::LEVELS[..=1]),
+        PageSize::_1GbPage => (0x40000, &PagingModeSv39::LEVELS[..=2]),
+    };
+    for (idx, pte) in page_table
+        .iter_kernel_levels(range, levels)
+        .enumerate()
+    {
+        pte.set(PFN::from(idx * pfn_size + phy_offest), PageAttribute64::from_page_attr(attr));
+    }
+}
+
+/// Map physical memory after ekernel, about 0x8040 0000-0x20_7fff_fff about 128GB
+/// to add a 0xffff ffc0 0000 0000 offest
+/// first use 4KB page, then 2MB page, last 1GB page
+fn map_free_physical_memory(attr: PageAttribute, page_table: &PageTable) {
+    let ekernel = _ekernel as usize - KIMAGE_OFFSET;
+
+    let start = PAddr::from(ekernel).ceil_to(PageSize::_4KbPage as usize);
+    let end = PAddr::from(ekernel).ceil_to(PageSize::_2MbPage as usize);
+    let size_4kb = end - start;
+    let range = VRange::from(VAddr::from(PHYS_MAP_VIRT + start.addr())).grow(size_4kb);
+    let pfn_start = start.addr() >> PAGE_SIZE_BITS;
+    map_area(page_table, attr, range, pfn_start, PageSize::_4KbPage);
+
+    let start = end;
+    let end = start.ceil_to(PageSize::_1GbPage as usize);
+    let size_2mb = end - start;
+    let range = VRange::from(VAddr::from(PHYS_MAP_VIRT + start.addr())).grow(size_2mb);
+    let pfn_start = start.addr() >> PAGE_SIZE_BITS;
+    map_area(page_table, attr, range, pfn_start, PageSize::_2MbPage);
+
+    let start = end;
+    let size_1gb = MEMORY_SIZE;
+    let range = VRange::from(VAddr::from(PHYS_MAP_VIRT + start.addr())).grow(size_1gb);
+    let pfn_start = start.addr() >> PAGE_SIZE_BITS;
+    map_area(page_table, attr, range, pfn_start, PageSize::_1GbPage);
+}
 
-fn setup_kernel_page_table() {
+pub fn setup_kernel_page_table() {
     let attr = PageAttribute::WRITE
         | PageAttribute::READ
         | PageAttribute::EXECUTE
@@ -163,22 +209,15 @@ fn setup_kernel_page_table() {
     let root_table_page = Page::alloc_in(BuddyPageAlloc);
     let page_table = PageTable::new_in(&root_table_page, BuddyPageAlloc);
 
-    // Map 0x80200000-0x81200000 16MB identically, use 2MB page
-    for (idx, pte) in page_table
-        .iter_kernel_levels(VRange::from(VAddr::from(KIMAGE_PHYS_BASE)).grow(0x1000000), &PagingModeSv48::LEVELS[..=2])
-        .enumerate()
-    {
-        pte.set(PFN::from(idx * 0x200 + 0x80200), PageAttribute64::from_page_attr(attr));
-    }
-
-    // Map 0x0000_0000_0000_0000-0x0000_007F_FFFF_FFFF 512GB
-    // to 0xFFFF_FF00_0000_0000 to 0xFFFF_FF7F_FFFF_FFFF, use 1 GB page
-    for (idx, pte) in page_table
-        .iter_kernel_levels(VRange::from(VAddr::from(PHYS_MAP_VIRT)).grow(0x80_0000_0000), &PagingModeSv48::LEVELS[..=1])
-        .enumerate()
-    {
-        pte.set(PFN::from(idx * 0x40000), PageAttribute64::from_page_attr(attr));
-    }
+    // Map 0x00000000-0x7fffffff 2GB MMIO,
+    // to 0xffff ffff 0000 0000 to 0xffff ffff 7ffff ffff, use 1GB page
+    map_area(&page_table,
+        attr,
+        VRange::from(VAddr::from(MMIO_VIRT_BASE)).grow(0x2000_0000),
+        0,
+        PageSize::_1GbPage);
+    
+    map_free_physical_memory(attr, &page_table);
 
     // Map 2 MB kernel image
     for (idx, pte) in page_table
@@ -188,26 +227,12 @@ fn setup_kernel_page_table() {
         pte.set(PFN::from(idx + 0x80200), PageAttribute64::from_page_attr(attr));
     }
 
-
     unsafe {
-        satp::set(satp::Mode::Sv48, 0, PFN::from(page_table.addr()).into());
+        satp::set(
+            satp::Mode::Sv39,
+            0,
+            usize::from(PFN::from(page_table.addr())),
+        );
     }
     sfence_vma_all();
 }
-
-extern "C" {
-    fn kernel_init();
-}
-
-/// TODO: 
-/// linker,现在VMA和LMA不对
-/// 现在的地址空间可能要改一改,改回Sv39的,Sv48有点大了
-#[no_mangle]
-pub unsafe extern "C" fn riscv64_start(hart_id: usize, dtb_addr: usize) -> ! {
-    let num_harts = get_num_harts(dtb_addr);
-    config::smp::set_num_harts(num_harts);
-    setup_kernel_page_table();
-    unsafe { kernel_init() };
-
-    unreachable!();
-}

+ 6 - 6
arch/src/riscv64/kernel.ld

@@ -1,18 +1,18 @@
-OUTPUT_FORMAT(elf64-littleriscv)
+OUTPUT_FORMAT(riscv)
 ENTRY(_start)
 
+RAM = 0x80200000;
+
 MEMORY
 {
-    PHYMEM        (w)  : org = 0xffffff0000000000, len = 512 * 1024M
-    PARRAY        (w)  : org = 0xffffff8000000000, len = 128 * 1024M
-    KBSS          (w)  : org = 0xffffffffc0200000, len = 2M
-    KIMAGE        (wx) : org = 0xffffffffffc00000, len = 2M
+    KBSS          (w)  : org = 0xffffffff00200000, len = 2M
+    KIMAGE        (wx) : org = 0xffffffff80200000, len = 2M
     KPERCPU       (w)  : org = 0x0000000000000000, len = 128K
 }
 
 SECTIONS
 {
-    .text : AT(0x80200000)
+    .text : AT(RAM)
     {
         TEXT_START = .;
         *(.text.entry)

+ 13 - 0
arch/src/riscv64/memory.txt

@@ -0,0 +1,13 @@
+physical memory:
+
+0x0000 0000 - 0x8000 0000  2GB MMIO
+0x8000 0000 - 0x8020 0000  2MB SBI
+0x8020 0000 - 0x8040 0000  2MB kernel image (maybe)
+free memory after kernel image
+
+
+kernel virtual address space:
+
+0xffff ffc0 0000 0000 - 0xffff ffdf ffff ffff  128GB physical memory
+0xffff ffff 0000 0000 - 0xffff ffff 7fff ffff    2GB MMIO
+0xffff ffff 8020 0000 - 0xffff ffff 803f ffff    2MB kernel image

+ 6 - 7
arch/src/riscv64/mm.rs

@@ -37,9 +37,9 @@ pub struct PTE64(pub u64);
 #[derive(Clone, Copy)]
 pub struct PageAttribute64(u64);
 
-pub struct RawPageTableSv48<'a>(NonNull<PTE64>, PhantomData<&'a ()>);
+pub struct RawPageTableSv39<'a>(NonNull<PTE64>, PhantomData<&'a ()>);
 
-pub struct PagingModeSv48;
+pub struct PagingModeSv39;
 
 impl PTE for PTE64 {
     type Attr = PageAttribute64;
@@ -55,11 +55,10 @@ impl PTE for PTE64 {
     }
 }
 
-impl PagingMode for PagingModeSv48 {
+impl PagingMode for PagingModeSv39 {
     type Entry = PTE64;
-    type RawTable<'a> = RawPageTableSv48<'a>;
+    type RawTable<'a> = RawPageTableSv39<'a>;
     const LEVELS: &'static [PageTableLevel] = &[
-        PageTableLevel::new(39, 9),
         PageTableLevel::new(30, 9),
         PageTableLevel::new(21, 9),
         PageTableLevel::new(12, 9),
@@ -67,7 +66,7 @@ impl PagingMode for PagingModeSv48 {
     const KERNEL_ROOT_TABLE_PFN: PFN = PAGE_TABLE_BASE;
 }
 
-impl<'a> RawPageTable<'a> for RawPageTableSv48<'a> {
+impl<'a> RawPageTable<'a> for RawPageTableSv39<'a> {
     type Entry = PTE64;
 
     fn index(&self, index: u16) -> &'a Self::Entry {
@@ -205,7 +204,7 @@ impl RawAttribute for PageAttribute64 {
     }
 }
 
-pub type DefaultPagingMode = PagingModeSv48;
+pub type DefaultPagingMode = PagingModeSv39;
 
 pub fn setup_kernel_satp() {
     unsafe {

+ 2 - 2
arch/src/riscv64/mod.rs

@@ -1,5 +1,5 @@
 mod mm;
-mod start;
+mod entry;
 mod context;
 mod console;
 mod io;
@@ -10,7 +10,7 @@ mod interrupt;
 mod fdt;
 
 pub use self::mm::*;
-pub use self::start::*;
+pub use self::entry::*;
 pub use self::context::*;
 pub use self::console::*;
 pub use self::io::*;