cpu.rs 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. use super::mem::{AsMemoryBlock, GlobalPageAlloc};
  2. use arch::{PercpuArea, CPU};
  3. use core::{alloc::Layout, pin::Pin, ptr::NonNull};
  4. use eonix_hal::mm::PAGE_SIZE;
  5. use eonix_mm::paging::Page;
  6. use eonix_sync::LazyLock;
  7. #[eonix_percpu::define_percpu]
  8. static CPU: LazyLock<CPU> =
  9. LazyLock::new(|| CPU::new(unsafe { eonix_hal::trap::TRAP_STUBS_START }));
  10. /// # Safety
  11. /// This function is unsafe because it needs preemption to be disabled.
  12. pub unsafe fn local_cpu() -> Pin<&'static mut CPU> {
  13. // SAFETY: `CPU_STATUS` is global static and initialized only once.
  14. unsafe { Pin::new_unchecked(CPU.as_mut().get_mut()) }
  15. }
  16. pub fn percpu_allocate(layout: Layout) -> NonNull<u8> {
  17. // TODO: Use page size defined in `arch`.
  18. let page_count = layout.size().div_ceil(PAGE_SIZE);
  19. let page = Page::alloc_at_least_in(page_count, GlobalPageAlloc::early_alloc());
  20. let page_data = page.as_memblk().as_byte_ptr();
  21. core::mem::forget(page);
  22. page_data
  23. }
  24. pub fn init_localcpu() {
  25. let percpu_area = PercpuArea::new(percpu_allocate);
  26. // Preemption count is percpu. So we need to initialize percpu area first.
  27. percpu_area.setup();
  28. eonix_preempt::disable();
  29. // SAFETY: Preemption is disabled.
  30. let mut cpu = unsafe { local_cpu() };
  31. unsafe {
  32. cpu.as_mut().init();
  33. }
  34. percpu_area.register(cpu.cpuid());
  35. eonix_preempt::enable();
  36. }