interrupt.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. use core::{arch::asm, pin::Pin, ptr::NonNull};
  2. use crate::rdmsr;
  3. use super::pause;
  4. /// Saved registers when a trap (interrupt or exception) occurs.
  5. #[allow(missing_docs)]
  6. #[repr(C)]
  7. #[derive(Debug, Default, Clone, Copy)]
  8. pub struct InterruptContext {
  9. pub rax: u64,
  10. pub rbx: u64,
  11. pub rcx: u64,
  12. pub rdx: u64,
  13. pub rdi: u64,
  14. pub rsi: u64,
  15. pub r8: u64,
  16. pub r9: u64,
  17. pub r10: u64,
  18. pub r11: u64,
  19. pub r12: u64,
  20. pub r13: u64,
  21. pub r14: u64,
  22. pub r15: u64,
  23. pub rbp: u64,
  24. pub int_no: u64,
  25. pub error_code: u64,
  26. // Pushed by CPU
  27. pub rip: u64,
  28. pub cs: u64,
  29. pub eflags: u64,
  30. pub rsp: u64,
  31. pub ss: u64,
  32. }
  33. #[repr(C)]
  34. #[derive(Clone, Copy)]
  35. struct IDTEntry {
  36. offset_low: u16,
  37. selector: u16,
  38. interrupt_stack: u8,
  39. attributes: u8,
  40. offset_mid: u16,
  41. offset_high: u32,
  42. reserved: u32,
  43. }
  44. pub struct APICReg(*mut u32);
  45. pub struct APICRegs {
  46. base: NonNull<u32>,
  47. }
  48. /// Architecture-specific interrupt control block.
  49. pub struct InterruptControl {
  50. idt: [IDTEntry; 256],
  51. apic_base: APICRegs,
  52. }
  53. impl IDTEntry {
  54. const fn new(offset: usize, selector: u16, attributes: u8) -> Self {
  55. Self {
  56. offset_low: offset as u16,
  57. selector,
  58. interrupt_stack: 0,
  59. attributes,
  60. offset_mid: (offset >> 16) as u16,
  61. offset_high: (offset >> 32) as u32,
  62. reserved: 0,
  63. }
  64. }
  65. const fn null() -> Self {
  66. Self {
  67. offset_low: 0,
  68. selector: 0,
  69. interrupt_stack: 0,
  70. attributes: 0,
  71. offset_mid: 0,
  72. offset_high: 0,
  73. reserved: 0,
  74. }
  75. }
  76. }
  77. impl APICReg {
  78. fn new(pointer: *mut u32) -> Self {
  79. Self(pointer)
  80. }
  81. pub fn read(&self) -> u32 {
  82. unsafe { self.0.read_volatile() }
  83. }
  84. pub fn write(&self, value: u32) {
  85. unsafe { self.0.write_volatile(value) }
  86. }
  87. }
  88. impl APICRegs {
  89. pub fn local_apic_id(&self) -> APICReg {
  90. unsafe { APICReg::new(self.base.byte_offset(0x20).as_ptr()) }
  91. }
  92. pub fn task_priority(&self) -> APICReg {
  93. unsafe { APICReg::new(self.base.byte_offset(0x80).as_ptr()) }
  94. }
  95. pub fn end_of_interrupt(&self) {
  96. unsafe { APICReg::new(self.base.byte_offset(0xb0).as_ptr()).write(0) }
  97. }
  98. pub fn spurious(&self) -> APICReg {
  99. unsafe { APICReg::new(self.base.byte_offset(0xf0).as_ptr()) }
  100. }
  101. pub fn interrupt_command(&self) -> APICReg {
  102. unsafe { APICReg::new(self.base.byte_offset(0x300).as_ptr()) }
  103. }
  104. pub fn timer_register(&self) -> APICReg {
  105. unsafe { APICReg::new(self.base.byte_offset(0x320).as_ptr()) }
  106. }
  107. pub fn timer_initial_count(&self) -> APICReg {
  108. unsafe { APICReg::new(self.base.byte_offset(0x380).as_ptr()) }
  109. }
  110. pub fn timer_current_count(&self) -> APICReg {
  111. unsafe { APICReg::new(self.base.byte_offset(0x390).as_ptr()) }
  112. }
  113. pub fn timer_divide(&self) -> APICReg {
  114. unsafe { APICReg::new(self.base.byte_offset(0x3e0).as_ptr()) }
  115. }
  116. }
  117. impl InterruptControl {
  118. /// # Return
  119. /// Returns a tuple of InterruptControl and the cpu id of the current cpu.
  120. pub unsafe fn new() -> (Self, usize) {
  121. extern "C" {
  122. static ISR_START_ADDR: usize;
  123. }
  124. let idt = core::array::from_fn(|idx| match idx {
  125. 0..0x80 => IDTEntry::new(unsafe { ISR_START_ADDR } + 8 * idx, 0x08, 0x8e),
  126. 0x80 => IDTEntry::new(unsafe { ISR_START_ADDR } + 8 * idx, 0x08, 0xee),
  127. _ => IDTEntry::null(),
  128. });
  129. let apic_base = {
  130. let apic_base = rdmsr(0x1b);
  131. assert_eq!(apic_base & 0x800, 0x800, "LAPIC not enabled");
  132. let apic_base = ((apic_base & !0xfff) + 0xffffff00_00000000) as *mut u32;
  133. APICRegs {
  134. // TODO: A better way to convert to physical address
  135. base: NonNull::new(apic_base).expect("Invalid APIC base"),
  136. }
  137. };
  138. // Make sure APIC is enabled.
  139. apic_base.spurious().write(0x1ff);
  140. let cpuid = apic_base.local_apic_id().read() >> 24;
  141. (Self { idt, apic_base }, cpuid as usize)
  142. }
  143. pub fn setup_timer(&self) {
  144. self.apic_base.task_priority().write(0);
  145. self.apic_base.timer_divide().write(0x3); // Divide by 16
  146. self.apic_base.timer_register().write(0x20040);
  147. // TODO: Get the bus frequency from...?
  148. let freq = 200;
  149. let count = freq * 1_000_000 / 16 / 100;
  150. self.apic_base.timer_initial_count().write(count as u32);
  151. }
  152. pub fn setup_idt(self: Pin<&mut Self>) {
  153. lidt(
  154. self.idt.as_ptr() as usize,
  155. (size_of::<IDTEntry>() * 256 - 1) as u16,
  156. );
  157. }
  158. pub fn send_sipi(&self) {
  159. let icr = self.apic_base.interrupt_command();
  160. icr.write(0xc4500);
  161. while icr.read() & 0x1000 != 0 {
  162. pause();
  163. }
  164. icr.write(0xc4601);
  165. while icr.read() & 0x1000 != 0 {
  166. pause();
  167. }
  168. }
  169. /// Send EOI to APIC so that it can send more interrupts.
  170. pub fn end_of_interrupt(&self) {
  171. self.apic_base.end_of_interrupt()
  172. }
  173. }
  174. pub fn enable_irqs() {
  175. unsafe {
  176. asm!("sti");
  177. }
  178. }
  179. pub fn disable_irqs() {
  180. unsafe {
  181. asm!("cli");
  182. }
  183. }
  184. fn lidt(base: usize, limit: u16) {
  185. let mut idt_descriptor = [0u16; 5];
  186. idt_descriptor[0] = limit;
  187. idt_descriptor[1] = base as u16;
  188. idt_descriptor[2] = (base >> 16) as u16;
  189. idt_descriptor[3] = (base >> 32) as u16;
  190. idt_descriptor[4] = (base >> 48) as u16;
  191. unsafe {
  192. asm!("lidt ({})", in(reg) &idt_descriptor, options(att_syntax));
  193. }
  194. }