bootstrap.rs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. use super::cpu::CPUID;
  2. use super::cpu::CPU_COUNT;
  3. use crate::{
  4. arch::{
  5. cpu::CPU,
  6. mm::{ArchPhysAccess, PageAttribute64, GLOBAL_PAGE_TABLE},
  7. trap::CSR_KERNEL_TP,
  8. },
  9. bootstrap::BootStrapData,
  10. mm::{
  11. flush_tlb_all, ArchMemory, ArchPagingMode, BasicPageAlloc, BasicPageAllocRef,
  12. ScopedAllocator,
  13. },
  14. };
  15. use core::arch::naked_asm;
  16. use core::{
  17. alloc::Allocator,
  18. arch::asm,
  19. cell::RefCell,
  20. sync::atomic::{AtomicBool, AtomicUsize, Ordering},
  21. };
  22. use eonix_hal_traits::mm::Memory;
  23. use eonix_mm::{
  24. address::{Addr as _, PAddr, PRange, PhysAccess, VAddr, VRange},
  25. page_table::{PageAttribute, PagingMode, PTE as _},
  26. paging::{Page, PageAccess, PageAlloc, PAGE_SIZE, PFN},
  27. };
  28. use eonix_percpu::PercpuArea;
  29. use loongArch64::register::ecfg;
  30. use loongArch64::register::ecfg::LineBasedInterrupt;
  31. use loongArch64::register::tcfg;
  32. use loongArch64::register::{euen, pgdl};
  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; 512]);
  38. /// map 0x8000_0000 to 0x8000_0000 and 0xffff_ffff_8000_0000
  39. #[unsafe(link_section = ".bootstrap.page_table.1")]
  40. static BOOT_PAGE_TABLE: PageTable = {
  41. let mut arr = [0; 512];
  42. arr[0] = 0 | 0x11d3; // G | W | P | H | Cached | D | V
  43. arr[510] = 0 | 0x11d3; // G | W | P | H | Cached | D | V
  44. arr[511] = 0x8000_2000 | (1 << 60); // PT1, PT
  45. PageTable(arr)
  46. };
  47. #[unsafe(link_section = ".bootstrap.page_table.2")]
  48. #[used]
  49. static PT1: PageTable = {
  50. let mut arr = [0; 512];
  51. arr[510] = 0x8000_0000 | 0x11d3; // G | W | P | H | Cached | D | V
  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() -> ! {
  59. naked_asm!(
  60. "
  61. li.d $t0, 0xc
  62. csrwr $t0, {CSR_STLB_PAGE_SIZE}
  63. li.d $t0, {PWCL}
  64. csrwr $t0, {CSR_PWCL}
  65. li.d $t0, {PWCH}
  66. csrwr $t0, {CSR_PWCH}
  67. la.global $t0, {tlb_refill_entry}
  68. csrwr $t0, {CSR_TLB_REFILL_ENTRY}
  69. la.global $t0, {page_table}
  70. move $t1, $t0
  71. csrwr $t0, {CSR_PGDL}
  72. csrwr $t1, {CSR_PGDH}
  73. dbar 0x0
  74. invtlb 0x0, $zero, $zero
  75. csrrd $t0, {CSR_CRMD}
  76. li.d $t1, ~0x18
  77. and $t0, $t0, $t1
  78. ori $t0, $t0, 0x10
  79. csrwr $t0, {CSR_CRMD}
  80. la.global $sp, {boot_stack}
  81. li.d $t0, 0xffffff0000000000
  82. or $sp, $sp, $t0
  83. li.d $t0, {BOOT_STACK_SIZE}
  84. add.d $sp, $sp, $t0
  85. csrrd $a0, {CSR_CPUID}
  86. move $ra, $zero
  87. la.global $t0, {riscv64_start}
  88. jirl $zero, $t0, 0
  89. ",
  90. boot_stack = sym BOOT_STACK,
  91. BOOT_STACK_SIZE = const size_of_val(&BOOT_STACK),
  92. CSR_CRMD = const 0x00,
  93. CSR_PGDL = const 0x19,
  94. CSR_PGDH = const 0x1a,
  95. CSR_PWCL = const 0x1c,
  96. CSR_PWCH = const 0x1d,
  97. CSR_STLB_PAGE_SIZE = const 0x1e,
  98. CSR_CPUID = const 0x20,
  99. CSR_TLB_REFILL_ENTRY = const 0x88,
  100. PWCL = const (12 << 0) | (9 << 5) | (21 << 10) | (9 << 15) | (30 << 20) | (9 << 25) | (0 << 30),
  101. PWCH = const (39 << 0) | (9 << 6),
  102. tlb_refill_entry = sym tlb_refill_entry,
  103. page_table = sym BOOT_PAGE_TABLE,
  104. riscv64_start = sym riscv64_start,
  105. )
  106. }
  107. #[unsafe(naked)]
  108. #[unsafe(link_section = ".bootstrap.tlb_fill_entry")]
  109. unsafe extern "C" fn tlb_refill_entry() {
  110. naked_asm!(
  111. "csrwr $t0, {CSR_TLBRSAVE}",
  112. "csrrd $t0, {CSR_PGD}",
  113. "lddir $t0, $t0, 3",
  114. "lddir $t0, $t0, 2",
  115. "lddir $t0, $t0, 1",
  116. "ldpte $t0, 0",
  117. "ldpte $t0, 1",
  118. "tlbfill",
  119. "csrrd $t0, {CSR_TLBRSAVE}",
  120. "ertn",
  121. CSR_TLBRSAVE = const 0x8b,
  122. CSR_PGD = const 0x1b,
  123. )
  124. }
  125. /// TODO:
  126. /// 启动所有的cpu
  127. pub unsafe extern "C" fn riscv64_start(hart_id: usize) -> ! {
  128. pgdl::set_base(0xffff_ffff_ffff_0000);
  129. flush_tlb_all();
  130. let real_allocator = RefCell::new(BasicPageAlloc::new());
  131. let alloc = BasicPageAllocRef::new(&real_allocator);
  132. for range in ArchMemory::free_ram() {
  133. real_allocator.borrow_mut().add_range(range);
  134. }
  135. setup_kernel_page_table(&alloc);
  136. setup_cpu(&alloc, hart_id);
  137. // TODO: set up interrupt, smp
  138. ScopedAllocator::new(&mut [0; 1024])
  139. .with_alloc(|mem_alloc| bootstrap_smp(mem_alloc, &real_allocator));
  140. unsafe extern "Rust" {
  141. fn _eonix_hal_main(_: BootStrapData) -> !;
  142. }
  143. let start = unsafe {
  144. ((&BOOT_STACK_START) as *const &'static [u8; 4096 * 16]).read_volatile() as *const _
  145. as usize
  146. };
  147. let bootstrap_data = BootStrapData {
  148. early_stack: PRange::new(
  149. PAddr::from(start),
  150. PAddr::from(start + size_of_val(&BOOT_STACK)),
  151. ),
  152. allocator: Some(real_allocator),
  153. };
  154. unsafe {
  155. _eonix_hal_main(bootstrap_data);
  156. }
  157. }
  158. unsafe extern "C" {
  159. fn BSS_LENGTH();
  160. fn KIMAGE_PAGES();
  161. }
  162. fn setup_kernel_page_table(alloc: impl PageAlloc) {
  163. let global_page_table = &GLOBAL_PAGE_TABLE;
  164. let attr = PageAttribute::WRITE
  165. | PageAttribute::READ
  166. | PageAttribute::EXECUTE
  167. | PageAttribute::GLOBAL
  168. | PageAttribute::PRESENT
  169. | PageAttribute::ACCESSED
  170. | PageAttribute::DIRTY;
  171. const KERNEL_BSS_START: VAddr = VAddr::from(0xffffffff40000000);
  172. // Map kernel BSS
  173. for pte in global_page_table.iter_kernel_in(
  174. VRange::from(KERNEL_BSS_START).grow(BSS_LENGTH as usize),
  175. ArchPagingMode::LEVELS,
  176. &alloc,
  177. ) {
  178. let page = Page::alloc_in(&alloc);
  179. let attr = {
  180. let mut attr = attr.clone();
  181. attr.remove(PageAttribute::EXECUTE);
  182. attr
  183. };
  184. pte.set(page.into_raw(), attr.into());
  185. }
  186. flush_tlb_all();
  187. unsafe {
  188. core::ptr::write_bytes(KERNEL_BSS_START.addr() as *mut (), 0, BSS_LENGTH as usize);
  189. }
  190. }
  191. /// set up tp register to percpu
  192. fn setup_cpu(alloc: impl PageAlloc, hart_id: usize) {
  193. // enable FPU
  194. euen::set_fpe(true);
  195. euen::set_sxe(true);
  196. CPU_COUNT.fetch_add(1, Ordering::Relaxed);
  197. let mut percpu_area = PercpuArea::new(|layout| {
  198. let page_count = layout.size().div_ceil(PAGE_SIZE);
  199. let page = Page::alloc_at_least_in(page_count, alloc);
  200. let ptr = ArchPhysAccess::get_ptr_for_page(&page).cast();
  201. page.into_raw();
  202. ptr
  203. });
  204. // set tp(x4) register
  205. percpu_area.setup(|pointer| {
  206. let percpu_base_addr = pointer.addr().get();
  207. unsafe {
  208. asm!(
  209. "move $tp, {0}",
  210. in(reg) percpu_base_addr,
  211. options(nostack, preserves_flags)
  212. );
  213. }
  214. });
  215. CPUID.set(hart_id);
  216. let mut cpu = CPU::local();
  217. unsafe {
  218. cpu.as_mut().init();
  219. }
  220. percpu_area.register(cpu.cpuid());
  221. unsafe {
  222. asm!(
  223. "csrwr {tp}, {CSR_KERNEL_TP}",
  224. tp = inout(reg) PercpuArea::get_for(cpu.cpuid()).unwrap().as_ptr() => _,
  225. CSR_KERNEL_TP = const CSR_KERNEL_TP,
  226. )
  227. }
  228. let timer_frequency = loongArch64::time::get_timer_freq();
  229. // 1ms periodic timer.
  230. tcfg::set_init_val(timer_frequency / 1_000);
  231. tcfg::set_periodic(true);
  232. tcfg::set_en(true);
  233. ecfg::set_lie(LineBasedInterrupt::all());
  234. }
  235. /// TODO
  236. fn bootstrap_smp(alloc: impl Allocator, page_alloc: &RefCell<BasicPageAlloc>) {}
  237. pub fn shutdown() -> ! {
  238. let ged_addr = PAddr::from(0x100E001C);
  239. unsafe {
  240. let ged_ptr = ArchPhysAccess::as_ptr::<u8>(ged_addr);
  241. ged_ptr.write_volatile(0x34);
  242. loop {}
  243. }
  244. }