cpu.rs 2.7 KB

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