cpu.rs 2.7 KB

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