interrupt.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * interrupt.c
  3. *
  4. * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <interrupt.h>
  20. #include <segments.h>
  21. #include <lock.h>
  22. #include <thread.h>
  23. static byte_t isr_stubs[IDT_NUM_INTERRUPTS * ISR_STUB_SIZE];
  24. static idt_entry_t idt[IDT_NUM_INTERRUPTS];
  25. static interrupt_handler_t handlers[IDT_NUM_INTERRUPTS];
  26. static inline void lidt(dword_t base, dword_t size)
  27. {
  28. volatile dword_t idtr[2];
  29. idtr[0] = size << 16;
  30. idtr[1] = base;
  31. asm volatile ("lidt (%0)" :: "r"((byte_t*)idtr + 2));
  32. }
  33. static void idt_main_handler(byte_t interrupt_num, registers_t regs)
  34. {
  35. regs.esp += 16;
  36. if (handlers[interrupt_num].procedure == NULL) return;
  37. thread_t *thread = get_current_thread();
  38. if (thread)
  39. {
  40. if (thread->in_kernel == 0) thread->last_context = &regs;
  41. thread->in_kernel++;
  42. }
  43. if (handlers[interrupt_num].interrupts) enable_ints();
  44. handlers[interrupt_num].procedure(&regs, interrupt_num);
  45. if (thread)
  46. {
  47. ASSERT(thread->in_kernel > 0);
  48. if (--thread->in_kernel == 0)
  49. {
  50. thread->last_context = NULL;
  51. if (thread->terminated || (thread->frozen > 0))
  52. {
  53. enable_ints();
  54. syscall_yield_quantum();
  55. }
  56. ASSERT(!thread->terminated && (thread->frozen <= 0));
  57. }
  58. }
  59. disable_ints();
  60. }
  61. dword_t set_int_handler(byte_t interrupt_num, isr_proc_t proc, bool_t interrupts, bool_t usermode)
  62. {
  63. dword_t ret = ERR_SUCCESS;
  64. critical_t critical;
  65. enter_critical(&critical);
  66. if (handlers[interrupt_num].procedure != NULL)
  67. {
  68. ret = ERR_EXISTS;
  69. goto done;
  70. }
  71. handlers[interrupt_num].procedure = proc;
  72. handlers[interrupt_num].interrupts = interrupts;
  73. idt[interrupt_num].type = usermode ? IDT_GATE_USER : IDT_GATE_KERNEL;
  74. done:
  75. leave_critical(&critical);
  76. return ret;
  77. }
  78. dword_t remove_int_handler(byte_t interrupt_num)
  79. {
  80. dword_t ret = ERR_SUCCESS;
  81. critical_t critical;
  82. enter_critical(&critical);
  83. if (handlers[interrupt_num].procedure == NULL)
  84. {
  85. ret = ERR_NOTFOUND;
  86. goto done;
  87. }
  88. handlers[interrupt_num].procedure = NULL;
  89. idt[interrupt_num].type = IDT_GATE_KERNEL;
  90. done:
  91. leave_critical(&critical);
  92. return ret;
  93. }
  94. void interrupt_init(void)
  95. {
  96. dword_t i, offset = 0;
  97. for (i = 0; i < IDT_NUM_INTERRUPTS; i++)
  98. {
  99. idt[i].offset = (dword_t)&isr_stubs[offset] & 0xFFFF;
  100. idt[i].offset_high = (dword_t)&isr_stubs[offset] >> 16;
  101. idt[i].selector = get_kernel_code_selector();
  102. idt[i].type = IDT_GATE_KERNEL;
  103. idt[i].zero = 0;
  104. if (!HAS_ERROR_CODE(i))
  105. {
  106. isr_stubs[offset++] = 0x6A; // push 0
  107. isr_stubs[offset++] = 0x00;
  108. }
  109. isr_stubs[offset++] = 0x60; // pushad
  110. isr_stubs[offset++] = 0x1E; // push ds
  111. isr_stubs[offset++] = 0x6A; // push get_kernel_data_selector()
  112. isr_stubs[offset++] = get_kernel_data_selector();
  113. isr_stubs[offset++] = 0x58; // pop eax
  114. isr_stubs[offset++] = 0x8E; // mov ds, ax
  115. isr_stubs[offset++] = 0xD8;
  116. isr_stubs[offset++] = 0x8E; // mov es, ax
  117. isr_stubs[offset++] = 0xC0;
  118. isr_stubs[offset++] = 0x8E; // mov fs, ax
  119. isr_stubs[offset++] = 0xE0;
  120. isr_stubs[offset++] = 0x8E; // mov gs, ax
  121. isr_stubs[offset++] = 0xE8;
  122. isr_stubs[offset++] = 0x6A; // push i
  123. isr_stubs[offset++] = (byte_t) i;
  124. isr_stubs[offset++] = 0xE8; // call idt_main_handler
  125. dword_t rel_addr = (dword_t)idt_main_handler - (dword_t)&isr_stubs[offset + 4];
  126. isr_stubs[offset++] = rel_addr & 0xFF;
  127. isr_stubs[offset++] = (rel_addr >> 8) & 0xFF;
  128. isr_stubs[offset++] = (rel_addr >> 16) & 0xFF;
  129. isr_stubs[offset++] = (rel_addr >> 24) & 0xFF;
  130. isr_stubs[offset++] = 0x58; // pop eax
  131. if (!HAS_ERROR_CODE(i))
  132. {
  133. isr_stubs[offset++] = 0x81; // cmp dword [esp + 0x24], CONTEXT_SWITCH_MAGIC
  134. isr_stubs[offset++] = 0x7C;
  135. isr_stubs[offset++] = 0x24;
  136. isr_stubs[offset++] = 0x24;
  137. isr_stubs[offset++] = CONTEXT_SWITCH_MAGIC & 0xFF;
  138. isr_stubs[offset++] = (CONTEXT_SWITCH_MAGIC >> 8) & 0xFF;
  139. isr_stubs[offset++] = (CONTEXT_SWITCH_MAGIC >> 16) & 0xFF;
  140. isr_stubs[offset++] = CONTEXT_SWITCH_MAGIC >> 24;
  141. isr_stubs[offset++] = 0x75; // jnz +0x04
  142. isr_stubs[offset++] = 0x04;
  143. isr_stubs[offset++] = 0x8B; // mov esp, [esp + 0x10]
  144. isr_stubs[offset++] = 0x64;
  145. isr_stubs[offset++] = 0x24;
  146. isr_stubs[offset++] = 0x10;
  147. }
  148. isr_stubs[offset++] = 0x58; // pop eax
  149. isr_stubs[offset++] = 0x8E; // mov ds, ax
  150. isr_stubs[offset++] = 0xD8;
  151. isr_stubs[offset++] = 0x8E; // mov es, ax
  152. isr_stubs[offset++] = 0xC0;
  153. isr_stubs[offset++] = 0x8E; // mov fs, ax
  154. isr_stubs[offset++] = 0xE0;
  155. isr_stubs[offset++] = 0x8E; // mov gs, ax
  156. isr_stubs[offset++] = 0xE8;
  157. isr_stubs[offset++] = 0x61; // popad
  158. isr_stubs[offset++] = 0x83; // add esp, 4
  159. isr_stubs[offset++] = 0xC4;
  160. isr_stubs[offset++] = 0x04;
  161. isr_stubs[offset++] = 0xCF; // iret
  162. }
  163. lidt((dword_t)&idt, sizeof(idt));
  164. }