123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /*
- * interrupt.c
- *
- * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <interrupt.h>
- #include <segments.h>
- #include <lock.h>
- #include <thread.h>
- #include <cpu.h>
- #include <log.h>
- static byte_t isr_stubs[IDT_NUM_INTERRUPTS * ISR_STUB_SIZE];
- static idt_entry_t idt[IDT_NUM_INTERRUPTS];
- static interrupt_handler_t handlers[IDT_NUM_INTERRUPTS];
- static void idt_main_handler(byte_t interrupt_num, registers_t regs)
- {
- regs.esp += 16;
- if (SEGMENT_RPL(regs.cs) != 0) regs.esp += 8;
- if (handlers[interrupt_num].procedure == NULL) return;
- thread_t *thread = get_current_thread();
- if (thread)
- {
- if (thread->in_kernel == 0) thread->last_context = ®s;
- thread->in_kernel++;
- }
- if (handlers[interrupt_num].interrupts) cpu_enable_interrupts();
- handlers[interrupt_num].procedure(®s, interrupt_num);
- if (thread)
- {
- ASSERT(thread->in_kernel > 0);
- if (--thread->in_kernel == 0)
- {
- thread->last_context = NULL;
- if (thread->terminating) thread->terminated = TRUE;
- if (thread->terminated || thread->frozen > 0) syscall_yield_quantum();
- ASSERT(!thread->terminated && (thread->frozen <= 0));
- }
- }
- cpu_disable_interrupts();
- }
- dword_t set_int_handler(byte_t interrupt_num, isr_proc_t proc, bool_t interrupts, bool_t usermode)
- {
- dword_t ret = ERR_SUCCESS;
- critical_t critical;
- enter_critical(&critical);
- if (handlers[interrupt_num].procedure != NULL)
- {
- ret = ERR_EXISTS;
- goto done;
- }
- handlers[interrupt_num].procedure = proc;
- handlers[interrupt_num].interrupts = interrupts;
- idt[interrupt_num].type = usermode ? IDT_GATE_USER : IDT_GATE_KERNEL;
- done:
- leave_critical(&critical);
- return ret;
- }
- dword_t remove_int_handler(byte_t interrupt_num)
- {
- dword_t ret = ERR_SUCCESS;
- critical_t critical;
- enter_critical(&critical);
- if (handlers[interrupt_num].procedure == NULL)
- {
- ret = ERR_NOTFOUND;
- goto done;
- }
- handlers[interrupt_num].procedure = NULL;
- idt[interrupt_num].type = IDT_GATE_KERNEL;
- done:
- leave_critical(&critical);
- return ret;
- }
- void interrupt_init(void)
- {
- dword_t i, offset = 0;
- for (i = 0; i < IDT_NUM_INTERRUPTS; i++)
- {
- idt[i].offset = (dword_t)&isr_stubs[offset] & 0xFFFF;
- idt[i].offset_high = (dword_t)&isr_stubs[offset] >> 16;
- idt[i].selector = get_kernel_code_selector();
- idt[i].type = IDT_GATE_KERNEL;
- idt[i].zero = 0;
- if (!HAS_ERROR_CODE(i))
- {
- isr_stubs[offset++] = 0x6A; // push 0
- isr_stubs[offset++] = 0x00;
- }
- isr_stubs[offset++] = 0x60; // pushad
- isr_stubs[offset++] = 0x1E; // push ds
- isr_stubs[offset++] = 0x6A; // push get_kernel_data_selector()
- isr_stubs[offset++] = get_kernel_data_selector();
- isr_stubs[offset++] = 0x58; // pop eax
- isr_stubs[offset++] = 0x8E; // mov ds, ax
- isr_stubs[offset++] = 0xD8;
- isr_stubs[offset++] = 0x8E; // mov es, ax
- isr_stubs[offset++] = 0xC0;
- isr_stubs[offset++] = 0x8E; // mov fs, ax
- isr_stubs[offset++] = 0xE0;
- isr_stubs[offset++] = 0x8E; // mov gs, ax
- isr_stubs[offset++] = 0xE8;
- isr_stubs[offset++] = 0x6A; // push i
- isr_stubs[offset++] = (byte_t) i;
- isr_stubs[offset++] = 0xE8; // call idt_main_handler
- dword_t rel_addr = (dword_t)idt_main_handler - (dword_t)&isr_stubs[offset + 4];
- isr_stubs[offset++] = rel_addr & 0xFF;
- isr_stubs[offset++] = (rel_addr >> 8) & 0xFF;
- isr_stubs[offset++] = (rel_addr >> 16) & 0xFF;
- isr_stubs[offset++] = (rel_addr >> 24) & 0xFF;
- isr_stubs[offset++] = 0x58; // pop eax
- if (!HAS_ERROR_CODE(i))
- {
- isr_stubs[offset++] = 0x81; // cmp dword [esp + 0x24], CONTEXT_SWITCH_MAGIC
- isr_stubs[offset++] = 0x7C;
- isr_stubs[offset++] = 0x24;
- isr_stubs[offset++] = 0x24;
- isr_stubs[offset++] = CONTEXT_SWITCH_MAGIC & 0xFF;
- isr_stubs[offset++] = (CONTEXT_SWITCH_MAGIC >> 8) & 0xFF;
- isr_stubs[offset++] = (CONTEXT_SWITCH_MAGIC >> 16) & 0xFF;
- isr_stubs[offset++] = CONTEXT_SWITCH_MAGIC >> 24;
- isr_stubs[offset++] = 0x75; // jnz +0x04
- isr_stubs[offset++] = 0x04;
- isr_stubs[offset++] = 0x8B; // mov esp, [esp + 0x10]
- isr_stubs[offset++] = 0x64;
- isr_stubs[offset++] = 0x24;
- isr_stubs[offset++] = 0x10;
- }
- isr_stubs[offset++] = 0x58; // pop eax
- isr_stubs[offset++] = 0x8E; // mov ds, ax
- isr_stubs[offset++] = 0xD8;
- isr_stubs[offset++] = 0x8E; // mov es, ax
- isr_stubs[offset++] = 0xC0;
- isr_stubs[offset++] = 0x8E; // mov fs, ax
- isr_stubs[offset++] = 0xE0;
- isr_stubs[offset++] = 0x8E; // mov gs, ax
- isr_stubs[offset++] = 0xE8;
- isr_stubs[offset++] = 0x61; // popad
- isr_stubs[offset++] = 0x83; // add esp, 4
- isr_stubs[offset++] = 0xC4;
- isr_stubs[offset++] = 0x04;
- isr_stubs[offset++] = 0xCF; // iret
- }
- cpu_set_interrupt_table(idt, sizeof(idt));
- }
|