bootstrap.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. use super::{
  2. config::{self, mm::*},
  3. console::write_str,
  4. trap::TRAP_SCRATCH,
  5. };
  6. use crate::{
  7. arch::{
  8. cpu::CPU,
  9. fdt::{init_dtb_and_fdt, FdtExt},
  10. mm::{ArchPhysAccess, FreeRam, PageAttribute64, GLOBAL_PAGE_TABLE},
  11. interrupt::enable_timer_interrupt,
  12. },
  13. bootstrap::BootStrapData,
  14. mm::{ArchMemory, ArchPagingMode, BasicPageAlloc, BasicPageAllocRef, ScopedAllocator},
  15. };
  16. use core::arch::naked_asm;
  17. use core::{
  18. alloc::Allocator,
  19. arch::asm,
  20. cell::RefCell,
  21. sync::atomic::{AtomicBool, AtomicUsize},
  22. };
  23. use eonix_hal_traits::mm::Memory;
  24. use eonix_mm::{
  25. address::{Addr as _, PAddr, PRange, PhysAccess, VAddr, VRange},
  26. page_table::{PageAttribute, PagingMode, PTE as _},
  27. paging::{Page, PageAccess, PageAlloc, PAGE_SIZE, PFN},
  28. };
  29. use eonix_percpu::PercpuArea;
  30. use fdt::Fdt;
  31. use riscv::{asm::sfence_vma_all, register::satp};
  32. use sbi::legacy::console_putchar;
  33. #[unsafe(link_section = ".bootstrap.stack")]
  34. static BOOT_STACK: [u8; 4096 * 16] = [0; 4096 * 16];
  35. static BOOT_STACK_START: &'static [u8; 4096 * 16] = &BOOT_STACK;
  36. #[repr(C, align(4096))]
  37. struct PageTable([u64; PTES_PER_PAGE]);
  38. /// map 0x8000 0000 to itself and 0xffff ffff 8000 0000
  39. #[unsafe(link_section = ".bootstrap.page_table.1")]
  40. static BOOT_PAGE_TABLE: PageTable = {
  41. let mut arr: [u64; PTES_PER_PAGE] = [0; PTES_PER_PAGE];
  42. arr[0] = 0 | 0x2f;
  43. arr[510] = 0 | 0x2f;
  44. arr[511] = (0x80202 << 10) | 0x21;
  45. PageTable(arr)
  46. };
  47. #[unsafe(link_section = ".bootstrap.page_table.2")]
  48. #[used]
  49. static PT1: PageTable = {
  50. let mut arr: [u64; PTES_PER_PAGE] = [0; PTES_PER_PAGE];
  51. arr[510] = (0x80000 << 10) | 0x2f;
  52. PageTable(arr)
  53. };
  54. /// bootstrap in rust
  55. #[unsafe(naked)]
  56. #[unsafe(no_mangle)]
  57. #[unsafe(link_section = ".bootstrap.entry")]
  58. unsafe extern "C" fn _start(hart_id: usize, dtb_addr: usize) -> ! {
  59. naked_asm!(
  60. "
  61. ld sp, 2f
  62. li t0, 0x10000
  63. add sp, sp, t0
  64. ld t0, 3f
  65. srli t0, t0, 12
  66. li t1, 9 << 60
  67. or t0, t0, t1
  68. csrw satp, t0
  69. sfence.vma
  70. ld t0, 4f
  71. jalr t0 // call riscv64_start
  72. .pushsection .bootstrap.data, \"aw\", @progbits
  73. 2:
  74. .8byte {boot_stack}
  75. 3:
  76. .8byte {page_table}
  77. 4:
  78. .8byte {riscv64_start}
  79. .popsection
  80. ",
  81. boot_stack = sym BOOT_STACK,
  82. page_table = sym BOOT_PAGE_TABLE,
  83. riscv64_start = sym riscv64_start,
  84. )
  85. }
  86. /// TODO:
  87. /// 启动所有的cpu
  88. pub unsafe extern "C" fn riscv64_start(hart_id: usize, dtb_addr: PAddr) -> ! {
  89. let fdt = Fdt::from_ptr(ArchPhysAccess::as_ptr(dtb_addr).as_ptr())
  90. .expect("Failed to parse DTB from static memory.");
  91. let real_allocator = RefCell::new(BasicPageAlloc::new());
  92. let alloc = BasicPageAllocRef::new(&real_allocator);
  93. for range in fdt.present_ram().free_ram() {
  94. real_allocator.borrow_mut().add_range(range);
  95. }
  96. setup_kernel_page_table(&alloc);
  97. unsafe {
  98. init_dtb_and_fdt(dtb_addr);
  99. }
  100. setup_cpu(&alloc, hart_id);
  101. // TODO: set up interrupt, smp
  102. ScopedAllocator::new(&mut [0; 1024])
  103. .with_alloc(|mem_alloc| bootstrap_smp(mem_alloc, &real_allocator));
  104. unsafe extern "Rust" {
  105. fn _eonix_hal_main(_: BootStrapData) -> !;
  106. }
  107. let start = unsafe {
  108. ((&BOOT_STACK_START) as *const &'static [u8; 4096 * 16]).read_volatile() as *const _
  109. as usize
  110. };
  111. let bootstrap_data = BootStrapData {
  112. early_stack: PRange::new(PAddr::from(start), PAddr::from(start + 4096 * 16)),
  113. allocator: Some(real_allocator),
  114. };
  115. unsafe {
  116. _eonix_hal_main(bootstrap_data);
  117. }
  118. }
  119. unsafe extern "C" {
  120. fn BSS_LENGTH();
  121. fn KIMAGE_PAGES();
  122. }
  123. /// TODO:
  124. /// 对kernel image添加更细的控制,或者不加也行
  125. fn setup_kernel_page_table(alloc: impl PageAlloc) {
  126. let global_page_table = &GLOBAL_PAGE_TABLE;
  127. let attr = PageAttribute::WRITE
  128. | PageAttribute::READ
  129. | PageAttribute::EXECUTE
  130. | PageAttribute::GLOBAL
  131. | PageAttribute::PRESENT;
  132. const KERNEL_BSS_START: VAddr = VAddr::from(0xffffffff40000000);
  133. // Map kernel BSS
  134. for pte in global_page_table.iter_kernel_in(
  135. VRange::from(KERNEL_BSS_START).grow(BSS_LENGTH as usize),
  136. ArchPagingMode::LEVELS,
  137. &alloc,
  138. ) {
  139. let page = Page::alloc_in(&alloc);
  140. let attr = {
  141. let mut attr = attr.clone();
  142. attr.remove(PageAttribute::EXECUTE);
  143. attr
  144. };
  145. pte.set(page.into_raw(), attr.into());
  146. }
  147. sfence_vma_all();
  148. unsafe {
  149. core::ptr::write_bytes(KERNEL_BSS_START.addr() as *mut (), 0, BSS_LENGTH as usize);
  150. }
  151. unsafe {
  152. satp::set(
  153. satp::Mode::Sv48,
  154. 0,
  155. usize::from(PFN::from(global_page_table.addr())),
  156. );
  157. }
  158. sfence_vma_all();
  159. }
  160. /// set up tp register to percpu
  161. fn setup_cpu(alloc: impl PageAlloc, hart_id: usize) {
  162. let mut percpu_area = PercpuArea::new(|layout| {
  163. let page_count = layout.size().div_ceil(PAGE_SIZE);
  164. let page = Page::alloc_at_least_in(page_count, alloc);
  165. let ptr = ArchPhysAccess::get_ptr_for_page(&page).cast();
  166. page.into_raw();
  167. ptr
  168. });
  169. // set tp(x4) register
  170. percpu_area.setup(|pointer| {
  171. let percpu_base_addr = pointer.addr().get();
  172. unsafe {
  173. asm!(
  174. "mv tp, {0}",
  175. in(reg) percpu_base_addr,
  176. options(nostack, preserves_flags)
  177. );
  178. }
  179. });
  180. let mut cpu = CPU::local();
  181. unsafe {
  182. cpu.as_mut().init(hart_id);
  183. }
  184. percpu_area.register(cpu.cpuid());
  185. unsafe {
  186. // SAFETY: Interrupts are disabled.
  187. TRAP_SCRATCH
  188. .as_mut()
  189. .set_kernel_tp(PercpuArea::get_for(cpu.cpuid()).unwrap().cast());
  190. }
  191. // set current hart's mtimecmp register
  192. enable_timer_interrupt();
  193. }
  194. /// TODO
  195. fn bootstrap_smp(alloc: impl Allocator, page_alloc: &RefCell<BasicPageAlloc>) {}
  196. pub fn early_console_write(s: &str) {
  197. write_str(s);
  198. }
  199. pub fn early_console_putchar(ch: u8) {
  200. console_putchar(ch);
  201. }