diff --git a/kernel/Makefile b/kernel/Makefile
index 24128bbd..f97c4ca8 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -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 \
diff --git a/kernel/include/sortix/kernel/interrupt.h b/kernel/include/sortix/kernel/interrupt.h
index 5247c5f1..c6b681d0 100644
--- a/kernel/include/sortix/kernel/interrupt.h
+++ b/kernel/include/sortix/kernel/interrupt.h
@@ -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 .
sortix/kernel/interrupt.h
- High level interrupt service routines and interrupt request handlers.
+ High level interrupt services.
*******************************************************************************/
@@ -30,13 +30,17 @@
#include
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
diff --git a/kernel/include/sortix/kernel/scheduler.h b/kernel/include/sortix/kernel/scheduler.h
index f4972e77..7475e688 100644
--- a/kernel/include/sortix/kernel/scheduler.h
+++ b/kernel/include/sortix/kernel/scheduler.h
@@ -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
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
diff --git a/kernel/include/sortix/kernel/signal.h b/kernel/include/sortix/kernel/signal.h
index a70d4f00..98c05fbc 100644
--- a/kernel/include/sortix/kernel/signal.h
+++ b/kernel/include/sortix/kernel/signal.h
@@ -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.
diff --git a/kernel/include/sortix/kernel/syscall.h b/kernel/include/sortix/kernel/syscall.h
index fc7976cc..dfe06f13 100644
--- a/kernel/include/sortix/kernel/syscall.h
+++ b/kernel/include/sortix/kernel/syscall.h
@@ -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
diff --git a/kernel/interrupt.cpp b/kernel/interrupt.cpp
index 4cc1d53f..4fc28f89 100644
--- a/kernel/interrupt.cpp
+++ b/kernel/interrupt.cpp
@@ -18,7 +18,7 @@
Sortix. If not, see .
interrupt.cpp
- High level interrupt service routines and interrupt request handlers.
+ High level interrupt services.
*******************************************************************************/
@@ -37,292 +37,9 @@
#include
#include
-#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;
diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp
index feee120b..e72331bc 100644
--- a/kernel/scheduler.cpp
+++ b/kernel/scheduler.cpp
@@ -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);
}
diff --git a/kernel/signal.cpp b/kernel/signal.cpp
index 91f05358..bceb15d6 100644
--- a/kernel/signal.cpp
+++ b/kernel/signal.cpp
@@ -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
diff --git a/kernel/x64/interrupt.S b/kernel/x64/interrupt.S
index 1df22946..72aed0fa 100644
--- a/kernel/x64/interrupt.S
+++ b/kernel/x64/interrupt.S
@@ -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:
diff --git a/kernel/x64/syscall.S b/kernel/x64/syscall.S
index 05f87c1a..6b24bc83 100644
--- a/kernel/x64/syscall.S
+++ b/kernel/x64/syscall.S
@@ -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
diff --git a/kernel/x86-family/idt.cpp b/kernel/x86-family/idt.cpp
index d986e018..a1e32f98 100644
--- a/kernel/x86-family/idt.cpp
+++ b/kernel/x86-family/idt.cpp
@@ -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
diff --git a/kernel/x86-family/idt.h b/kernel/x86-family/idt.h
index aa6d6981..6ba8cfaf 100644
--- a/kernel/x86-family/idt.h
+++ b/kernel/x86-family/idt.h
@@ -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
+
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
diff --git a/kernel/x86-family/interrupt.cpp b/kernel/x86-family/interrupt.cpp
new file mode 100644
index 00000000..232d9918
--- /dev/null
+++ b/kernel/x86-family/interrupt.cpp
@@ -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 .
+
+ x86-family/interrupt.cpp
+ Interrupt support for i386 and x86_64 systems.
+
+*******************************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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
diff --git a/kernel/x86-family/pic.cpp b/kernel/x86-family/pic.cpp
new file mode 100644
index 00000000..029572e5
--- /dev/null
+++ b/kernel/x86-family/pic.cpp
@@ -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 .
+
+ x86-family/pic.cpp
+ Driver for the Programmable Interrupt Controller.
+
+*******************************************************************************/
+
+#include
+
+#include
+#include
+#include
+
+#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
diff --git a/kernel/x86-family/pic.h b/kernel/x86-family/pic.h
new file mode 100644
index 00000000..02b568f2
--- /dev/null
+++ b/kernel/x86-family/pic.h
@@ -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 .
+
+ 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
diff --git a/kernel/x86/interrupt.S b/kernel/x86/interrupt.S
index b58c5ff6..45380311 100644
--- a/kernel/x86/interrupt.S
+++ b/kernel/x86/interrupt.S
@@ -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:
diff --git a/kernel/x86/syscall.S b/kernel/x86/syscall.S
index 8f63f10a..e0d1ce38 100644
--- a/kernel/x86/syscall.S
+++ b/kernel/x86/syscall.S
@@ -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