interrupt.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. use crate::arch::cpu::rdmsr;
  2. use core::{arch::asm, marker::PhantomPinned, pin::Pin, ptr::NonNull};
  3. #[repr(C)]
  4. #[derive(Clone, Copy)]
  5. struct IDTEntry {
  6. offset_low: u16,
  7. selector: u16,
  8. interrupt_stack: u8,
  9. attributes: u8,
  10. offset_mid: u16,
  11. offset_high: u32,
  12. reserved: u32,
  13. }
  14. pub struct APICReg(*mut u32);
  15. pub struct APICRegs {
  16. base: NonNull<u32>,
  17. }
  18. /// Architecture-specific interrupt control block.
  19. pub struct InterruptControl {
  20. idt: [IDTEntry; 256],
  21. apic_base: APICRegs,
  22. _pinned: PhantomPinned,
  23. }
  24. impl IDTEntry {
  25. const fn new(offset: usize, selector: u16, attributes: u8) -> Self {
  26. Self {
  27. offset_low: offset as u16,
  28. selector,
  29. interrupt_stack: 0,
  30. attributes,
  31. offset_mid: (offset >> 16) as u16,
  32. offset_high: (offset >> 32) as u32,
  33. reserved: 0,
  34. }
  35. }
  36. const fn null() -> Self {
  37. Self {
  38. offset_low: 0,
  39. selector: 0,
  40. interrupt_stack: 0,
  41. attributes: 0,
  42. offset_mid: 0,
  43. offset_high: 0,
  44. reserved: 0,
  45. }
  46. }
  47. }
  48. impl APICReg {
  49. fn new(pointer: *mut u32) -> Self {
  50. Self(pointer)
  51. }
  52. pub fn read(&self) -> u32 {
  53. unsafe { self.0.read_volatile() }
  54. }
  55. pub fn write(&self, value: u32) {
  56. unsafe { self.0.write_volatile(value) }
  57. }
  58. }
  59. impl APICRegs {
  60. pub fn local_apic_id(&self) -> APICReg {
  61. unsafe { APICReg::new(self.base.byte_offset(0x20).as_ptr()) }
  62. }
  63. pub fn task_priority(&self) -> APICReg {
  64. unsafe { APICReg::new(self.base.byte_offset(0x80).as_ptr()) }
  65. }
  66. pub fn end_of_interrupt(&self) {
  67. unsafe { APICReg::new(self.base.byte_offset(0xb0).as_ptr()).write(0) }
  68. }
  69. pub fn spurious(&self) -> APICReg {
  70. unsafe { APICReg::new(self.base.byte_offset(0xf0).as_ptr()) }
  71. }
  72. pub fn interrupt_command(&self) -> APICReg {
  73. unsafe { APICReg::new(self.base.byte_offset(0x300).as_ptr()) }
  74. }
  75. pub fn timer_register(&self) -> APICReg {
  76. unsafe { APICReg::new(self.base.byte_offset(0x320).as_ptr()) }
  77. }
  78. pub fn timer_initial_count(&self) -> APICReg {
  79. unsafe { APICReg::new(self.base.byte_offset(0x380).as_ptr()) }
  80. }
  81. pub fn timer_current_count(&self) -> APICReg {
  82. unsafe { APICReg::new(self.base.byte_offset(0x390).as_ptr()) }
  83. }
  84. pub fn timer_divide(&self) -> APICReg {
  85. unsafe { APICReg::new(self.base.byte_offset(0x3e0).as_ptr()) }
  86. }
  87. }
  88. impl InterruptControl {
  89. /// # Return
  90. /// Returns a tuple of InterruptControl and the cpu id of the current cpu.
  91. pub fn new() -> (Self, usize) {
  92. let trap_stubs_base = super::trap::trap_stubs_start as usize;
  93. let idt = core::array::from_fn(|idx| match idx {
  94. 0..0x80 => IDTEntry::new(trap_stubs_base + 8 * idx, 0x08, 0x8e),
  95. 0x80 => IDTEntry::new(trap_stubs_base + 8 * idx, 0x08, 0xee),
  96. _ => IDTEntry::null(),
  97. });
  98. let apic_base = {
  99. let apic_base = rdmsr(0x1b);
  100. assert_eq!(apic_base & 0x800, 0x800, "LAPIC not enabled");
  101. let apic_base = ((apic_base & !0xfff) + 0xffffff00_00000000) as *mut u32;
  102. APICRegs {
  103. // TODO: A better way to convert to physical address
  104. base: NonNull::new(apic_base).expect("Invalid APIC base"),
  105. }
  106. };
  107. // Make sure APIC is enabled.
  108. apic_base.spurious().write(0x1ff);
  109. let cpuid = apic_base.local_apic_id().read() >> 24;
  110. (
  111. Self {
  112. idt,
  113. apic_base,
  114. _pinned: PhantomPinned,
  115. },
  116. cpuid as usize,
  117. )
  118. }
  119. pub fn setup_timer(&self) {
  120. self.apic_base.task_priority().write(0);
  121. self.apic_base.timer_divide().write(0x3); // Divide by 16
  122. self.apic_base.timer_register().write(0x0040);
  123. // Setup the PIT to generate interrupts at 100Hz.
  124. unsafe {
  125. asm!(
  126. "in $0x61, %al",
  127. "and $0xfd, %al",
  128. "or $0x1, %al",
  129. "out %al, %dx",
  130. "mov $0xb2, %al",
  131. "out %al, $0x43",
  132. "mov $0x9b, %al",
  133. "out %al, $0x42",
  134. "in $0x60, %al",
  135. "mov $0x2e, %al",
  136. "out %al, $0x42",
  137. "in $0x61, %al",
  138. "and $0xfe, %al",
  139. "out %al, $0x61",
  140. "or $0x1, %al",
  141. "out %al, $0x61",
  142. out("eax") _,
  143. out("edx") _,
  144. options(att_syntax, nomem, nostack, preserves_flags),
  145. );
  146. }
  147. self.apic_base.timer_initial_count().write(u32::MAX);
  148. unsafe {
  149. asm!(
  150. "2:",
  151. "in $0x61, %al",
  152. "and $0x20, %al",
  153. "jz 2b",
  154. out("ax") _,
  155. options(att_syntax, nomem, nostack, preserves_flags),
  156. )
  157. }
  158. self.apic_base.timer_register().write(0x10000);
  159. let counts = self.apic_base.timer_current_count().read();
  160. let freq = (u32::MAX - counts) as u64 * 16 * 100;
  161. self.apic_base
  162. .timer_initial_count()
  163. .write((freq / 16 / 1_000) as u32);
  164. self.apic_base.timer_register().write(0x20040);
  165. self.apic_base.timer_divide().write(0x3); // Divide by 16
  166. }
  167. pub fn setup_idt(self: Pin<&mut Self>) {
  168. lidt(
  169. self.idt.as_ptr() as usize,
  170. (size_of::<IDTEntry>() * 256 - 1) as u16,
  171. );
  172. }
  173. pub fn send_sipi(&self) {
  174. let icr = self.apic_base.interrupt_command();
  175. icr.write(0xc4500);
  176. while icr.read() & 0x1000 != 0 {
  177. core::hint::spin_loop();
  178. }
  179. icr.write(0xc4606);
  180. while icr.read() & 0x1000 != 0 {
  181. core::hint::spin_loop();
  182. }
  183. }
  184. /// Send EOI to APIC so that it can send more interrupts.
  185. pub fn end_of_interrupt(&self) {
  186. self.apic_base.end_of_interrupt()
  187. }
  188. }
  189. fn lidt(base: usize, limit: u16) {
  190. let mut idt_descriptor = [0u16; 5];
  191. idt_descriptor[0] = limit;
  192. idt_descriptor[1] = base as u16;
  193. idt_descriptor[2] = (base >> 16) as u16;
  194. idt_descriptor[3] = (base >> 32) as u16;
  195. idt_descriptor[4] = (base >> 48) as u16;
  196. unsafe {
  197. asm!("lidt ({})", in(reg) &idt_descriptor, options(att_syntax, nostack, preserves_flags));
  198. }
  199. }