summaryrefslogtreecommitdiff
path: root/kernel/interrupts.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/interrupts.c')
-rw-r--r--kernel/interrupts.c105
1 files changed, 87 insertions, 18 deletions
diff --git a/kernel/interrupts.c b/kernel/interrupts.c
index b7cdd74..8bc4f47 100644
--- a/kernel/interrupts.c
+++ b/kernel/interrupts.c
@@ -13,6 +13,7 @@
#include "apic.h"
#include "ringbuffer.h"
#include "compositor.h"
+#include "syscalls.h"
/** The size of our interrupts table */
#define INT_MAX 256 // 0-255
@@ -51,8 +52,37 @@ static void int_install_ir(int irq, uint16_t flags, uint16_t sel, void *addr)
}
/**
- * Register an interrupt handler for given irq number.
+ * Register an interrupt handler for a given irq number.
+ *
+ * Some general notes on interrupts
+ * (TODO: consider moving this somewehre else)
+ *
+ * 1) In case of a syscall (coming from userspace) the handler should:
+ * a) For a blocking call, set required params and call the scheduler!
+ * b) Otherweise call x86_sti() by itself as soon as possiblle to
+ * reenable interrupts.
+ *
+ * 2) In case of APIC Timer interrupt call the scheduler.
+ *
+ * 3) Keyboard, Mouse, E1000, PIT
+ * just push your stuff somewhere for later processing as fast as
+ * you can and reschedule to a kernel worker OR just iret.
+ *
+ * 4) IPI
+ * we use them to force rescheduling only now
+ * treated in the same way as a APIC Timer interrupt...
+ * TODO: NOT CALL THIS IPI!! since we send it only on same cpu now :P
+ *
+ * NOTE: apic_eoi() should be called in all cases except the syscalls,
+ * to signal the "end of interrupt" to the APIC.
+ *
+ * TODO: REMEMBER THAT WE WILL HAVE TO CHECK ALL OUR SYSCALL ARE REENTRANT!
+ * ALSO IN MULTICPU SETTINGS! (check the userspace wrappers as well!)
+ * EACH prog requires a sufficient kernel-stack as well! (check this!)
+ * WE CAN GUARD with spinlocks / disabling interrupts when really needed....
+ *
*/
+
void interrupt_register(uint32_t irq, uint32_t func_addr)
{
if(irq<128||irq>160)kpanic("irq number out of range!");
@@ -72,36 +102,75 @@ uint32_t interrupt_handler(uint32_t esp, uint32_t irq)
{
uint32_t (*f)(uint32_t esp)=handlers[irq];
esp=f(esp);
- apic_eoi();
+ if(irq!=INTERRUPT_SYSCALL)apic_eoi();
return esp;
}
- if(irq==INTERRUPT_APIC_TIMER)
+ if(irq==INTERRUPT_APIC_TIMER || irq==INTERRUPT_IPI)
{
- if(cpu==0)
- {
- compositor_wake2();
- scheduler_wake_all();
- scheduler_wake_worker(esp);
+ if(cpu==0) // thi
+ {
+ // limit compositor to APIC_TIMER freq.(60hz?)
+ if(irq==INTERRUPT_APIC_TIMER)compositor_wake2();
}
- }
- if(irq==INTERRUPT_APIC_TIMER || irq==INTERRUPT_IPI)
- {
- esp=scheduler_run(esp,-1);
+ esp=scheduler_run(esp,-1); // just schedule to next task
apic_eoi();
return esp;
}
if(irq==INTERRUPT_SYSCALL)
{
- apic_eoi();
+ int pid=task_get_current_pid();
+
uint32_t *stack;
- stack=esp;
- task_syscall(stack[11],stack[8],stack[10],stack[9]); //eax,ebx,ecx,edx
- scheduler_wake_worker(esp);
- esp=scheduler_run(esp,-1);
- return esp;
+ stack=esp;
+
+ // extract variables from stack
+ // (NOTE we pass them in some fucked up order,
+ // they were pushed via pusha!
+ uint32_t eax=stack[11];
+ uint32_t ebx=stack[8];
+ uint32_t ecx=stack[10];
+ uint32_t edx=stack[9];
+
+ // only chance to do somehting before we reenable interrupts!
+ syscall_generic_prep(eax,edx,ecx,ebx,pid);
+
+ // now we don't give a shit about gettting interrupted, yeah!
+ // this is guaranteed to cause heavy troubles... since we are
+ // not reentrant and do not guard anythin..
+
+ // keep brute force rescheduling till' we get through....
+ // TODO: implement some waiting queue and wake only if there
+ // is any chance this will not fail again and again and again..
+ // TODO: get rid of this big KERNEL LOCK
+ // it will also not work with SMP
+ while(true)
+ {
+ // x86_cli();
+ int ok=syscall_generic_test(eax,edx,ecx,ebx,pid);
+ // x86_sti();
+ if(ok)break;
+ else __asm__("int $0x81");
+ }
+
+ // uff, once we got through we can do the syscall and get out
+ // of this place...
+ // x86_cli();
+ uint32_t ret=syscall_generic(eax,edx,ecx,ebx,pid);
+ // x86_sti();
+
+ stack[12]=0x1; // indicate with 0x1 we WANT to set a return
+ // value in ebx (0x0 will skip it)
+ stack[13]=ret; // and THIS is our return value!
+
+ #ifdef LOG_SYSCALLS
+ klog("syscall ret=0x%08X",ret);
+ #endif
+
+ //__asm__("int $0x81");
+ return esp; // return to asm interrupt handler... and iret.
}
kpanic("unhandled interrupt %d",irq);