interrupt.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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. #include <cpu.h>
  24. #include <log.h>
  25. static byte_t isr_stubs[IDT_NUM_INTERRUPTS * ISR_STUB_SIZE];
  26. static idt_entry_t idt[IDT_NUM_INTERRUPTS];
  27. static interrupt_handler_t handlers[IDT_NUM_INTERRUPTS];
  28. static void idt_main_handler(byte_t interrupt_num, registers_t regs)
  29. {
  30. regs.esp += 16;
  31. if (SEGMENT_RPL(regs.cs) != 0) regs.esp += 8;
  32. if (handlers[interrupt_num].procedure == NULL) return;
  33. thread_t *thread = get_current_thread();
  34. if (thread)
  35. {
  36. if (thread->in_kernel == 0) thread->last_context = &regs;
  37. thread->in_kernel++;
  38. }
  39. if (handlers[interrupt_num].interrupts) cpu_enable_interrupts();
  40. handlers[interrupt_num].procedure(&regs, interrupt_num);
  41. if (thread)
  42. {
  43. ASSERT(thread->in_kernel > 0);
  44. if (--thread->in_kernel == 0)
  45. {
  46. thread->last_context = NULL;
  47. if (thread->terminating) thread->terminated = TRUE;
  48. if (thread->terminated || thread->frozen > 0) syscall_yield_quantum();
  49. ASSERT(!thread->terminated && (thread->frozen <= 0));
  50. }
  51. }
  52. cpu_disable_interrupts();
  53. }
  54. dword_t set_int_handler(byte_t interrupt_num, isr_proc_t proc, bool_t interrupts, bool_t usermode)
  55. {
  56. dword_t ret = ERR_SUCCESS;
  57. critical_t critical;
  58. enter_critical(&critical);
  59. if (handlers[interrupt_num].procedure != NULL)
  60. {
  61. ret = ERR_EXISTS;
  62. goto done;
  63. }
  64. handlers[interrupt_num].procedure = proc;
  65. handlers[interrupt_num].interrupts = interrupts;
  66. idt[interrupt_num].type = usermode ? IDT_GATE_USER : IDT_GATE_KERNEL;
  67. done:
  68. leave_critical(&critical);
  69. return ret;
  70. }
  71. dword_t remove_int_handler(byte_t interrupt_num)
  72. {
  73. dword_t ret = ERR_SUCCESS;
  74. critical_t critical;
  75. enter_critical(&critical);
  76. if (handlers[interrupt_num].procedure == NULL)
  77. {
  78. ret = ERR_NOTFOUND;
  79. goto done;
  80. }
  81. handlers[interrupt_num].procedure = NULL;
  82. idt[interrupt_num].type = IDT_GATE_KERNEL;
  83. done:
  84. leave_critical(&critical);
  85. return ret;
  86. }
  87. void interrupt_init(void)
  88. {
  89. dword_t i, offset = 0;
  90. for (i = 0; i < IDT_NUM_INTERRUPTS; i++)
  91. {
  92. idt[i].offset = (dword_t)&isr_stubs[offset] & 0xFFFF;
  93. idt[i].offset_high = (dword_t)&isr_stubs[offset] >> 16;
  94. idt[i].selector = get_kernel_code_selector();
  95. idt[i].type = IDT_GATE_KERNEL;
  96. idt[i].zero = 0;
  97. if (!HAS_ERROR_CODE(i))
  98. {
  99. isr_stubs[offset++] = 0x6A; // push 0
  100. isr_stubs[offset++] = 0x00;
  101. }
  102. isr_stubs[offset++] = 0x60; // pushad
  103. isr_stubs[offset++] = 0x1E; // push ds
  104. isr_stubs[offset++] = 0x6A; // push get_kernel_data_selector()
  105. isr_stubs[offset++] = get_kernel_data_selector();
  106. isr_stubs[offset++] = 0x58; // pop eax
  107. isr_stubs[offset++] = 0x8E; // mov ds, ax
  108. isr_stubs[offset++] = 0xD8;
  109. isr_stubs[offset++] = 0x8E; // mov es, ax
  110. isr_stubs[offset++] = 0xC0;
  111. isr_stubs[offset++] = 0x8E; // mov fs, ax
  112. isr_stubs[offset++] = 0xE0;
  113. isr_stubs[offset++] = 0x8E; // mov gs, ax
  114. isr_stubs[offset++] = 0xE8;
  115. isr_stubs[offset++] = 0x6A; // push i
  116. isr_stubs[offset++] = (byte_t) i;
  117. isr_stubs[offset++] = 0xE8; // call idt_main_handler
  118. dword_t rel_addr = (dword_t)idt_main_handler - (dword_t)&isr_stubs[offset + 4];
  119. isr_stubs[offset++] = rel_addr & 0xFF;
  120. isr_stubs[offset++] = (rel_addr >> 8) & 0xFF;
  121. isr_stubs[offset++] = (rel_addr >> 16) & 0xFF;
  122. isr_stubs[offset++] = (rel_addr >> 24) & 0xFF;
  123. isr_stubs[offset++] = 0x58; // pop eax
  124. if (!HAS_ERROR_CODE(i))
  125. {
  126. isr_stubs[offset++] = 0x81; // cmp dword [esp + 0x24], CONTEXT_SWITCH_MAGIC
  127. isr_stubs[offset++] = 0x7C;
  128. isr_stubs[offset++] = 0x24;
  129. isr_stubs[offset++] = 0x24;
  130. isr_stubs[offset++] = CONTEXT_SWITCH_MAGIC & 0xFF;
  131. isr_stubs[offset++] = (CONTEXT_SWITCH_MAGIC >> 8) & 0xFF;
  132. isr_stubs[offset++] = (CONTEXT_SWITCH_MAGIC >> 16) & 0xFF;
  133. isr_stubs[offset++] = CONTEXT_SWITCH_MAGIC >> 24;
  134. isr_stubs[offset++] = 0x75; // jnz +0x04
  135. isr_stubs[offset++] = 0x04;
  136. isr_stubs[offset++] = 0x8B; // mov esp, [esp + 0x10]
  137. isr_stubs[offset++] = 0x64;
  138. isr_stubs[offset++] = 0x24;
  139. isr_stubs[offset++] = 0x10;
  140. }
  141. isr_stubs[offset++] = 0x58; // pop eax
  142. isr_stubs[offset++] = 0x8E; // mov ds, ax
  143. isr_stubs[offset++] = 0xD8;
  144. isr_stubs[offset++] = 0x8E; // mov es, ax
  145. isr_stubs[offset++] = 0xC0;
  146. isr_stubs[offset++] = 0x8E; // mov fs, ax
  147. isr_stubs[offset++] = 0xE0;
  148. isr_stubs[offset++] = 0x8E; // mov gs, ax
  149. isr_stubs[offset++] = 0xE8;
  150. isr_stubs[offset++] = 0x61; // popad
  151. isr_stubs[offset++] = 0x83; // add esp, 4
  152. isr_stubs[offset++] = 0xC4;
  153. isr_stubs[offset++] = 0x04;
  154. isr_stubs[offset++] = 0xCF; // iret
  155. }
  156. cpu_set_interrupt_table(idt, sizeof(idt));
  157. }