cpu.rs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. use super::{
  2. interrupt::InterruptControl,
  3. trap::{setup_trap, TRAP_SCRATCH},
  4. };
  5. use crate::arch::fdt::{FdtExt, FDT};
  6. use core::{arch::asm, pin::Pin, ptr::NonNull};
  7. use eonix_preempt::PreemptGuard;
  8. use eonix_sync_base::LazyLock;
  9. use riscv::register::{
  10. medeleg::{self, Medeleg},
  11. mhartid, sscratch, sstatus,
  12. };
  13. use sbi::PhysicalAddress;
  14. #[eonix_percpu::define_percpu]
  15. pub static CPUID: usize = 0;
  16. #[eonix_percpu::define_percpu]
  17. static LOCAL_CPU: LazyLock<CPU> = LazyLock::new(|| CPU::new(CPUID.get()));
  18. #[derive(Debug, Clone)]
  19. pub enum UserTLS {
  20. Base(u64),
  21. }
  22. /// RISC-V Hart
  23. pub struct CPU {
  24. pub(crate) interrupt: InterruptControl,
  25. }
  26. impl UserTLS {
  27. pub fn new(base: u64) -> Self {
  28. Self::Base(base)
  29. }
  30. }
  31. impl CPU {
  32. fn new(cpuid: usize) -> Self {
  33. Self {
  34. interrupt: InterruptControl::new(cpuid),
  35. }
  36. }
  37. /// Load CPU specific configurations for the current Hart.
  38. ///
  39. /// # Safety
  40. /// This function performs low-level hardware initialization and should
  41. /// only be called once per Hart during its boot sequence.
  42. pub unsafe fn init(mut self: Pin<&mut Self>) {
  43. let me = self.as_mut().get_unchecked_mut();
  44. setup_trap();
  45. let interrupt = self.map_unchecked_mut(|me| &mut me.interrupt);
  46. interrupt.init();
  47. sstatus::set_sum();
  48. sscratch::write(TRAP_SCRATCH.as_ptr() as usize);
  49. }
  50. /// Boot all other hart.
  51. pub unsafe fn bootstrap_cpus(&self) {
  52. let total_harts = FDT.hart_count();
  53. for i in (0..total_harts).filter(|&i| i != self.cpuid()) {
  54. sbi::hsm::hart_start(i, PhysicalAddress::new(0x8020_0078), 0)
  55. .expect("Failed to start secondary hart via SBI");
  56. }
  57. }
  58. pub unsafe fn load_interrupt_stack(self: Pin<&mut Self>, sp: u64) {
  59. TRAP_SCRATCH
  60. .as_mut()
  61. .set_trap_context(NonNull::new(sp as *mut _).unwrap());
  62. }
  63. pub fn set_tls32(self: Pin<&mut Self>, _user_tls: &UserTLS) {
  64. // nothing
  65. }
  66. pub fn local() -> PreemptGuard<Pin<&'static mut Self>> {
  67. unsafe {
  68. // SAFETY: We pass the reference into a `PreemptGuard`, which ensures
  69. // that preemption is disabled.
  70. PreemptGuard::new(Pin::new_unchecked(LOCAL_CPU.as_mut().get_mut()))
  71. }
  72. }
  73. pub fn cpuid(&self) -> usize {
  74. CPUID.get()
  75. }
  76. }
  77. #[inline(always)]
  78. pub fn halt() {
  79. unsafe {
  80. asm!("wfi", options(nomem, nostack, preserves_flags));
  81. }
  82. }