/// <summary> /// Initializes the GDT /// </summary> public static unsafe void Init() { // Allocate data m_entries = new GDT_Entry[6]; m_ptr = new GDT_Pointer(); // Set GDT table pointer m_ptr.Limit = (ushort)((6 * sizeof(GDT_Entry)) - 1); fixed(GDT_Entry *ptr = m_entries) { m_ptr.BaseAddress = (uint)ptr; } // NULL segment setEntry(0, 0, 0, 0, 0); // Kernel code segment setEntry(1, 0, 0xFFFFFFFF, (int)GDT_Data.ER | (int)GDTFlags.DescriptorCodeOrData | Privilege(0) | (int)GDTFlags.Present, (int)GDTFlags.Size32 | (int)GDTFlags.Granularity); // Kernel data segment setEntry(2, 0, 0xFFFFFFFF, (int)GDT_Data.RW | (int)GDTFlags.DescriptorCodeOrData | Privilege(0) | (int)GDTFlags.Present, (int)GDTFlags.Size32 | (int)GDTFlags.Granularity); // User code segment setEntry(3, 0, 0xFFFFFFFF, (int)GDT_Data.ER | (int)GDTFlags.DescriptorCodeOrData | Privilege(3) | (int)GDTFlags.Present, (int)GDTFlags.Size32 | (int)GDTFlags.Granularity); // User data segment setEntry(4, 0, 0xFFFFFFFF, (int)GDT_Data.RW | (int)GDTFlags.DescriptorCodeOrData | Privilege(3) | (int)GDTFlags.Present, (int)GDTFlags.Size32 | (int)GDTFlags.Granularity); // TSS TSS_Entry = (TSS *)Heap.Alloc(sizeof(TSS)); setTSS(5, TSS_Entry); // Flush GDT fixed(GDT_Pointer *ptr = &m_ptr) { flushGDT(ptr); } // Flush TSS flushTSS(); }
/// <summary> /// Writes a TSS entry into the GDT /// </summary> /// <param name="num">The index of the corresponding GDT entry</param> /// <param name="tss">The TSS</param> private static unsafe void setTSS(int num, TSS *tss) { // Base and limit uint baseAddr = (uint)tss; uint limit = (uint)(baseAddr + sizeof(TSS)); // Set TSS // Kernel Data Selector = 0x10, Kernel Code Selector = 0x08 Memory.Memclear(tss, sizeof(TSS)); tss->SS0 = 0x10; tss->IOMap = (ushort)sizeof(TSS); tss->CS = 0x08; tss->DS = 0x10; tss->ES = 0x10; tss->FS = 0x10; tss->GS = 0x10; tss->SS = 0x10; // Add TSS descriptor to GDT setEntry(num, baseAddr, limit, (int)GDT_Data.EA | Privilege(3) | (int)GDTFlags.Present, 0); }
public static void Init() { //ExceptionMethods.ThePageFaultHandler = HandlePageFault; ActiveQueue.Name = "Active Queue"; InactiveQueue.Name = "Inactive Queue"; //Load first process and first thread #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Setting current process..."); #endif ProcessManager.CurrentProcess = (Process)ProcessManager.Processes[0]; #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Setting current thread..."); #endif ProcessManager.CurrentThread = (Thread)ProcessManager.CurrentProcess.Threads[0]; #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Setting current thread state..."); #endif ProcessManager.CurrentThread_State = ProcessManager.CurrentThread.State; //Init TSS #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Getting TSS pointer..."); #endif TSS *tss = GetTSSPointer(); #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Setting esp0..."); #endif tss->esp0 = (uint)ProcessManager.CurrentThread_State->KernelStackTop; #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Setting ss0..."); #endif //Note: KM CS is loaded from IDT entry on ring 3 -> 0 switch tss->ss0 = 0x10; //Kernel mode stack segment = KM Data segment (same for all processes) #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Setting cr3..."); #endif tss->cr3 = VirtMem.x86.GetCR3(); //Load Task Register #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Loading TR..."); #endif LoadTR(); //Enable timer #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Adding timer handler..."); #endif /*Multiply by 1000000 to get from ms to ns*/ Hardware.Devices.Timer.Default.RegisterHandler(OnTimerInterrupt, /* MSFreq * 1000000 */ 5000000, true, null); #if SCHEDULER_TRACE BasicConsole.WriteLine(" > Enabling process switching..."); #endif Interrupts.Interrupts.EnableProcessSwitching = true; //#if SCHEDULER_TRACE BasicConsole.WriteLine(" > Enabling scheduler..."); //#endif UpdateCountdown = UpdatePeriod; Initialised = true; Enable(); }