public static void ClockInterrupt(ref IDTStack stackSate) { Interlocked.Increment(ref clockTicks); if (!Enabled) { return; } // check if current thread should get more time var currentThreadID = GetCurrentThreadID(); var th = GetCurrentThread(); if (th != null) { if (th.Priority != 0) { if (th.Priority > 0) { if (++th.PriorityInterrupts <= th.Priority) { return; } } th.PriorityInterrupts = 0; } } // Save current stack state SaveThreadState(currentThreadID, ref stackSate); ScheduleNextThread(currentThreadID); }
/// <summary> /// Syscall interrupt handler. Dispatcher for every SysCall. /// </summary> private static void InterruptHandler(ref IDTStack stack, SysCallCallingType callingMethod) { var args = new SystemMessage { Target = (SysCallTarget)stack.EAX, Arg1 = stack.EBX, Arg2 = stack.ECX, Arg3 = stack.EDX, Arg4 = stack.ESI, Arg5 = stack.EDI, Arg6 = stack.EBP, }; var commandNum = GetCommandNum(args.Target); if (KConfig.Log.SysCall) { KernelMessage.WriteLine("Got SysCall cmd={0} arg1={1:X8} arg2={2:X8} arg3={3:X8} arg4={4:X8} arg5={5:X8} arg6={6:X8}", (uint)args.Target, args.Arg1, args.Arg2, args.Arg3, args.Arg4, args.Arg5, args.Arg6); } Scheduler.SaveThreadState(Scheduler.GetCurrentThread().ThreadID, ref stack); var info = Commands[commandNum]; if (info == null) { Panic.Error("Undefined SysCall"); } var ctx = new SysCallContext { CallingType = callingMethod, Debug = info.Debug, }; if (info.Debug) { KDebug.DumpStats(); Debug.Nop(); } var result = info.Handler(ref ctx, ref args); if (KConfig.Log.SysCall) { KernelMessage.WriteLine("Result of Syscall cmd={0}: {1:X8}", (uint)args.Target, result); } stack.EAX = result; }
/// <summary> /// Saves the current thread state, so we can switch to another thread. /// </summary> public static unsafe void SaveThreadState(int threadID, ref IDTStack stackState) { //Assert.True(threadID < MaxThreads, "SaveThreadState(): invalid thread id > max"); var stackStatePtr = (IDTStack *)Unsafe.AsPointer(ref stackState); var thread = Threads[threadID]; if (thread.Status != ThreadStatus.Running) { return; // New threads doesn't have a stack in use. Take the initial one. } //Assert.True(thread != null, "SaveThreadState(): thread id = null"); if (thread.User) { Assert.IsSet(thread.StackState, "thread.StackState is null"); *thread.StackState = *(IDTTaskStack *)stackStatePtr; } else { thread.StackState = (IDTTaskStack *)stackStatePtr; } if (KConfig.Log.TaskSwitch) { KernelMessage.Write("Task {0}: Stored ThreadState from {1:X8} stored at {2:X8}, EIP={3:X8}", (uint)threadID, (uint)stackStatePtr, (uint)thread.StackState, thread.StackState->Stack.EIP); if (thread.User) { KernelMessage.WriteLine(" ESP={0:X8}", thread.StackState->TASK_ESP); } else { KernelMessage.WriteLine(); } } }
/// <summary> /// Syscall interrupt handler for asynchronous calls. /// </summary> private static void ActionInterruptHandler(ref IDTStack stack) { InterruptHandler(ref stack, SysCallCallingType.Async); }
/// <summary> /// Entry point into the ISR (Interrupt Service Routine) /// </summary> /// <param name="stack">Pointer to the ISR stack</param> private static unsafe void ProcessInterrupt(ref IDTStack stack) { // Switch to Kernel segments ushort dataSelector = KnownSegments.KernelData; Native.SetSegments(dataSelector, dataSelector, KnownSegments.KernelThreadStorage, dataSelector, dataSelector); // Switch to Kernel Adresse space var block = (InterruptControlBlock *)Address.InterruptControlBlock; Native.SetCR3(block->KernelPageTableAddr); // Get the IRQ var irq = stack.Interrupt; // Get the pagetable address of the interrupted process uint pageTableAddr = 0; var thread = Scheduler.GetCurrentThread(); if (thread != null) { dataSelector = (ushort)thread.DataSelector; pageTableAddr = thread.Process.PageTable.GetPageTablePhysAddr(); } // If the IDTManager is not initialized yet or hard disabled, we return now if (!IDTManager.Enabled) { PIC.SendEndOfInterrupt(irq); return; } // Get interrupt info for the IRQ var interruptInfo = IDTManager.Handlers[irq]; if (KConfig.Log.Interrupts && interruptInfo.Trace && thread != null) { KernelMessage.WriteLine("Interrupt {0}, Thread {1}, EIP={2:X8} ESP={3:X8}", irq, (uint)thread.ThreadID, stack.EIP, stack.ESP); } // Some statistics IDTManager.RaisedCount++; if (interruptInfo.CountStatistcs) { IDTManager.RaisedCountCustom++; } if (KConfig.Log.Interrupts) { if (interruptInfo.Trace) { KernelMessage.WriteLine("Interrupt: {0}", irq); } var col = Screen.Column; var row = Screen.Row; Screen.Column = 0; Screen.Goto(2, 35); Screen.Write("Interrupts: "); Screen.Write(IDTManager.RaisedCount); Screen.Goto(3, 35); Screen.Write("IntNoClock: "); Screen.Write(IDTManager.RaisedCountCustom); Screen.Row = row; Screen.Column = col; } // This should never happen if (irq < 0 || irq > 255) { Panic.Error("Invalid Interrupt"); } // Invoke handlers if (interruptInfo.PreHandler != null) { interruptInfo.PreHandler(ref stack); } if (interruptInfo.Handler == null) { Panic.Error("Handler is null"); } else { } interruptInfo.Handler(ref stack); // Important! Otherwise we will get any more interrupts of this kind PIC.SendEndOfInterrupt(irq); // Switch to original address space if (pageTableAddr > 0) { Native.SetCR3(pageTableAddr); } // Switch to original segments Native.SetSegments(dataSelector, dataSelector, KnownSegments.UserThreadStorage, dataSelector, KnownSegments.KernelData); // ISR is completed. The upper ISR stub will re-enable interrupts and resume the original process }