context.rs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. use core::arch::naked_asm;
  2. use eonix_hal_traits::context::RawTaskContext;
  3. #[repr(C)]
  4. #[derive(Debug)]
  5. pub struct TaskContext {
  6. sx: [u64; 9],
  7. sp: u64,
  8. ra: u64,
  9. fp: u64,
  10. crmd: usize,
  11. }
  12. impl RawTaskContext for TaskContext {
  13. fn new() -> Self {
  14. Self::new()
  15. }
  16. fn set_program_counter(&mut self, pc: usize) {
  17. self.ra = pc as u64;
  18. }
  19. fn set_stack_pointer(&mut self, sp: usize) {
  20. self.sp = sp as u64;
  21. }
  22. fn is_interrupt_enabled(&self) -> bool {
  23. self.crmd & (1 << 2) != 0
  24. }
  25. fn set_interrupt_enabled(&mut self, is_enabled: bool) {
  26. if is_enabled {
  27. self.crmd = self.crmd | (1 << 2);
  28. } else {
  29. self.crmd = self.crmd & !(1 << 2);
  30. }
  31. }
  32. fn call(&mut self, func: unsafe extern "C" fn(usize) -> !, arg: usize) {
  33. self.sx[0] = func as u64;
  34. self.sx[1] = arg as u64;
  35. self.set_program_counter(Self::do_call as usize);
  36. }
  37. #[unsafe(naked)]
  38. unsafe extern "C" fn switch(from: &mut Self, to: &mut Self) {
  39. // Input arguments `from` and `to` will be in `a0` (x10) and `a1` (x11).
  40. naked_asm!(
  41. // Save current task's callee-saved registers to `from` context
  42. "st.d $s0, $a0, 0",
  43. "st.d $s1, $a0, 8",
  44. "st.d $s2, $a0, 16",
  45. "st.d $s3, $a0, 24",
  46. "st.d $s4, $a0, 32",
  47. "st.d $s5, $a0, 40",
  48. "st.d $s6, $a0, 48",
  49. "st.d $s7, $a0, 56",
  50. "st.d $s8, $a0, 64",
  51. "st.d $sp, $a0, 72",
  52. "st.d $ra, $a0, 80",
  53. "st.d $fp, $a0, 88",
  54. "csrrd $t0, 0", // CRMD
  55. "st.d $t0, $a0, 96",
  56. "",
  57. "ld.d $s0, $a1, 0",
  58. "ld.d $s1, $a1, 8",
  59. "ld.d $s2, $a1, 16",
  60. "ld.d $s3, $a1, 24",
  61. "ld.d $s4, $a1, 32",
  62. "ld.d $s5, $a1, 40",
  63. "ld.d $s6, $a1, 48",
  64. "ld.d $s7, $a1, 56",
  65. "ld.d $s8, $a1, 64",
  66. "ld.d $sp, $a1, 72",
  67. "ld.d $ra, $a1, 80",
  68. "ld.d $fp, $a1, 88",
  69. "ld.d $t0, $a1, 96",
  70. "csrwr $t0, 0", // CRMD
  71. "ret",
  72. );
  73. }
  74. }
  75. impl TaskContext {
  76. pub const fn new() -> Self {
  77. Self {
  78. sx: [0; 9],
  79. sp: 0,
  80. ra: 0,
  81. fp: 0,
  82. crmd: 1 << 4, // PG = 1
  83. }
  84. }
  85. #[unsafe(naked)]
  86. /// Maximum of 5 arguments supported.
  87. unsafe extern "C" fn do_call() -> ! {
  88. naked_asm!(
  89. "move $a0, $s1", // Args
  90. "move $a1, $s2",
  91. "move $a2, $s3",
  92. "move $a3, $s4",
  93. "move $a4, $s5",
  94. "move $fp, $zero", // Set frame pointer to 0.
  95. "move $ra, $zero",
  96. "jirl $zero, $s0, 0",
  97. );
  98. }
  99. }