context.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. use core::arch::naked_asm;
  2. /// Necessary hardware states of task for context switch
  3. #[repr(C)]
  4. #[derive(Debug, Default)]
  5. pub struct TaskContext {
  6. r12: u64,
  7. r13: u64,
  8. r14: u64,
  9. r15: u64,
  10. rbx: u64,
  11. rbp: u64,
  12. rsp: u64,
  13. rip: u64, // Should we save rip here?
  14. rflags: u64, // Should we save rflags here?
  15. }
  16. impl TaskContext {
  17. /// Create a new task context with the given entry point and stack pointer.
  18. /// The entry point is the function to be called when the task is scheduled.
  19. /// The stack pointer is the address of the top of the stack.
  20. /// The stack pointer should be aligned to 16 bytes.
  21. pub const fn new() -> Self {
  22. Self {
  23. r12: 0,
  24. r13: 0,
  25. r14: 0,
  26. r15: 0,
  27. rbx: 0,
  28. rbp: 0,
  29. rsp: 0,
  30. rip: 0,
  31. rflags: 0x200, // IF = 1 by default.
  32. }
  33. }
  34. pub fn ip(&mut self, ip: usize) {
  35. self.rip = ip as u64;
  36. }
  37. pub fn sp(&mut self, sp: usize) {
  38. self.rsp = sp as u64;
  39. }
  40. pub fn call1(&mut self, func: unsafe extern "C" fn(usize) -> !, arg: [usize; 1]) {
  41. self.ip(Self::do_call as _);
  42. self.rbp = func as _;
  43. self.r12 = arg[0] as _;
  44. }
  45. pub fn call2(&mut self, func: unsafe extern "C" fn(usize, usize) -> !, arg: [usize; 2]) {
  46. self.ip(Self::do_call as _);
  47. self.rbp = func as _;
  48. (self.r12, self.r13) = (arg[0] as _, arg[1] as _);
  49. }
  50. pub fn call3(&mut self, func: unsafe extern "C" fn(usize, usize, usize) -> !, arg: [usize; 3]) {
  51. self.ip(Self::do_call as _);
  52. self.rbp = func as _;
  53. (self.r12, self.r13, self.r14) = (arg[0] as _, arg[1] as _, arg[2] as _);
  54. }
  55. pub fn call4(
  56. &mut self,
  57. func: unsafe extern "C" fn(usize, usize, usize, usize) -> !,
  58. arg: [usize; 4],
  59. ) {
  60. self.ip(Self::do_call as _);
  61. self.rbp = func as _;
  62. (self.r12, self.r13, self.r14, self.r15) =
  63. (arg[0] as _, arg[1] as _, arg[2] as _, arg[3] as _);
  64. }
  65. pub fn call5(
  66. &mut self,
  67. func: unsafe extern "C" fn(usize, usize, usize, usize, usize) -> !,
  68. arg: [usize; 5],
  69. ) {
  70. self.ip(Self::do_call as _);
  71. self.rbp = func as _;
  72. (self.r12, self.r13, self.r14, self.r15, self.rbx) = (
  73. arg[0] as _,
  74. arg[1] as _,
  75. arg[2] as _,
  76. arg[3] as _,
  77. arg[4] as _,
  78. );
  79. }
  80. pub fn interrupt(&mut self, is_enabled: bool) {
  81. if is_enabled {
  82. self.rflags |= 0x200; // IF = 1
  83. } else {
  84. self.rflags &= !0x200; // IF = 0
  85. }
  86. }
  87. #[naked]
  88. pub unsafe extern "C" fn switch(from: &mut Self, to: &mut Self) {
  89. naked_asm!(
  90. "pop %rax",
  91. "pushf",
  92. "pop %rcx",
  93. "mov %r12, (%rdi)",
  94. "mov %r13, 8(%rdi)",
  95. "mov %r14, 16(%rdi)",
  96. "mov %r15, 24(%rdi)",
  97. "mov %rbx, 32(%rdi)",
  98. "mov %rbp, 40(%rdi)",
  99. "mov %rsp, 48(%rdi)",
  100. "mov %rax, 56(%rdi)",
  101. "mov %rcx, 64(%rdi)",
  102. "",
  103. "mov (%rsi), %r12",
  104. "mov 8(%rsi), %r13",
  105. "mov 16(%rsi), %r14",
  106. "mov 24(%rsi), %r15",
  107. "mov 32(%rsi), %rbx",
  108. "mov 40(%rsi), %rbp",
  109. "mov 48(%rsi), %rdi", // store next stack pointer
  110. "mov 56(%rsi), %rax",
  111. "mov 64(%rsi), %rcx",
  112. "push %rcx",
  113. "popf",
  114. "xchg %rdi, %rsp", // switch to new stack
  115. "jmp *%rax",
  116. options(att_syntax),
  117. );
  118. }
  119. #[naked]
  120. /// Maximum of 5 arguments supported.
  121. unsafe extern "C" fn do_call() -> ! {
  122. naked_asm!(
  123. "mov %r12, %rdi",
  124. "mov %r13, %rsi",
  125. "mov %r14, %rdx",
  126. "mov %r15, %rcx",
  127. "mov %rbx, %r8",
  128. "mov %rbp, %rax",
  129. "xor %rbp, %rbp",
  130. "jmp *%rax",
  131. options(att_syntax),
  132. );
  133. }
  134. }