mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Refactor i386 and x86_64 interrupt support.
This commit is contained in:
parent
d50e8f1bce
commit
a133a7717e
17 changed files with 655 additions and 553 deletions
|
@ -45,6 +45,8 @@ ifdef X86FAMILY
|
|||
$(CPU)/memorymanagement.o \
|
||||
x86-family/memorymanagement.o \
|
||||
$(CPU)/interrupt.o \
|
||||
x86-family/interrupt.o \
|
||||
x86-family/pic.o \
|
||||
x86-family/gdt.o \
|
||||
x86-family/idt.o \
|
||||
$(CPU)/syscall.o \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/kernel/interrupt.h
|
||||
High level interrupt service routines and interrupt request handlers.
|
||||
High level interrupt services.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
|
@ -30,13 +30,17 @@
|
|||
#include <sortix/kernel/decl.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
namespace CPU {
|
||||
struct InterruptRegisters;
|
||||
} // namespace CPU
|
||||
|
||||
struct InterruptRegisters;
|
||||
|
||||
} // namespace CPU
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
namespace Interrupt {
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
const unsigned int IRQ0 = 32;
|
||||
const unsigned int IRQ1 = 33;
|
||||
const unsigned int IRQ2 = 34;
|
||||
|
@ -53,27 +57,60 @@ const unsigned int IRQ12 = 44;
|
|||
const unsigned int IRQ13 = 45;
|
||||
const unsigned int IRQ14 = 46;
|
||||
const unsigned int IRQ15 = 47;
|
||||
#endif
|
||||
|
||||
extern "C" unsigned long asm_interrupts_are_enabled();
|
||||
extern "C" unsigned long asm_is_cpu_interrupted;
|
||||
|
||||
inline bool IsEnabled() { return asm_interrupts_are_enabled(); }
|
||||
inline void Enable() { asm volatile("sti"); }
|
||||
inline void Disable() { asm volatile("cli"); }
|
||||
inline bool IsCPUInterrupted() { return asm_is_cpu_interrupted != 0; }
|
||||
inline bool SetEnabled(bool isenabled)
|
||||
inline bool IsEnabled()
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
unsigned long is_enabled;
|
||||
asm("pushf\t\n"
|
||||
"pop %0\t\n"
|
||||
"and $0x000200, %0" : "=r"(is_enabled));
|
||||
return is_enabled != 0;
|
||||
#else
|
||||
#warning "You need to implement checking if interrupts are on"
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void Enable()
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
asm volatile("sti");
|
||||
#else
|
||||
#warning "You need to implement enabling interrupts"
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void Disable()
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
asm volatile("cli");
|
||||
#else
|
||||
#warning "You need to implement disabling interrupts"
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool IsCPUInterrupted()
|
||||
{
|
||||
return asm_is_cpu_interrupted != 0;
|
||||
}
|
||||
|
||||
inline bool SetEnabled(bool is_enabled)
|
||||
{
|
||||
bool wasenabled = IsEnabled();
|
||||
if ( isenabled ) { Enable(); } else { Disable(); }
|
||||
if ( is_enabled )
|
||||
Enable();
|
||||
else
|
||||
Disable();
|
||||
return wasenabled;
|
||||
}
|
||||
|
||||
|
||||
typedef void (*Handler)(CPU::InterruptRegisters* regs, void* user);
|
||||
void RegisterHandler(unsigned int index, Handler handler, void* user);
|
||||
|
||||
typedef void (*RawHandler)(void);
|
||||
void RegisterRawHandler(unsigned int index, RawHandler handler, bool userspace);
|
||||
|
||||
void Init();
|
||||
void InitWorker();
|
||||
void WorkerThread(void* user);
|
||||
|
@ -84,57 +121,4 @@ bool ScheduleWork(WorkHandler handler, void* payload, size_t payloadsize);
|
|||
} // namespace Interrupt
|
||||
} // namespace Sortix
|
||||
|
||||
extern "C" void isr0();
|
||||
extern "C" void isr1();
|
||||
extern "C" void isr2();
|
||||
extern "C" void isr3();
|
||||
extern "C" void isr4();
|
||||
extern "C" void isr5();
|
||||
extern "C" void isr6();
|
||||
extern "C" void isr7();
|
||||
extern "C" void isr8();
|
||||
extern "C" void isr9();
|
||||
extern "C" void isr10();
|
||||
extern "C" void isr11();
|
||||
extern "C" void isr12();
|
||||
extern "C" void isr13();
|
||||
extern "C" void isr14();
|
||||
extern "C" void isr15();
|
||||
extern "C" void isr16();
|
||||
extern "C" void isr17();
|
||||
extern "C" void isr18();
|
||||
extern "C" void isr19();
|
||||
extern "C" void isr20();
|
||||
extern "C" void isr21();
|
||||
extern "C" void isr22();
|
||||
extern "C" void isr23();
|
||||
extern "C" void isr24();
|
||||
extern "C" void isr25();
|
||||
extern "C" void isr26();
|
||||
extern "C" void isr27();
|
||||
extern "C" void isr28();
|
||||
extern "C" void isr29();
|
||||
extern "C" void isr30();
|
||||
extern "C" void isr31();
|
||||
extern "C" void isr128();
|
||||
extern "C" void isr130();
|
||||
extern "C" void isr131();
|
||||
extern "C" void irq0();
|
||||
extern "C" void irq1();
|
||||
extern "C" void irq2();
|
||||
extern "C" void irq3();
|
||||
extern "C" void irq4();
|
||||
extern "C" void irq5();
|
||||
extern "C" void irq6();
|
||||
extern "C" void irq7();
|
||||
extern "C" void irq8();
|
||||
extern "C" void irq9();
|
||||
extern "C" void irq10();
|
||||
extern "C" void irq11();
|
||||
extern "C" void irq12();
|
||||
extern "C" void irq13();
|
||||
extern "C" void irq14();
|
||||
extern "C" void irq15();
|
||||
extern "C" void interrupt_handler_null();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -28,20 +28,26 @@
|
|||
#include <sortix/kernel/decl.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Process;
|
||||
class Thread;
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
namespace CPU {
|
||||
struct InterruptRegisters;
|
||||
} // namespace CPU
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
enum ThreadState { NONE, RUNNABLE, BLOCKING, DEAD };
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
namespace Scheduler {
|
||||
|
||||
void Init();
|
||||
void Switch(CPU::InterruptRegisters* regs);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
inline static void Yield() { asm volatile ("int $129"); }
|
||||
__attribute__ ((noreturn))
|
||||
inline static void ExitThread()
|
||||
|
@ -49,6 +55,7 @@ inline static void ExitThread()
|
|||
asm volatile ("int $132");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
#endif
|
||||
void SetThreadState(Thread* thread, ThreadState state);
|
||||
ThreadState GetThreadState(Thread* thread);
|
||||
void SetIdleThread(Thread* thread);
|
||||
|
@ -56,9 +63,10 @@ void SetDummyThreadOwner(Process* process);
|
|||
void SetInitProcess(Process* init);
|
||||
Process* GetInitProcess();
|
||||
Process* GetKernelProcess();
|
||||
void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* user);
|
||||
void ThreadExitCPU(CPU::InterruptRegisters* regs, void* user);
|
||||
|
||||
} // namespace Scheduler
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -38,6 +38,4 @@ void Register(size_t index, void* funcptr);
|
|||
} // namespace Syscall
|
||||
} // namespace Sortix
|
||||
|
||||
extern "C" void syscall_handler();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
interrupt.cpp
|
||||
High level interrupt service routines and interrupt request handlers.
|
||||
High level interrupt services.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
|
@ -37,292 +37,9 @@
|
|||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
|
||||
#include "x86-family/idt.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
namespace Interrupt {
|
||||
|
||||
const uint16_t PIC_MASTER = 0x20;
|
||||
const uint16_t PIC_SLAVE = 0xA0;
|
||||
const uint16_t PIC_COMMAND = 0x00;
|
||||
const uint16_t PIC_DATA = 0x01;
|
||||
const uint8_t PIC_CMD_ENDINTR = 0x20;
|
||||
const uint8_t PIC_ICW1_ICW4 = 0x01; // ICW4 (not) needed
|
||||
const uint8_t PIC_ICW1_SINGLE = 0x02; // Single (cascade) mode
|
||||
const uint8_t PIC_ICW1_INTERVAL4 = 0x04; // Call address interval 4 (8)
|
||||
const uint8_t PIC_ICW1_LEVEL = 0x08; // Level triggered (edge) mode
|
||||
const uint8_t PIC_CMD_INIT = 0x10;
|
||||
const uint8_t PIC_MODE_8086 = 0x01; // 8086/88 (MCS-80/85) mode
|
||||
const uint8_t PIC_MODE_AUTO = 0x02; // Auto (normal) EOI
|
||||
const uint8_t PIC_MODE_BUF_SLAVE = 0x08; // Buffered mode/slave
|
||||
const uint8_t PIC_MODE_BUF_MASTER = 0x0C; // Buffered mode/master
|
||||
const uint8_t PIC_MODE_SFNM = 0x10; // Special fully nested (not)
|
||||
|
||||
extern "C" { unsigned long asm_is_cpu_interrupted = 0; }
|
||||
const bool DEBUG_EXCEPTION = true;
|
||||
const bool DEBUG_IRQ = false;
|
||||
const bool DEBUG_ISR = false;
|
||||
const bool CALLTRACE_KERNEL = false;
|
||||
const bool CALLTRACE_USER = false;
|
||||
const bool RUN_DEBUGGER_ON_CRASH = false;
|
||||
|
||||
const size_t NUM_KNOWN_EXCEPTIONS = 20;
|
||||
const char* exceptions[] =
|
||||
{
|
||||
"Divide by zero", /* 0, 0x0 */
|
||||
"Debug", /* 1, 0x1 */
|
||||
"Non maskable interrupt", /* 2, 0x2 */
|
||||
"Breakpoint", /* 3, 0x3 */
|
||||
"Into detected overflow", /* 4, 0x4 */
|
||||
"Out of bounds", /* 5, 0x5 */
|
||||
"Invalid opcode", /* 6, 0x6 */
|
||||
"No coprocessor", /* 7, 0x7 */
|
||||
"Double fault", /* 8, 0x8 */
|
||||
"Coprocessor segment overrun", /* 9, 0x9 */
|
||||
"Bad TSS", /* 10, 0xA */
|
||||
"Segment not present", /* 11, 0xB */
|
||||
"Stack fault", /* 12, 0xC */
|
||||
"General protection fault", /* 13, 0xD */
|
||||
"Page fault", /* 14, 0xE */
|
||||
"Unknown interrupt", /* 15, 0xF */
|
||||
"Coprocessor fault", /* 16, 0x10 */
|
||||
"Alignment check", /* 17, 0x11 */
|
||||
"Machine check", /* 18, 0x12 */
|
||||
"SIMD Floating-Point", /* 19, 0x13 */
|
||||
};
|
||||
|
||||
const unsigned int NUM_INTERRUPTS = 256UL;
|
||||
static Handler interrupt_handlers[NUM_INTERRUPTS];
|
||||
static void* interrupt_handler_params[NUM_INTERRUPTS];
|
||||
|
||||
extern "C" void ReprogramPIC()
|
||||
{
|
||||
uint8_t master_mask = 0;
|
||||
uint8_t slave_mask = 0;
|
||||
CPU::OutPortB(PIC_MASTER + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, IRQ0);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, IRQ8);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x04); // Slave PIC at IRQ2
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x02); // Cascade Identity
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, master_mask);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, slave_mask);
|
||||
}
|
||||
|
||||
extern "C" void DeprogramPIC()
|
||||
{
|
||||
uint8_t master_mask = 0;
|
||||
uint8_t slave_mask = 0;
|
||||
CPU::OutPortB(PIC_MASTER + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x08);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x70);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x04); // Slave PIC at IRQ2
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x02); // Cascade Identity
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, master_mask);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, slave_mask);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
IDT::Init();
|
||||
|
||||
for ( unsigned int i = 0; i < NUM_INTERRUPTS; i++ )
|
||||
{
|
||||
interrupt_handlers[i] = NULL;
|
||||
interrupt_handler_params[i] = NULL;
|
||||
RegisterRawHandler(i, interrupt_handler_null, false);
|
||||
}
|
||||
|
||||
// Remap the IRQ table on the PICs.
|
||||
ReprogramPIC();
|
||||
|
||||
RegisterRawHandler(0, isr0, false);
|
||||
RegisterRawHandler(1, isr1, false);
|
||||
RegisterRawHandler(2, isr2, false);
|
||||
RegisterRawHandler(3, isr3, false);
|
||||
RegisterRawHandler(4, isr4, false);
|
||||
RegisterRawHandler(5, isr5, false);
|
||||
RegisterRawHandler(6, isr6, false);
|
||||
RegisterRawHandler(7, isr7, false);
|
||||
RegisterRawHandler(8, isr8, false);
|
||||
RegisterRawHandler(9, isr9, false);
|
||||
RegisterRawHandler(10, isr10, false);
|
||||
RegisterRawHandler(11, isr11, false);
|
||||
RegisterRawHandler(12, isr12, false);
|
||||
RegisterRawHandler(13, isr13, false);
|
||||
RegisterRawHandler(14, isr14, false);
|
||||
RegisterRawHandler(15, isr15, false);
|
||||
RegisterRawHandler(16, isr16, false);
|
||||
RegisterRawHandler(17, isr17, false);
|
||||
RegisterRawHandler(18, isr18, false);
|
||||
RegisterRawHandler(19, isr19, false);
|
||||
RegisterRawHandler(20, isr20, false);
|
||||
RegisterRawHandler(21, isr21, false);
|
||||
RegisterRawHandler(22, isr22, false);
|
||||
RegisterRawHandler(23, isr23, false);
|
||||
RegisterRawHandler(24, isr24, false);
|
||||
RegisterRawHandler(25, isr25, false);
|
||||
RegisterRawHandler(26, isr26, false);
|
||||
RegisterRawHandler(27, isr27, false);
|
||||
RegisterRawHandler(28, isr28, false);
|
||||
RegisterRawHandler(29, isr29, false);
|
||||
RegisterRawHandler(30, isr30, false);
|
||||
RegisterRawHandler(31, isr31, false);
|
||||
RegisterRawHandler(32, irq0, false);
|
||||
RegisterRawHandler(33, irq1, false);
|
||||
RegisterRawHandler(34, irq2, false);
|
||||
RegisterRawHandler(35, irq3, false);
|
||||
RegisterRawHandler(36, irq4, false);
|
||||
RegisterRawHandler(37, irq5, false);
|
||||
RegisterRawHandler(38, irq6, false);
|
||||
RegisterRawHandler(39, irq7, false);
|
||||
RegisterRawHandler(40, irq8, false);
|
||||
RegisterRawHandler(41, irq9, false);
|
||||
RegisterRawHandler(42, irq10, false);
|
||||
RegisterRawHandler(43, irq11, false);
|
||||
RegisterRawHandler(44, irq12, false);
|
||||
RegisterRawHandler(45, irq13, false);
|
||||
RegisterRawHandler(46, irq14, false);
|
||||
RegisterRawHandler(47, irq15, false);
|
||||
|
||||
// TODO: Let the syscall.cpp code register this.
|
||||
RegisterRawHandler(128, syscall_handler, true);
|
||||
|
||||
Interrupt::Enable();
|
||||
}
|
||||
|
||||
void RegisterHandler(unsigned int index, Interrupt::Handler handler, void* user)
|
||||
{
|
||||
interrupt_handlers[index] = handler;
|
||||
interrupt_handler_params[index] = user;
|
||||
}
|
||||
|
||||
// TODO: This function contains magic IDT-related values!
|
||||
void RegisterRawHandler(unsigned int index, RawHandler handler, bool userspace)
|
||||
{
|
||||
addr_t handler_entry = (addr_t) handler;
|
||||
uint16_t sel = KCS;
|
||||
uint8_t flags = 0x8E;
|
||||
if ( userspace )
|
||||
flags |= 0x60;
|
||||
IDT::SetEntry(index, handler_entry, sel, flags);
|
||||
}
|
||||
|
||||
void CrashHandler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
CurrentThread()->SaveRegisters(regs);
|
||||
|
||||
const char* message = regs->int_no < NUM_KNOWN_EXCEPTIONS
|
||||
? exceptions[regs->int_no] : "Unknown";
|
||||
|
||||
if ( DEBUG_EXCEPTION )
|
||||
{
|
||||
regs->LogRegisters();
|
||||
Log::Print("\n");
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
addr_t ip = regs->rip;
|
||||
#elif defined(__i386__)
|
||||
addr_t ip = regs->eip;
|
||||
#endif
|
||||
|
||||
// Halt and catch fire if we are the kernel.
|
||||
unsigned code_mode = regs->cs & 0x3;
|
||||
bool is_in_kernel = !code_mode;
|
||||
bool is_in_user = !is_in_kernel;
|
||||
|
||||
if ( (is_in_kernel && CALLTRACE_KERNEL) || (is_in_user && CALLTRACE_USER) )
|
||||
#if defined(__x86_64__)
|
||||
Calltrace::Perform(regs->rbp);
|
||||
#elif defined(__i386__)
|
||||
Calltrace::Perform(regs->ebp);
|
||||
#else
|
||||
#error Please provide a calltrace implementation for your CPU.
|
||||
#endif
|
||||
|
||||
if ( RUN_DEBUGGER_ON_CRASH )
|
||||
Debugger::Run();
|
||||
|
||||
if ( is_in_kernel )
|
||||
{
|
||||
PanicF("Unhandled CPU Exception id %zu '%s' at ip=0x%zx "
|
||||
"(cr2=0x%p, err_code=0x%p)", regs->int_no, message,
|
||||
ip, regs->cr2, regs->err_code);
|
||||
}
|
||||
|
||||
Interrupt::Enable();
|
||||
|
||||
Log::PrintF("The current program (pid %ji %s) has crashed and was terminated:\n",
|
||||
(intmax_t) CurrentProcess()->pid, CurrentProcess()->program_image_path);
|
||||
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%p, err_code=0x%p)\n",
|
||||
message, ip, regs->cr2, regs->err_code);
|
||||
|
||||
// Exit the process with the right error code.
|
||||
// TODO: Sent a SIGINT, SIGBUS, or whatever instead.
|
||||
CurrentProcess()->Exit(139);
|
||||
|
||||
Interrupt::Disable();
|
||||
Signal::Dispatch(regs);
|
||||
}
|
||||
|
||||
void ISRHandler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
unsigned int int_no = regs->int_no;
|
||||
|
||||
if ( DEBUG_ISR )
|
||||
{
|
||||
Log::PrintF("ISR%u ", int_no);
|
||||
regs->LogRegisters();
|
||||
Log::Print("\n");
|
||||
}
|
||||
|
||||
// Run the desired interrupt handler.
|
||||
if ( int_no < 32 && int_no != 7 )
|
||||
CrashHandler(regs);
|
||||
else if ( interrupt_handlers[regs->int_no] != NULL )
|
||||
interrupt_handlers[int_no](regs, interrupt_handler_params[int_no]);
|
||||
}
|
||||
|
||||
void IRQHandler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
// TODO: IRQ 7 and 15 might be spurious and might need to be ignored.
|
||||
// See http://wiki.osdev.org/PIC for details (section Spurious IRQs).
|
||||
if ( regs->int_no == 32 + 7 || regs->int_no == 32 + 15 )
|
||||
return;
|
||||
|
||||
if ( DEBUG_IRQ )
|
||||
{
|
||||
Log::PrintF("IRQ%u ", regs->int_no-32);
|
||||
regs->LogRegisters();
|
||||
Log::Print("\n");
|
||||
}
|
||||
|
||||
unsigned int int_no = regs->int_no;
|
||||
|
||||
// Send an EOI (end of interrupt) signal to the PICs.
|
||||
if ( IRQ8 <= int_no )
|
||||
CPU::OutPortB(PIC_SLAVE, PIC_CMD_ENDINTR);
|
||||
CPU::OutPortB(PIC_MASTER, PIC_CMD_ENDINTR);
|
||||
|
||||
if ( interrupt_handlers[int_no] )
|
||||
interrupt_handlers[int_no](regs, interrupt_handler_params[int_no]);
|
||||
}
|
||||
|
||||
extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
if ( 32 <= regs->int_no && regs->int_no < 48 )
|
||||
IRQHandler(regs);
|
||||
else
|
||||
ISRHandler(regs);
|
||||
}
|
||||
|
||||
// TODO: This implementation is a bit hacky and can be optimized.
|
||||
|
||||
uint8_t* queue;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -187,12 +187,12 @@ void LogEndSwitch(Thread* current, const CPU::InterruptRegisters* regs)
|
|||
}
|
||||
}
|
||||
|
||||
static void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
{
|
||||
Switch(regs);
|
||||
}
|
||||
|
||||
static void ThreadExitCPU(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void ThreadExitCPU(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
{
|
||||
// Can't use floating point instructions from now.
|
||||
Float::NofityTaskExit(currentthread);
|
||||
|
@ -298,9 +298,6 @@ static int sys_usleep(size_t usecs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void yield_cpu_handler();
|
||||
extern "C" void thread_exit_handler();
|
||||
|
||||
void Init()
|
||||
{
|
||||
premagic = postmagic = SCHED_MAGIC;
|
||||
|
@ -317,13 +314,6 @@ void Init()
|
|||
firstsleepingthread = NULL;
|
||||
idlethread = NULL;
|
||||
|
||||
// Register our raw handler with user-space access. It calls our real
|
||||
// handler after common interrupt preparation stuff has occured.
|
||||
Interrupt::RegisterRawHandler(129, yield_cpu_handler, true);
|
||||
Interrupt::RegisterHandler(129, InterruptYieldCPU, NULL);
|
||||
Interrupt::RegisterRawHandler(132, thread_exit_handler, true);
|
||||
Interrupt::RegisterHandler(132, ThreadExitCPU, NULL);
|
||||
|
||||
Syscall::Register(SYSCALL_SLEEP, (void*) sys_sleep);
|
||||
Syscall::Register(SYSCALL_USLEEP, (void*) sys_usleep);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -127,10 +127,6 @@ void Return(CPU::InterruptRegisters* regs, void* /*user*/)
|
|||
|
||||
void Init()
|
||||
{
|
||||
Interrupt::RegisterRawHandler(130, isr130, true);
|
||||
Interrupt::RegisterHandler(130, Dispatch, NULL);
|
||||
Interrupt::RegisterRawHandler(131, isr131, true);
|
||||
Interrupt::RegisterHandler(131, Return, NULL);
|
||||
}
|
||||
|
||||
} // namespace Signal
|
||||
|
|
|
@ -27,371 +27,318 @@
|
|||
.global isr0
|
||||
.type isr0, @function
|
||||
isr0:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $0 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr1
|
||||
.type isr1, @function
|
||||
isr1:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $1 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr2
|
||||
.type isr2, @function
|
||||
isr2:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $2 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr3
|
||||
.type isr3, @function
|
||||
isr3:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $3 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr4
|
||||
.type isr4, @function
|
||||
isr4:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $4 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr5
|
||||
.type isr5, @function
|
||||
isr5:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $5 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr6
|
||||
.type isr6, @function
|
||||
isr6:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $6 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr7
|
||||
.type isr7, @function
|
||||
isr7:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $7 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr8
|
||||
.type isr8, @function
|
||||
isr8:
|
||||
cli
|
||||
# pushq $0 # err_code pushed by CPU
|
||||
pushq $8 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr9
|
||||
.type isr9, @function
|
||||
isr9:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $9 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr10
|
||||
.type isr10, @function
|
||||
isr10:
|
||||
cli
|
||||
# pushq $0 # err_code pushed by CPU
|
||||
pushq $10 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr11
|
||||
.type isr11, @function
|
||||
isr11:
|
||||
cli
|
||||
# pushq $0 # err_code pushed by CPU
|
||||
pushq $11 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr12
|
||||
.type isr12, @function
|
||||
isr12:
|
||||
cli
|
||||
# pushq $0 # err_code pushed by CPU
|
||||
pushq $12 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr13
|
||||
.type isr13, @function
|
||||
isr13:
|
||||
cli
|
||||
# pushq $0 # err_code pushed by CPU
|
||||
pushq $13 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr14
|
||||
.type isr14, @function
|
||||
isr14:
|
||||
cli
|
||||
# pushq $0 # err_code pushed by CPU
|
||||
pushq $14 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr15
|
||||
.type isr15, @function
|
||||
isr15:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $15 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr16
|
||||
.type isr16, @function
|
||||
isr16:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $16 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr17
|
||||
.type isr17, @function
|
||||
isr17:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $17 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr18
|
||||
.type isr18, @function
|
||||
isr18:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $18 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr19
|
||||
.type isr19, @function
|
||||
isr19:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $19 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr20
|
||||
.type isr20, @function
|
||||
isr20:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $20 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr21
|
||||
.type isr21, @function
|
||||
isr21:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $21 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr22
|
||||
.type isr22, @function
|
||||
isr22:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $22 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr23
|
||||
.type isr23, @function
|
||||
isr23:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $23 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr24
|
||||
.type isr24, @function
|
||||
isr24:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $24 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr25
|
||||
.type isr25, @function
|
||||
isr25:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $25 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr26
|
||||
.type isr26, @function
|
||||
isr26:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $26 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr27
|
||||
.type isr27, @function
|
||||
isr27:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $27 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr28
|
||||
.type isr28, @function
|
||||
isr28:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $28 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr29
|
||||
.type isr29, @function
|
||||
isr29:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $29 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr30
|
||||
.type isr30, @function
|
||||
isr30:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $30 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr31
|
||||
.type isr31, @function
|
||||
isr31:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $31 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr128
|
||||
.type isr128, @function
|
||||
isr128:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $128 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr130
|
||||
.type isr130, @function
|
||||
isr130:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $130 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr131
|
||||
.type isr131, @function
|
||||
isr131:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $131 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq0
|
||||
.type irq0, @function
|
||||
irq0:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $32 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq1
|
||||
.type irq1, @function
|
||||
irq1:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $33 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq2
|
||||
.type irq2, @function
|
||||
irq2:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $34 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq3
|
||||
.type irq3, @function
|
||||
irq3:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $35 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq4
|
||||
.type irq4, @function
|
||||
irq4:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $36 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq5
|
||||
.type irq5, @function
|
||||
irq5:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $37 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq6
|
||||
.type irq6, @function
|
||||
irq6:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $38 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq7
|
||||
.type irq7, @function
|
||||
irq7:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $39 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq8
|
||||
.type irq8, @function
|
||||
irq8:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $40 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq9
|
||||
.type irq9, @function
|
||||
irq9:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $41 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq10
|
||||
.type irq10, @function
|
||||
irq10:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $42 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq11
|
||||
.type irq11, @function
|
||||
irq11:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $43 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq12
|
||||
.type irq12, @function
|
||||
irq12:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $44 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq13
|
||||
.type irq13, @function
|
||||
irq13:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $45 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq14
|
||||
.type irq14, @function
|
||||
irq14:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $46 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq15
|
||||
.type irq15, @function
|
||||
irq15:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $47 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global yield_cpu_handler
|
||||
.type yield_cpu_handler, @function
|
||||
yield_cpu_handler:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $129 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global thread_exit_handler
|
||||
.type thread_exit_handler, @function
|
||||
thread_exit_handler:
|
||||
cli
|
||||
pushq $0 # err_code
|
||||
pushq $132 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
|
@ -494,15 +441,6 @@ interrupt_handler_null:
|
|||
iretq
|
||||
.size interrupt_handler_null, . - interrupt_handler_null
|
||||
|
||||
.global asm_interrupts_are_enabled
|
||||
.type asm_interrupts_are_enabled, @function
|
||||
asm_interrupts_are_enabled:
|
||||
pushfq
|
||||
popq %rax
|
||||
andq $0x000200, %rax # FLAGS_INTERRUPT
|
||||
retq
|
||||
.size asm_interrupts_are_enabled, . - asm_interrupts_are_enabled
|
||||
|
||||
.global load_registers
|
||||
.type load_registers, @function
|
||||
load_registers:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -27,11 +27,6 @@
|
|||
.section .text
|
||||
.type syscall_handler, @function
|
||||
syscall_handler:
|
||||
# The processor disabled interrupts during the int $0x80 instruction,
|
||||
# however Sortix system calls runs with interrupts enabled such that they
|
||||
# can be pre-empted.
|
||||
sti
|
||||
|
||||
movl $0, global_errno # Reset errno
|
||||
|
||||
pushq %rbp
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -30,52 +30,49 @@
|
|||
namespace Sortix {
|
||||
namespace IDT {
|
||||
|
||||
struct idt_entry
|
||||
{
|
||||
uint16_t handler_low;
|
||||
uint16_t sel;
|
||||
uint8_t reserved0;
|
||||
uint8_t flags;
|
||||
uint16_t handler_high;
|
||||
#if defined(__x86_64__)
|
||||
uint32_t handler_highest;
|
||||
uint32_t reserved1;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct idt_ptr
|
||||
{
|
||||
uint16_t limit;
|
||||
#if defined(__x86_64__)
|
||||
uint64_t idt_ptr;
|
||||
#else
|
||||
uint32_t idt_ptr;
|
||||
#endif
|
||||
} __attribute__((packed));
|
||||
|
||||
static struct idt_entry idt_entries[256];
|
||||
|
||||
void Init()
|
||||
{
|
||||
volatile struct idt_ptr ptr;
|
||||
ptr.limit = sizeof(idt_entries) - 1;
|
||||
ptr.idt_ptr = (unsigned long) &idt_entries;
|
||||
asm volatile ("lidt (%0)" : : "r"(&ptr));
|
||||
memset(&idt_entries, 0, sizeof(idt_entries));
|
||||
Set(idt_entries, 256);
|
||||
}
|
||||
|
||||
void SetEntry(uint8_t num, uintptr_t handler, uint16_t sel, uint8_t flags)
|
||||
void Set(struct idt_entry* table, size_t length)
|
||||
{
|
||||
idt_entries[num].flags = flags;
|
||||
idt_entries[num].reserved0 = 0;
|
||||
idt_entries[num].sel = sel;
|
||||
idt_entries[num].handler_low = handler >> 0 & 0xFFFF;
|
||||
idt_entries[num].handler_high = handler >> 16 & 0xFFFF;
|
||||
size_t limit = sizeof(idt_entry) * length - 1;
|
||||
#if defined(__x86_64__)
|
||||
idt_entries[num].handler_highest = handler >> 32 & 0xFFFFFFFFU;
|
||||
idt_entries[num].reserved1 = 0;
|
||||
asm volatile ("subq $10, %%rsp\n\t"
|
||||
"movw %w0, 0(%%rsp)\n\t"
|
||||
"movq %1, 2(%%rsp)\n\t"
|
||||
"lidt (%%rsp)\n\t"
|
||||
"addq $10, %%rsp" : : "rN"(limit), "r"(table));
|
||||
#else
|
||||
asm volatile ("subl $6, %%esp\n\t"
|
||||
"movw %w0, 0(%%esp)\n\t"
|
||||
"movl %1, 2(%%esp)\n\t"
|
||||
"lidt (%%esp)\n\t"
|
||||
"addl $6, %%esp" : : "rN"(limit), "r"(table));
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetEntry(struct idt_entry* entry, uintptr_t handler, uint16_t selector, uint8_t flags, uint8_t ist)
|
||||
{
|
||||
entry->flags = flags;
|
||||
entry->ist = ist;
|
||||
entry->selector = selector;
|
||||
entry->handler_low = handler >> 0 & 0xFFFF;
|
||||
entry->handler_high = handler >> 16 & 0xFFFF;
|
||||
#if defined(__x86_64__)
|
||||
entry->handler_highest = handler >> 32 & 0xFFFFFFFFU;
|
||||
entry->reserved1 = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetEntry(uint8_t num, uintptr_t handler, uint16_t selector, uint8_t flags, uint8_t ist)
|
||||
{
|
||||
SetEntry(idt_entries + num, handler, selector, flags, ist);
|
||||
}
|
||||
|
||||
} // namespace IDT
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -25,12 +25,36 @@
|
|||
#ifndef SORTIX_X86_FAMILY_IDT_H
|
||||
#define SORTIX_X86_FAMILY_IDT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Sortix {
|
||||
namespace IDT {
|
||||
|
||||
void Init();
|
||||
void SetEntry(uint8_t num, uintptr_t handler, uint16_t sel, uint8_t flags);
|
||||
void Flush();
|
||||
struct idt_entry
|
||||
{
|
||||
uint16_t handler_low;
|
||||
uint16_t selector;
|
||||
uint8_t ist;
|
||||
uint8_t flags;
|
||||
uint16_t handler_high;
|
||||
#if defined(__x86_64__)
|
||||
uint32_t handler_highest;
|
||||
uint32_t reserved1;
|
||||
#endif
|
||||
};
|
||||
|
||||
static const uint8_t FLAG_PRESENT = 1 << 7;
|
||||
static const uint8_t FLAG_DPL_SHIFT = 5;
|
||||
static const uint8_t FLAG_DPL_BITS = 2;
|
||||
static const uint8_t FLAG_TYPE_SHIFT = 0;
|
||||
static const uint8_t FLAG_TYPE_BITS = 4;
|
||||
|
||||
static const uint8_t TYPE_INTERRUPT = 0xE;
|
||||
static const uint8_t TYPE_TRAP = 0xF;
|
||||
|
||||
void Set(struct idt_entry* table, size_t length);
|
||||
void SetEntry(struct idt_entry* entry, uintptr_t handler, uint16_t selector,
|
||||
uint8_t flags, uint8_t ist);
|
||||
|
||||
} // namespace IDT
|
||||
} // namespace Sortix
|
||||
|
|
355
kernel/x86-family/interrupt.cpp
Normal file
355
kernel/x86-family/interrupt.cpp
Normal file
|
@ -0,0 +1,355 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix 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 General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
x86-family/interrupt.cpp
|
||||
Interrupt support for i386 and x86_64 systems.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/kernel/calltrace.h>
|
||||
#include <sortix/kernel/cpu.h>
|
||||
#include <sortix/kernel/debugger.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/kernel.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/scheduler.h>
|
||||
#include <sortix/kernel/signal.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
|
||||
#include "idt.h"
|
||||
#include "pic.h"
|
||||
|
||||
extern "C" void isr0();
|
||||
extern "C" void isr1();
|
||||
extern "C" void isr2();
|
||||
extern "C" void isr3();
|
||||
extern "C" void isr4();
|
||||
extern "C" void isr5();
|
||||
extern "C" void isr6();
|
||||
extern "C" void isr7();
|
||||
extern "C" void isr8();
|
||||
extern "C" void isr9();
|
||||
extern "C" void isr10();
|
||||
extern "C" void isr11();
|
||||
extern "C" void isr12();
|
||||
extern "C" void isr13();
|
||||
extern "C" void isr14();
|
||||
extern "C" void isr15();
|
||||
extern "C" void isr16();
|
||||
extern "C" void isr17();
|
||||
extern "C" void isr18();
|
||||
extern "C" void isr19();
|
||||
extern "C" void isr20();
|
||||
extern "C" void isr21();
|
||||
extern "C" void isr22();
|
||||
extern "C" void isr23();
|
||||
extern "C" void isr24();
|
||||
extern "C" void isr25();
|
||||
extern "C" void isr26();
|
||||
extern "C" void isr27();
|
||||
extern "C" void isr28();
|
||||
extern "C" void isr29();
|
||||
extern "C" void isr30();
|
||||
extern "C" void isr31();
|
||||
extern "C" void isr128();
|
||||
extern "C" void isr130();
|
||||
extern "C" void isr131();
|
||||
extern "C" void irq0();
|
||||
extern "C" void irq1();
|
||||
extern "C" void irq2();
|
||||
extern "C" void irq3();
|
||||
extern "C" void irq4();
|
||||
extern "C" void irq5();
|
||||
extern "C" void irq6();
|
||||
extern "C" void irq7();
|
||||
extern "C" void irq8();
|
||||
extern "C" void irq9();
|
||||
extern "C" void irq10();
|
||||
extern "C" void irq11();
|
||||
extern "C" void irq12();
|
||||
extern "C" void irq13();
|
||||
extern "C" void irq14();
|
||||
extern "C" void irq15();
|
||||
extern "C" void interrupt_handler_null();
|
||||
extern "C" void syscall_handler();
|
||||
extern "C" void yield_cpu_handler();
|
||||
extern "C" void thread_exit_handler();
|
||||
|
||||
namespace Sortix {
|
||||
namespace Interrupt {
|
||||
|
||||
extern "C" { unsigned long asm_is_cpu_interrupted = 0; }
|
||||
|
||||
const bool CALLTRACE_KERNEL = false;
|
||||
const bool CALLTRACE_USER = false;
|
||||
const bool RUN_DEBUGGER_ON_KERNEL_CRASH = false;
|
||||
const bool RUN_DEBUGGER_ON_USER_CRASH = false;
|
||||
|
||||
const size_t NUM_KNOWN_EXCEPTIONS = 20;
|
||||
const char* exception_names[] =
|
||||
{
|
||||
"Divide by zero", /* 0, 0x0 */
|
||||
"Debug", /* 1, 0x1 */
|
||||
"Non maskable interrupt", /* 2, 0x2 */
|
||||
"Breakpoint", /* 3, 0x3 */
|
||||
"Into detected overflow", /* 4, 0x4 */
|
||||
"Out of bounds", /* 5, 0x5 */
|
||||
"Invalid opcode", /* 6, 0x6 */
|
||||
"No coprocessor", /* 7, 0x7 */
|
||||
"Double fault", /* 8, 0x8 */
|
||||
"Coprocessor segment overrun", /* 9, 0x9 */
|
||||
"Bad TSS", /* 10, 0xA */
|
||||
"Segment not present", /* 11, 0xB */
|
||||
"Stack fault", /* 12, 0xC */
|
||||
"General protection fault", /* 13, 0xD */
|
||||
"Page fault", /* 14, 0xE */
|
||||
"Unknown interrupt", /* 15, 0xF */
|
||||
"Coprocessor fault", /* 16, 0x10 */
|
||||
"Alignment check", /* 17, 0x11 */
|
||||
"Machine check", /* 18, 0x12 */
|
||||
"SIMD Floating-Point", /* 19, 0x13 */
|
||||
};
|
||||
|
||||
const unsigned int NUM_INTERRUPTS = 256U;
|
||||
|
||||
static struct IDT::idt_entry interrupt_table[NUM_INTERRUPTS];
|
||||
static Handler interrupt_handlers[NUM_INTERRUPTS];
|
||||
static void* interrupt_handler_context[NUM_INTERRUPTS];
|
||||
|
||||
void RegisterHandler(unsigned int index,
|
||||
Interrupt::Handler handler,
|
||||
void* context)
|
||||
{
|
||||
assert(index < NUM_INTERRUPTS);
|
||||
interrupt_handlers[index] = handler;
|
||||
interrupt_handler_context[index] = context;
|
||||
}
|
||||
|
||||
static void RegisterRawHandler(unsigned int index,
|
||||
void (*handler)(void),
|
||||
bool userspace,
|
||||
bool preemptive)
|
||||
{
|
||||
assert(index < NUM_INTERRUPTS);
|
||||
addr_t handler_entry = (addr_t) handler;
|
||||
uint16_t selector = KCS;
|
||||
uint8_t rpl = userspace ? URPL : KRPL;
|
||||
uint8_t type = preemptive ? IDT::TYPE_TRAP : IDT::TYPE_INTERRUPT;
|
||||
uint8_t ist = 0;
|
||||
uint8_t flags = IDT::FLAG_PRESENT
|
||||
| type << IDT::FLAG_TYPE_SHIFT
|
||||
| rpl << IDT::FLAG_DPL_SHIFT;
|
||||
IDT::SetEntry(&interrupt_table[index], handler_entry, selector, flags, ist);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
// Initialize the interrupt table entries to the null interrupt handler.
|
||||
memset(&interrupt_table, 0, sizeof(interrupt_table));
|
||||
for ( unsigned int i = 0; i < NUM_INTERRUPTS; i++ )
|
||||
{
|
||||
interrupt_handlers[i] = NULL;
|
||||
interrupt_handler_context[i] = NULL;
|
||||
RegisterRawHandler(i, interrupt_handler_null, false, false);
|
||||
}
|
||||
|
||||
// Remap the IRQ table on the PICs.
|
||||
PIC::ReprogramPIC();
|
||||
|
||||
RegisterRawHandler(0, isr0, false, false);
|
||||
RegisterRawHandler(1, isr1, false, false);
|
||||
RegisterRawHandler(2, isr2, false, false);
|
||||
RegisterRawHandler(3, isr3, false, false);
|
||||
RegisterRawHandler(4, isr4, false, false);
|
||||
RegisterRawHandler(5, isr5, false, false);
|
||||
RegisterRawHandler(6, isr6, false, false);
|
||||
RegisterRawHandler(7, isr7, false, false);
|
||||
RegisterRawHandler(8, isr8, false, false);
|
||||
RegisterRawHandler(9, isr9, false, false);
|
||||
RegisterRawHandler(10, isr10, false, false);
|
||||
RegisterRawHandler(11, isr11, false, false);
|
||||
RegisterRawHandler(12, isr12, false, false);
|
||||
RegisterRawHandler(13, isr13, false, false);
|
||||
RegisterRawHandler(14, isr14, false, false);
|
||||
RegisterRawHandler(15, isr15, false, false);
|
||||
RegisterRawHandler(16, isr16, false, false);
|
||||
RegisterRawHandler(17, isr17, false, false);
|
||||
RegisterRawHandler(18, isr18, false, false);
|
||||
RegisterRawHandler(19, isr19, false, false);
|
||||
RegisterRawHandler(20, isr20, false, false);
|
||||
RegisterRawHandler(21, isr21, false, false);
|
||||
RegisterRawHandler(22, isr22, false, false);
|
||||
RegisterRawHandler(23, isr23, false, false);
|
||||
RegisterRawHandler(24, isr24, false, false);
|
||||
RegisterRawHandler(25, isr25, false, false);
|
||||
RegisterRawHandler(26, isr26, false, false);
|
||||
RegisterRawHandler(27, isr27, false, false);
|
||||
RegisterRawHandler(28, isr28, false, false);
|
||||
RegisterRawHandler(29, isr29, false, false);
|
||||
RegisterRawHandler(30, isr30, false, false);
|
||||
RegisterRawHandler(31, isr31, false, false);
|
||||
RegisterRawHandler(32, irq0, false, false);
|
||||
RegisterRawHandler(33, irq1, false, false);
|
||||
RegisterRawHandler(34, irq2, false, false);
|
||||
RegisterRawHandler(35, irq3, false, false);
|
||||
RegisterRawHandler(36, irq4, false, false);
|
||||
RegisterRawHandler(37, irq5, false, false);
|
||||
RegisterRawHandler(38, irq6, false, false);
|
||||
RegisterRawHandler(39, irq7, false, false);
|
||||
RegisterRawHandler(40, irq8, false, false);
|
||||
RegisterRawHandler(41, irq9, false, false);
|
||||
RegisterRawHandler(42, irq10, false, false);
|
||||
RegisterRawHandler(43, irq11, false, false);
|
||||
RegisterRawHandler(44, irq12, false, false);
|
||||
RegisterRawHandler(45, irq13, false, false);
|
||||
RegisterRawHandler(46, irq14, false, false);
|
||||
RegisterRawHandler(47, irq15, false, false);
|
||||
RegisterRawHandler(128, syscall_handler, true, true);
|
||||
RegisterRawHandler(129, yield_cpu_handler, true, false);
|
||||
RegisterRawHandler(130, isr130, true, false);
|
||||
RegisterRawHandler(131, isr131, true, false);
|
||||
RegisterRawHandler(132, thread_exit_handler, true, false);
|
||||
|
||||
RegisterHandler(129, Scheduler::InterruptYieldCPU, NULL);
|
||||
RegisterHandler(130, Signal::Dispatch, NULL);
|
||||
RegisterHandler(131, Signal::Return, NULL);
|
||||
RegisterHandler(132, Scheduler::ThreadExitCPU, NULL);
|
||||
|
||||
IDT::Set(interrupt_table, NUM_INTERRUPTS);
|
||||
|
||||
Interrupt::Enable();
|
||||
}
|
||||
|
||||
const char* ExceptionName(const CPU::InterruptRegisters* regs)
|
||||
{
|
||||
if ( regs->int_no < NUM_KNOWN_EXCEPTIONS )
|
||||
return exception_names[regs->int_no];
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
uintptr_t ExceptionLocation(const CPU::InterruptRegisters* regs)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
return regs->rip;
|
||||
#elif defined(__i386__)
|
||||
return regs->eip;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CrashCalltrace(const CPU::InterruptRegisters* regs)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
Calltrace::Perform(regs->rbp);
|
||||
#elif defined(__i386__)
|
||||
Calltrace::Perform(regs->ebp);
|
||||
#else
|
||||
#warning "Please provide a calltrace implementation for your CPU."
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
void KernelCrashHandler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
CurrentThread()->SaveRegisters(regs);
|
||||
|
||||
// Walk and print the stack frames if this is a debug build.
|
||||
if ( CALLTRACE_KERNEL )
|
||||
CrashCalltrace(regs);
|
||||
|
||||
// Possibly switch to the kernel debugger in event of a crash.
|
||||
if ( RUN_DEBUGGER_ON_KERNEL_CRASH )
|
||||
Debugger::Run();
|
||||
|
||||
// Panic the kernel with a diagnostic message.
|
||||
PanicF("Unhandled CPU Exception id %zu `%s' at ip=0x%zx (cr2=0x%zx, "
|
||||
"err_code=0x%zx)", regs->int_no, ExceptionName(regs),
|
||||
ExceptionLocation(regs), regs->cr2, regs->err_code);
|
||||
}
|
||||
|
||||
void UserCrashHandler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
CurrentThread()->SaveRegisters(regs);
|
||||
|
||||
// Execute this crash handler with preemption on.
|
||||
Interrupt::Enable();
|
||||
|
||||
// Walk and print the stack frames if this is a debug build.
|
||||
if ( CALLTRACE_USER )
|
||||
CrashCalltrace(regs);
|
||||
|
||||
// Possibly switch to the kernel debugger in event of a crash.
|
||||
if ( RUN_DEBUGGER_ON_USER_CRASH )
|
||||
Debugger::Run();
|
||||
|
||||
// Issue a diagnostic message to the kernel log concerning the crash.
|
||||
Log::PrintF("The current process (pid %ji `%s') crashed and was terminated:\n",
|
||||
(intmax_t) CurrentProcess()->pid, CurrentProcess()->program_image_path);
|
||||
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%zx, err_code=0x%zx)\n",
|
||||
ExceptionName(regs), ExceptionLocation(regs), regs->cr2,
|
||||
regs->err_code);
|
||||
|
||||
// Exit the process with the right error code.
|
||||
// TODO: Send a SIGINT, SIGBUS, or whatever instead.
|
||||
CurrentProcess()->Exit(139);
|
||||
|
||||
// TODO: Is it strictly needed or even desirable to disable preemption here?
|
||||
Interrupt::Disable();
|
||||
|
||||
// Deliver signals to this thread so it can exit correctly.
|
||||
Signal::Dispatch(regs);
|
||||
}
|
||||
|
||||
extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
unsigned int int_no = regs->int_no;
|
||||
|
||||
// IRQ 7 and 15 might be spurious and might need to be ignored.
|
||||
if ( int_no == IRQ7 && !(PIC::ReadISR() & (1 << 7)) )
|
||||
return;
|
||||
if ( int_no == IRQ15 && !(PIC::ReadISR() & (1 << 15)) )
|
||||
{
|
||||
PIC::SendMasterEOI();
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_in_kernel = (regs->cs & 0x3) == KRPL;
|
||||
bool is_in_user = !is_in_kernel;
|
||||
bool is_crash = int_no < 32 && int_no != 7;
|
||||
|
||||
// Invoke the appropriate interrupt handler.
|
||||
if ( is_crash && is_in_kernel )
|
||||
KernelCrashHandler(regs);
|
||||
else if ( is_crash && is_in_user )
|
||||
UserCrashHandler(regs);
|
||||
else if ( interrupt_handlers[int_no] )
|
||||
interrupt_handlers[int_no](regs, interrupt_handler_context[int_no]);
|
||||
|
||||
// Send an end of interrupt signal to the PICs if we got an IRQ.
|
||||
if ( IRQ0 <= int_no && int_no <= IRQ15 )
|
||||
PIC::SendEOI(int_no - IRQ0);
|
||||
}
|
||||
|
||||
} // namespace Interrupt
|
||||
} // namespace Sortix
|
122
kernel/x86-family/pic.cpp
Normal file
122
kernel/x86-family/pic.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix 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 General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
x86-family/pic.cpp
|
||||
Driver for the Programmable Interrupt Controller.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sortix/kernel/cpu.h>
|
||||
#include <sortix/kernel/kernel.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
|
||||
#include "pic.h"
|
||||
|
||||
namespace Sortix {
|
||||
namespace PIC {
|
||||
|
||||
const uint16_t PIC_MASTER = 0x20;
|
||||
const uint16_t PIC_SLAVE = 0xA0;
|
||||
const uint16_t PIC_COMMAND = 0x00;
|
||||
const uint16_t PIC_DATA = 0x01;
|
||||
const uint8_t PIC_CMD_ENDINTR = 0x20;
|
||||
const uint8_t PIC_ICW1_ICW4 = 0x01; // ICW4 (not) needed
|
||||
const uint8_t PIC_ICW1_SINGLE = 0x02; // Single (cascade) mode
|
||||
const uint8_t PIC_ICW1_INTERVAL4 = 0x04; // Call address interval 4 (8)
|
||||
const uint8_t PIC_ICW1_LEVEL = 0x08; // Level triggered (edge) mode
|
||||
const uint8_t PIC_CMD_INIT = 0x10;
|
||||
const uint8_t PIC_MODE_8086 = 0x01; // 8086/88 (MCS-80/85) mode
|
||||
const uint8_t PIC_MODE_AUTO = 0x02; // Auto (normal) EOI
|
||||
const uint8_t PIC_MODE_BUF_SLAVE = 0x08; // Buffered mode/slave
|
||||
const uint8_t PIC_MODE_BUF_MASTER = 0x0C; // Buffered mode/master
|
||||
const uint8_t PIC_MODE_SFNM = 0x10; // Special fully nested (not)
|
||||
const uint8_t PIC_READ_IRR = 0x0A;
|
||||
const uint8_t PIC_READ_ISR = 0x0B;
|
||||
|
||||
static uint16_t ReadRegister(uint8_t ocw3)
|
||||
{
|
||||
CPU::OutPortB(PIC_MASTER + PIC_COMMAND, ocw3);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, ocw3);
|
||||
return CPU::InPortB(PIC_MASTER + PIC_COMMAND) << 0 |
|
||||
CPU::InPortB(PIC_SLAVE + PIC_COMMAND) << 8;
|
||||
}
|
||||
|
||||
uint16_t ReadIRR()
|
||||
{
|
||||
return ReadRegister(PIC_READ_IRR);
|
||||
}
|
||||
|
||||
uint16_t ReadISR()
|
||||
{
|
||||
return ReadRegister(PIC_READ_ISR);
|
||||
}
|
||||
|
||||
extern "C" void ReprogramPIC()
|
||||
{
|
||||
uint8_t master_mask = 0;
|
||||
uint8_t slave_mask = 0;
|
||||
CPU::OutPortB(PIC_MASTER + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, Interrupt::IRQ0);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, Interrupt::IRQ8);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x04); // Slave PIC at IRQ2
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x02); // Cascade Identity
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, master_mask);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, slave_mask);
|
||||
}
|
||||
|
||||
extern "C" void DeprogramPIC()
|
||||
{
|
||||
uint8_t master_mask = 0;
|
||||
uint8_t slave_mask = 0;
|
||||
CPU::OutPortB(PIC_MASTER + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x08);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x70);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x04); // Slave PIC at IRQ2
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x02); // Cascade Identity
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, master_mask);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, slave_mask);
|
||||
}
|
||||
|
||||
void SendMasterEOI()
|
||||
{
|
||||
CPU::OutPortB(PIC_MASTER, PIC_CMD_ENDINTR);
|
||||
}
|
||||
|
||||
void SendSlaveEOI()
|
||||
{
|
||||
CPU::OutPortB(PIC_SLAVE, PIC_CMD_ENDINTR);
|
||||
}
|
||||
|
||||
void SendEOI(unsigned int irq)
|
||||
{
|
||||
if ( 8 <= irq )
|
||||
SendSlaveEOI();
|
||||
SendMasterEOI();
|
||||
}
|
||||
|
||||
} // namespace PIC
|
||||
} // namespace Sortix
|
43
kernel/x86-family/pic.h
Normal file
43
kernel/x86-family/pic.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix 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 General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
x86-family/pic.h
|
||||
Driver for the Programmable Interrupt Controller.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_X86_FAMILY_PIC_H
|
||||
#define SORTIX_X86_FAMILY_PIC_H
|
||||
|
||||
namespace Sortix {
|
||||
namespace PIC {
|
||||
|
||||
uint16_t ReadIRR();
|
||||
uint16_t ReadISR();
|
||||
bool IsSpuriousIRQ(unsigned int irq);
|
||||
extern "C" void ReprogramPIC();
|
||||
extern "C" void DeprogramPIC();
|
||||
void SendMasterEOI();
|
||||
void SendSlaveEOI();
|
||||
void SendEOI(unsigned int irq);
|
||||
|
||||
} // namespace PIC
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -27,371 +27,318 @@
|
|||
.global isr0
|
||||
.type isr0, @function
|
||||
isr0:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $0 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr1
|
||||
.type isr1, @function
|
||||
isr1:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $1 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr2
|
||||
.type isr2, @function
|
||||
isr2:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $2 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr3
|
||||
.type isr3, @function
|
||||
isr3:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $3 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr4
|
||||
.type isr4, @function
|
||||
isr4:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $4 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr5
|
||||
.type isr5, @function
|
||||
isr5:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $5 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr6
|
||||
.type isr6, @function
|
||||
isr6:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $6 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr7
|
||||
.type isr7, @function
|
||||
isr7:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $7 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr8
|
||||
.type isr8, @function
|
||||
isr8:
|
||||
cli
|
||||
# pushl $0 # err_code pushed by CPU
|
||||
pushl $8 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr9
|
||||
.type isr9, @function
|
||||
isr9:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $9 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr10
|
||||
.type isr10, @function
|
||||
isr10:
|
||||
cli
|
||||
# pushl $0 # err_code pushed by CPU
|
||||
pushl $10 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr11
|
||||
.type isr11, @function
|
||||
isr11:
|
||||
cli
|
||||
# pushl $0 # err_code pushed by CPU
|
||||
pushl $11 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr12
|
||||
.type isr12, @function
|
||||
isr12:
|
||||
cli
|
||||
# pushl $0 # err_code pushed by CPU
|
||||
pushl $12 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr13
|
||||
.type isr13, @function
|
||||
isr13:
|
||||
cli
|
||||
# pushl $0 # err_code pushed by CPU
|
||||
pushl $13 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr14
|
||||
.type isr14, @function
|
||||
isr14:
|
||||
cli
|
||||
# pushl $0 # err_code pushed by CPU
|
||||
pushl $14 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr15
|
||||
.type isr15, @function
|
||||
isr15:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $15 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr16
|
||||
.type isr16, @function
|
||||
isr16:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $16 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr17
|
||||
.type isr17, @function
|
||||
isr17:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $17 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr18
|
||||
.type isr18, @function
|
||||
isr18:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $18 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr19
|
||||
.type isr19, @function
|
||||
isr19:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $19 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr20
|
||||
.type isr20, @function
|
||||
isr20:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $20 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr21
|
||||
.type isr21, @function
|
||||
isr21:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $21 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr22
|
||||
.type isr22, @function
|
||||
isr22:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $22 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr23
|
||||
.type isr23, @function
|
||||
isr23:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $23 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr24
|
||||
.type isr24, @function
|
||||
isr24:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $24 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr25
|
||||
.type isr25, @function
|
||||
isr25:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $25 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr26
|
||||
.type isr26, @function
|
||||
isr26:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $26 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr27
|
||||
.type isr27, @function
|
||||
isr27:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $27 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr28
|
||||
.type isr28, @function
|
||||
isr28:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $28 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr29
|
||||
.type isr29, @function
|
||||
isr29:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $29 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr30
|
||||
.type isr30, @function
|
||||
isr30:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $30 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr31
|
||||
.type isr31, @function
|
||||
isr31:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $31 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr128
|
||||
.type isr128, @function
|
||||
isr128:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $128 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr130
|
||||
.type isr130, @function
|
||||
isr130:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $130 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global isr131
|
||||
.type isr131, @function
|
||||
isr131:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $131 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq0
|
||||
.type irq0, @function
|
||||
irq0:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $32 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq1
|
||||
.type irq1, @function
|
||||
irq1:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $33 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq2
|
||||
.type irq2, @function
|
||||
irq2:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $34 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq3
|
||||
.type irq3, @function
|
||||
irq3:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $35 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq4
|
||||
.type irq4, @function
|
||||
irq4:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $36 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq5
|
||||
.type irq5, @function
|
||||
irq5:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $37 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq6
|
||||
.type irq6, @function
|
||||
irq6:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $38 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq7
|
||||
.type irq7, @function
|
||||
irq7:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $39 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq8
|
||||
.type irq8, @function
|
||||
irq8:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $40 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq9
|
||||
.type irq9, @function
|
||||
irq9:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $41 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq10
|
||||
.type irq10, @function
|
||||
irq10:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $42 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq11
|
||||
.type irq11, @function
|
||||
irq11:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $43 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq12
|
||||
.type irq12, @function
|
||||
irq12:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $44 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq13
|
||||
.type irq13, @function
|
||||
irq13:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $45 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq14
|
||||
.type irq14, @function
|
||||
irq14:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $46 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global irq15
|
||||
.type irq15, @function
|
||||
irq15:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $47 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global yield_cpu_handler
|
||||
.type yield_cpu_handler, @function
|
||||
yield_cpu_handler:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $129 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
.global thread_exit_handler
|
||||
.type thread_exit_handler, @function
|
||||
thread_exit_handler:
|
||||
cli
|
||||
pushl $0 # err_code
|
||||
pushl $132 # int_no
|
||||
jmp interrupt_handler_prepare
|
||||
|
@ -580,15 +527,6 @@ interrupt_handler_null:
|
|||
iret
|
||||
.size interrupt_handler_null, . - interrupt_handler_null
|
||||
|
||||
.global asm_interrupts_are_enabled
|
||||
.type asm_interrupts_are_enabled, @function
|
||||
asm_interrupts_are_enabled:
|
||||
pushfl
|
||||
popl %eax
|
||||
andl $0x000200, %eax # FLAGS_INTERRUPT
|
||||
retl
|
||||
.size asm_interrupts_are_enabled, . - asm_interrupts_are_enabled
|
||||
|
||||
.global load_registers
|
||||
.type load_registers, @function
|
||||
load_registers:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -27,11 +27,6 @@
|
|||
.section .text
|
||||
.type syscall_handler, @function
|
||||
syscall_handler:
|
||||
# The processor disabled interrupts during the int $0x80 instruction,
|
||||
# however Sortix system calls runs with interrupts enabled such that they
|
||||
# can be pre-empted.
|
||||
sti
|
||||
|
||||
movl $0, global_errno # Reset errno
|
||||
|
||||
pushl %ebp
|
||||
|
|
Loading…
Add table
Reference in a new issue