cpu.rs 1.3 KB

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