/// <summary> /// Switch to a specific thread. /// This method will not return! /// </summary> public static unsafe void SwitchToThread(int threadID) { var thread = Threads[threadID]; var proc = thread.Process; if (KConfig.Log.TaskSwitch) { KernelMessage.WriteLine("Switching to Thread {0}. StackState: {1:X8}", threadID, (uint)thread.StackState); } //Assert.True(thread != null, "invalid thread id"); thread.Ticks++; SetThreadID(threadID); PIC.SendEndOfInterrupt((int)KnownInterrupt.ClockTimer); thread.Status = ThreadStatus.Running; if (thread.StackState == null) { DumpStats(); KernelMessage.WriteLine("threadID: {0}", threadID); Debug.Break(); } thread.StackState->Stack.EFLAGS |= X86_EFlags.InterruptEnableFlag; if (proc.PageTable != PageTable.KernelTable) { Debug.Nop(); } uint pageDirAddr = proc.PageTable.GetPageTablePhysAddr(); //KernelMessage.WriteLine("PageDirAddr: {0:X8}", pageDirAddr); uint stackStateAddr = (uint)thread.StackState; uint dataSelector = thread.DataSelector; if (!thread.User) { thread.StackState = null; // just to be sure } GDT.Tss->ESP0 = thread.KernelStackBottom; if (thread.Debug) { Native.Nop(); } GDT.SetThreadStorageSegmentBase(thread.ThreadLocalStorageBaseAddr); InterruptReturn(stackStateAddr, pageDirAddr, dataSelector, KnownSegments.UserThreadStorage); }
/// <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 }
/// <summary> /// Interrupts the handler. /// </summary> /// <param name="stackStatePointer">The stack state pointer.</param> private static unsafe void ProcessInterrupt(uint stackStatePointer) { ushort dataSelector = 0x10; Native.SetSegments(dataSelector, dataSelector, dataSelector, dataSelector, dataSelector); var block = (InterruptControlBlock *)Address.InterruptControlBlock; Native.SetCR3(block->KernelPageTableAddr); //KernelMessage.WriteLine("Interrupt occurred"); var stack = (IDTStack *)stackStatePointer; var irq = stack->Interrupt; uint pageTableAddr = 0; var thread = Scheduler.GetCurrentThread(); if (thread != null) { dataSelector = (ushort)thread.DataSelector; pageTableAddr = thread.Process.PageTable.GetPageTablePhysAddr(); } if (!IDTManager.Enabled) { PIC.SendEndOfInterrupt(irq); return; } 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, thread.ThreadID, stack->EIP, stack->ESP); } 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; } if (irq < 0 || irq > 255) { Panic.Error("Invalid Interrupt"); } if (interruptInfo.PreHandler != null) { interruptInfo.PreHandler(stack); } if (interruptInfo.Handler == null) { Panic.Error("Handler is null"); } else { } interruptInfo.Handler(stack); PIC.SendEndOfInterrupt(irq); if (pageTableAddr > 0) { Native.SetCR3(pageTableAddr); } Native.SetSegments(dataSelector, dataSelector, dataSelector, dataSelector, 0x10); }