From 6bef4e1fa0cebfa94cdad6b734a0c23d2c0da5af Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Sun, 27 Dec 2020 19:31:58 +0100 Subject: [PATCH 01/15] Add changes from @Og-Rok --- source/Cosmos.Core/INTs.cs | 4 + source/Cosmos.Core/Memory/Old/Old_Heap.cs | 23 +++ source/Cosmos.Core/ObjUtilities.cs | 19 +++ source/Cosmos.Core/Processing/Mutex.cs | 27 +++ .../Cosmos.Core/Processing/ProcessContext.cs | 154 ++++++++++++++++++ .../Processing/ProcessorScheduler.cs | 102 ++++++++++++ source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs | 91 +++++++---- source/Cosmos.Core_Asm/DelegateImpl.cs | 7 +- source/Cosmos.Core_Asm/MutexImpl.cs | 36 ++++ source/Cosmos.Core_Asm/ObjUtilitiesImpl.cs | 40 +++++ .../Cosmos.Core_Plugs/System/DelegateImpl.cs | 7 +- .../System/Threading/ThreadImpl.cs | 6 + source/Cosmos.HAL2/Global.cs | 16 +- source/Cosmos.System2/Thread.cs | 45 +++++ 14 files changed, 546 insertions(+), 31 deletions(-) create mode 100644 source/Cosmos.Core/ObjUtilities.cs create mode 100644 source/Cosmos.Core/Processing/Mutex.cs create mode 100644 source/Cosmos.Core/Processing/ProcessContext.cs create mode 100644 source/Cosmos.Core/Processing/ProcessorScheduler.cs create mode 100644 source/Cosmos.Core_Asm/MutexImpl.cs create mode 100644 source/Cosmos.Core_Asm/ObjUtilitiesImpl.cs create mode 100644 source/Cosmos.System2/Thread.cs diff --git a/source/Cosmos.Core/INTs.cs b/source/Cosmos.Core/INTs.cs index 38d26cd873..3bcd1585af 100644 --- a/source/Cosmos.Core/INTs.cs +++ b/source/Cosmos.Core/INTs.cs @@ -234,6 +234,8 @@ public struct IRQContext { [AsmMarker(AsmMarker.Type.Int_LastKnownAddress)] private static uint mLastKnownAddress; + public static uint mStackContext; + /// /// IRQ handlers. /// @@ -845,6 +847,8 @@ public static void Dummy() { HandleInterrupt_47(ref xCtx); HandleInterrupt_48(ref xCtx); HandleInterrupt_49(ref xCtx); + Processing.ProcessorScheduler.SwitchTask(); + Processing.ProcessorScheduler.EntryPoint(); } } } diff --git a/source/Cosmos.Core/Memory/Old/Old_Heap.cs b/source/Cosmos.Core/Memory/Old/Old_Heap.cs index c89fbd7eb9..11bca292c2 100644 --- a/source/Cosmos.Core/Memory/Old/Old_Heap.cs +++ b/source/Cosmos.Core/Memory/Old/Old_Heap.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Cosmos.Core; +using Cosmos.Core.Processing; using Cosmos.Debug.Kernel; namespace Cosmos.Core.Memory.Old @@ -19,6 +20,8 @@ public static unsafe class Heap private static uint mLastEntryIndex = 0u; + private static Mutex mMemeoryGate = new Mutex(); + private static bool mInitialized = false; private static void DoInitialize(uint aEndOfRam) @@ -59,6 +62,11 @@ public static uint MemAlloc(uint aLength) { EnsureIsInitialized(); + if (mMemeoryGate != null) + { + mMemeoryGate.Lock(); + } + DataLookupTable* xCurrentTable = GlobalSystemInfo.GlobalInformationTable->FirstDataLookupTable; DataLookupTable* xPreviousTable = null; uint xResult; @@ -81,6 +89,11 @@ public static uint MemAlloc(uint aLength) } } + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } + return xResult; } mLastTable = xPreviousTable; @@ -117,6 +130,12 @@ public static uint MemAlloc(uint aLength) } mLastTable = xNextTablePointer; mLastEntryIndex = 0; + + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } + return xResult; } finally @@ -129,6 +148,10 @@ public static uint MemAlloc(uint aLength) { //Debugger.DoSend(" Not enabling interrupts, because they weren't enabled yet!"); } + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } } } diff --git a/source/Cosmos.Core/ObjUtilities.cs b/source/Cosmos.Core/ObjUtilities.cs new file mode 100644 index 0000000000..0de530713f --- /dev/null +++ b/source/Cosmos.Core/ObjUtilities.cs @@ -0,0 +1,19 @@ +using IL2CPU.API.Attribs; +using System; + +namespace Cosmos.Core +{ + public static unsafe class ObjUtilities + { + public static uint GetPointer(Delegate aVal) + { + return (uint)aVal.GetHashCode(); + } + + [PlugMethod(PlugRequired = true)] + public static uint GetPointer(Object aVal) { return 0; } + + [PlugMethod(PlugRequired = true)] + public static uint GetEntryPoint() { return 0; } + } +} diff --git a/source/Cosmos.Core/Processing/Mutex.cs b/source/Cosmos.Core/Processing/Mutex.cs new file mode 100644 index 0000000000..6cf4a51783 --- /dev/null +++ b/source/Cosmos.Core/Processing/Mutex.cs @@ -0,0 +1,27 @@ +using IL2CPU.API.Attribs; + +namespace Cosmos.Core.Processing +{ + public unsafe class Mutex + { + public int gate; + + [PlugMethod(PlugRequired = true)] + public static void MutexLock(int* mtx) { } + + public void Lock() + { + while (gate != 0) { } + gate = 1; + /*fixed (int* p = &gate) + { + MutexLock(p); + }*/ + } + + public void Unlock() + { + gate = 0; + } + } +} diff --git a/source/Cosmos.Core/Processing/ProcessContext.cs b/source/Cosmos.Core/Processing/ProcessContext.cs new file mode 100644 index 0000000000..4259f3701a --- /dev/null +++ b/source/Cosmos.Core/Processing/ProcessContext.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Cosmos.Core.Processing +{ + public static unsafe class ProcessContext + { + public enum Thread_State + { + ALIVE = 0, + DEAD = 1, + WAITING_SLEEP = 2, + PAUSED = 3 + } + + public enum Context_Type + { + THREAD = 0, + PROCESS = 1 + } + + public class Context + { + public Context next; + public Context_Type type; + public uint tid; + public string name; + public uint esp; + public uint stacktop; + public System.Threading.ThreadStart entry; + public System.Threading.ParameterizedThreadStart paramentry; + public Thread_State state; + public object param; + public int arg; + public uint priority; + public uint age; + public uint parent; + } + + public const uint STACK_SIZE = 4096; + public static uint m_NextCID; + public static Context m_CurrentContext; + public static Context m_ContextList; + + public static Context GetContext(uint tid) + { + /*for(int i = 0; i < m_ContextList.Count; i++) + { + if(m_ContextList[i].tid == tid) + { + return m_ContextList[i]; + } + }*/ + Context ctx = m_ContextList; + while (ctx.next != null) + { + if (ctx.tid == tid) + { + return ctx; + } + ctx = ctx.next; + } + if (ctx.tid == tid) + { + return ctx; + } + return null; + } + + public static uint* SetupStack(uint* stack) + { + uint origin = (uint)stack; + *--stack = 0xFFFFFFFF; // trash + *--stack = 0xFFFFFFFF; // trash + *--stack = 0xFFFFFFFF; // trash + *--stack = 0xFFFFFFFF; // trash + *--stack = 0x10; // ss ? + *--stack = 0x00000202; // eflags + *--stack = 0x8; // cs + *--stack = ObjUtilities.GetEntryPoint(); // eip + *--stack = 0; // error + *--stack = 0; // int + *--stack = 0; // eax + *--stack = 0; // ebx + *--stack = 0; // ecx + *--stack = 0; // offset + *--stack = 0; // edx + *--stack = 0; // esi + *--stack = 0; // edi + *--stack = origin; //ebp + *--stack = 0x10; // ds + *--stack = 0x10; // fs + *--stack = 0x10; // es + *--stack = 0x10; // gs + return stack; + } + + public static uint StartContext(string name, System.Threading.ThreadStart entry, Context_Type type) + { + Context context = new Context(); + context.type = type; + context.tid = m_NextCID++; + context.name = name; + context.stacktop = GCImplementation.AllocNewObject(4096); + context.esp = (uint)SetupStack((uint*)(context.stacktop + 4000)); + context.state = Thread_State.PAUSED; + context.entry = entry; + if (type == Context_Type.PROCESS) + { + context.parent = 0; + } + else + { + context.parent = m_CurrentContext.tid; + } + Context ctx = m_ContextList; + while (ctx.next != null) + { + ctx = ctx.next; + } + ctx.next = context; + return context.tid; + } + + public static uint StartContext(string name, System.Threading.ParameterizedThreadStart entry, Context_Type type, object param) + { + Context context = new Context(); + context.type = type; + context.tid = m_NextCID++; + context.name = name; + context.stacktop = GCImplementation.AllocNewObject(4096); + context.esp = (uint)SetupStack((uint*)(context.stacktop + 4000)); + context.state = Thread_State.ALIVE; + context.paramentry = entry; + context.param = param; + if (type == Context_Type.PROCESS) + { + context.parent = 0; + } + else + { + context.parent = m_CurrentContext.tid; + } + Context ctx = m_ContextList; + while (ctx.next != null) + { + ctx = ctx.next; + } + ctx.next = context; + return context.tid; + } + } +} diff --git a/source/Cosmos.Core/Processing/ProcessorScheduler.cs b/source/Cosmos.Core/Processing/ProcessorScheduler.cs new file mode 100644 index 0000000000..54ebde7e74 --- /dev/null +++ b/source/Cosmos.Core/Processing/ProcessorScheduler.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Text; +using IL2CPU.API.Attribs; + +namespace Cosmos.Core.Processing +{ + public static unsafe class ProcessorScheduler + { + public static void Initialize() + { + var context = new ProcessContext.Context(); + context.type = ProcessContext.Context_Type.PROCESS; + context.tid = ProcessContext.m_NextCID++; + context.name = "Boot"; + context.esp = 0; + context.stacktop = 0; + context.state = ProcessContext.Thread_State.ALIVE; + context.arg = 0; + context.priority = 0; + context.age = 0; + context.parent = 0; + ProcessContext.m_ContextList = context; + ProcessContext.m_CurrentContext = context; + + IOPort counter0 = new IOPort(0x40); + IOPort cmd = new IOPort(0x43); + + int divisor = 1193182 / 25; + cmd.Byte = (0x06 | 0x30); + counter0.Byte = (byte)divisor; + counter0.Byte = (byte)(divisor >> 8); + + IOPort pA1 = new IOPort(0xA1); + IOPort p21 = new IOPort(0xA1); + pA1.Byte = 0x00; + p21.Byte = 0x00; + } + + public static void EntryPoint() + { + ProcessContext.m_CurrentContext.entry?.Invoke(); + ProcessContext.m_CurrentContext.paramentry?.Invoke(ProcessContext.m_CurrentContext.param); + ProcessContext.m_CurrentContext.state = ProcessContext.Thread_State.DEAD; + while (true) { } // remove from thread pool later + } + + public static int interruptCount; + + public static void SwitchTask() + { + interruptCount++; + if (ProcessContext.m_CurrentContext != null) + { + ProcessContext.Context ctx = ProcessContext.m_ContextList; + ProcessContext.Context last = ctx; + while (ctx != null) + { + if (ctx.state == ProcessContext.Thread_State.DEAD) + { + last.next = ctx.next; + break; + } + last = ctx; + ctx = ctx.next; + } + ctx = ProcessContext.m_ContextList; + while (ctx != null) + { + if (ctx.state == ProcessContext.Thread_State.WAITING_SLEEP) + { + ctx.arg -= 1000 / 25; + if (ctx.arg <= 0) + { + ctx.state = ProcessContext.Thread_State.ALIVE; + } + } + ctx.age++; + ctx = ctx.next; + } + ProcessContext.m_CurrentContext.esp = INTs.mStackContext; + tryagain:; + if (ProcessContext.m_CurrentContext.next != null) + { + ProcessContext.m_CurrentContext = ProcessContext.m_CurrentContext.next; + } + else + { + ProcessContext.m_CurrentContext = ProcessContext.m_ContextList; + } + if (ProcessContext.m_CurrentContext.state != ProcessContext.Thread_State.ALIVE) + { + goto tryagain; + } + ProcessContext.m_CurrentContext.age = ProcessContext.m_CurrentContext.priority; + INTs.mStackContext = ProcessContext.m_CurrentContext.esp; + } + Global.PIC.EoiMaster(); + Global.PIC.EoiSlave(); + } + } +} diff --git a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs index 2fa715b9a9..b8e3fad5cb 100644 --- a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs +++ b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs @@ -13,7 +13,7 @@ namespace Cosmos.Core_Asm { public class CPUUpdateIDTAsm : AssemblerMethod { - private static MethodBase GetMethodDef(Assembly aAssembly, string aType, string aMethodName, bool aErrorWhenNotFound) + public static MethodBase GetMethodDef(Assembly aAssembly, string aType, string aMethodName, bool aErrorWhenNotFound) { Type xType = aAssembly.GetType(aType, false); if (xType != null) @@ -79,36 +79,71 @@ public override void AssembleNew(Assembler aAssembler, object aMethodInfo) XS.Push(0); } XS.Push((uint)j); - XS.PushAllRegisters(); - XS.Sub(ESP, 4); - XS.Set(EAX, ESP); // preserve old stack address for passing to interrupt handler - - // store floating point data - XS.And(ESP, 0xfffffff0); // fxsave needs to be 16-byte alligned - XS.Sub(ESP, 512); // fxsave needs 512 bytes - XS.SSE.FXSave(ESP, isIndirect: true); // save the registers - XS.Set(EAX, ESP, destinationIsIndirect: true); - - XS.Push(EAX); // - XS.Push(EAX); // pass old stack address (pointer to InterruptContext struct) to the interrupt handler - - XS.JumpToSegment(8, "__ISR_Handler_" + j.ToString("X2") + "_SetCS"); - XS.Label("__ISR_Handler_" + j.ToString("X2") + "_SetCS"); - MethodBase xHandler = GetInterruptHandler((byte)j); - if (xHandler == null) + if (j != 0x20) { - xHandler = GetMethodDef(typeof(Cosmos.Core.INTs).Assembly, typeof(Cosmos.Core.INTs).FullName, "HandleInterrupt_Default", true); + XS.PushAllRegisters(); + + XS.Sub(ESP, 4); + XS.Set(EAX, ESP); // preserve old stack address for passing to interrupt handler + + // store floating point data + XS.And(ESP, 0xfffffff0); // fxsave needs to be 16-byte alligned + XS.Sub(ESP, 512); // fxsave needs 512 bytes + XS.SSE.FXSave(ESP, isIndirect: true); // save the registers + XS.Set(EAX, ESP, destinationIsIndirect: true); + + XS.Push(EAX); // + XS.Push(EAX); // pass old stack address (pointer to InterruptContext struct) to the interrupt handler + + XS.JumpToSegment(8, "__ISR_Handler_" + j.ToString("X2") + "_SetCS"); + XS.Label("__ISR_Handler_" + j.ToString("X2") + "_SetCS"); + MethodBase xHandler = GetInterruptHandler((byte)j); + if (xHandler == null) + { + xHandler = GetMethodDef(typeof(Cosmos.Core.INTs).Assembly, typeof(Cosmos.Core.INTs).FullName, "HandleInterrupt_Default", true); + } + XS.Call(LabelName.Get(xHandler)); + XS.Pop(EAX); + XS.SSE.FXRestore(ESP, isIndirect: true); + + XS.Set(ESP, EAX); // this restores the stack for the FX stuff, except the pointer to the FX data + XS.Add(ESP, 4); // "pop" the pointer + + XS.PopAllRegisters(); } - XS.Call(LabelName.Get(xHandler)); - XS.Pop(EAX); - XS.SSE.FXRestore(ESP, isIndirect: true); - - XS.Set(ESP, EAX); // this restores the stack for the FX stuff, except the pointer to the FX data - XS.Add(ESP, 4); // "pop" the pointer - - XS.PopAllRegisters(); - + else + { + new LiteralAssemblerCode("pushad"); + new LiteralAssemblerCode("mov eax, ds"); + new LiteralAssemblerCode("push eax"); + new LiteralAssemblerCode("mov eax, es"); + new LiteralAssemblerCode("push eax"); + new LiteralAssemblerCode("mov eax, fs"); + new LiteralAssemblerCode("push eax"); + new LiteralAssemblerCode("mov eax, gs"); + new LiteralAssemblerCode("push eax"); + new LiteralAssemblerCode("mov ax, 0x10"); + new LiteralAssemblerCode("mov ds, ax"); + new LiteralAssemblerCode("mov es, ax"); + new LiteralAssemblerCode("mov fs, ax"); + new LiteralAssemblerCode("mov gs, ax"); + new LiteralAssemblerCode("mov eax, esp"); + XS.Set("static_field__Cosmos_Core_INTs_mStackContext", EAX, destinationIsIndirect: true); + XS.Call(LabelName.Get(GetMethodDef(typeof(Cosmos.Core.Processing.ProcessorScheduler).Assembly, typeof(Cosmos.Core.Processing.ProcessorScheduler).FullName, "SwitchTask", true))); + XS.Set(EAX, "static_field__Cosmos_Core_INTs_mStackContext", sourceIsIndirect: true); + new LiteralAssemblerCode("mov esp, eax"); + new LiteralAssemblerCode("pop eax"); + new LiteralAssemblerCode("mov gs, eax"); + new LiteralAssemblerCode("pop eax"); + new LiteralAssemblerCode("mov fs, eax"); + new LiteralAssemblerCode("pop eax"); + new LiteralAssemblerCode("mov es, eax"); + new LiteralAssemblerCode("pop eax"); + new LiteralAssemblerCode("mov ds, eax"); + new LiteralAssemblerCode("popad"); + } + XS.Add(ESP, 8); XS.Label("__ISR_Handler_" + j.ToString("X2") + "_END"); XS.InterruptReturn(); diff --git a/source/Cosmos.Core_Asm/DelegateImpl.cs b/source/Cosmos.Core_Asm/DelegateImpl.cs index 627cb0b531..2db3205252 100644 --- a/source/Cosmos.Core_Asm/DelegateImpl.cs +++ b/source/Cosmos.Core_Asm/DelegateImpl.cs @@ -4,7 +4,7 @@ namespace Cosmos.Core_Asm { [Plug(Target = typeof(Delegate), Inheritable = true)] - public static class DelegateImpl + public static unsafe class DelegateImpl { [PlugMethod(Assembler = typeof(DelegateCtorAsm), IsWildcard = true, WildcardMatchParameters = true)] public static void Ctor(Delegate aThis, object aTarget, IntPtr aMethod) @@ -28,5 +28,10 @@ public static bool Equals(Delegate aThis, object aThat) { throw new NotImplementedException(); } + + public static int GetHashCode(Delegate aThis, [FieldAccess(Name = "System.IntPtr System.Delegate._methodPtr")] ref IntPtr aAddress) + { + return (int)aAddress.ToPointer(); + } } } diff --git a/source/Cosmos.Core_Asm/MutexImpl.cs b/source/Cosmos.Core_Asm/MutexImpl.cs new file mode 100644 index 0000000000..1fb7a23fe4 --- /dev/null +++ b/source/Cosmos.Core_Asm/MutexImpl.cs @@ -0,0 +1,36 @@ +using Cosmos.Core.Processing; +using IL2CPU.API.Attribs; +using XSharp; +using XSharp.Assembler; + +namespace Cosmos.Core_Asm +{ + [Plug(Target = typeof(Mutex))] + public static unsafe class MutexImpl + { + [PlugMethod(Assembler = typeof(MutexLockASM))] + public static void MutexLock(int* mtx) { } + } + + public class MutexLockASM : AssemblerMethod + { + public override void AssembleNew(Assembler aAssembler, object aMethodInfo) + { + new LiteralAssemblerCode("lock_asm:"); + new LiteralAssemblerCode("mov eax, [esp + 8]"); + new LiteralAssemblerCode("mov ebx, 0"); + new LiteralAssemblerCode("lock bts[eax], ebx"); + new LiteralAssemblerCode("jc.spin_wait"); + new LiteralAssemblerCode("mov ebx, 1"); + new LiteralAssemblerCode("mov dword[eax], ebx"); + new LiteralAssemblerCode("jmp .finished"); + new LiteralAssemblerCode(".spin_wait:"); + new LiteralAssemblerCode("mov ebx, 1"); + new LiteralAssemblerCode("test dword[eax], ebx"); + new LiteralAssemblerCode("pause"); + new LiteralAssemblerCode("jnz.spin_wait"); + new LiteralAssemblerCode("jmp lock_asm"); + new LiteralAssemblerCode(".finished"); + } + } +} diff --git a/source/Cosmos.Core_Asm/ObjUtilitiesImpl.cs b/source/Cosmos.Core_Asm/ObjUtilitiesImpl.cs new file mode 100644 index 0000000000..f757352cd1 --- /dev/null +++ b/source/Cosmos.Core_Asm/ObjUtilitiesImpl.cs @@ -0,0 +1,40 @@ +using Cosmos.Core; +using IL2CPU.API; +using IL2CPU.API.Attribs; +using System; +using XSharp; +using XSharp.Assembler; + +namespace Cosmos.Core_Asm +{ + [Plug(Target = typeof(ObjUtilities))] + public static unsafe class ObjUtilitiesImpl + { + [PlugMethod(Assembler = typeof(ObjUtilitiesGetPointer))] + public static uint GetPointer(Delegate aVal) { return 0; } + + [PlugMethod(Assembler = typeof(ObjUtilitiesGetPointer))] + public static uint GetPointer(Object aVal) { return 0; } + + [PlugMethod(Assembler = typeof(ObjUtilitiesGetEntry))] + public static uint GetEntryPoint() { return 0; } + } + + public class ObjUtilitiesGetPointer : AssemblerMethod + { + public override void AssembleNew(Assembler aAssembler, object aMethodInfo) + { + XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: 0x8); + XS.Push(XSRegisters.EAX); + } + } + + public class ObjUtilitiesGetEntry : AssemblerMethod + { + public override void AssembleNew(Assembler aAssembler, object aMethodInfo) + { + XS.Set(XSRegisters.EAX, LabelName.Get(CPUUpdateIDTAsm.GetMethodDef(typeof(Cosmos.Core.Processing.ProcessorScheduler).Assembly, typeof(Cosmos.Core.Processing.ProcessorScheduler).FullName, "EntryPoint", true))); + XS.Push(XSRegisters.EAX); + } + } +} diff --git a/source/Cosmos.Core_Plugs/System/DelegateImpl.cs b/source/Cosmos.Core_Plugs/System/DelegateImpl.cs index 0bc8d281f9..343424d8aa 100644 --- a/source/Cosmos.Core_Plugs/System/DelegateImpl.cs +++ b/source/Cosmos.Core_Plugs/System/DelegateImpl.cs @@ -6,7 +6,7 @@ namespace Cosmos.Core_Plugs.System { [Plug(Target = typeof(Delegate))] - public static class DelegateImpl + public static unsafe class DelegateImpl { [PlugMethod(Signature = "System_Boolean__System_Delegate_Equals_System_Object_")] public static bool Equals(Delegate aThis, object aThat) @@ -24,6 +24,11 @@ public static unsafe bool InternalEqualTypes([ObjectPointerAccess] uint** a, [Ob return xTypeA == xTypeB; } + + public static int GetHashCode(Delegate aThis, [FieldAccess(Name = "System.IntPtr System.Delegate._methodPtr")] ref IntPtr aAddress) + { + return (int)aAddress.ToPointer(); + } } [Plug(Target = typeof(Delegate), Inheritable = true)] diff --git a/source/Cosmos.Core_Plugs/System/Threading/ThreadImpl.cs b/source/Cosmos.Core_Plugs/System/Threading/ThreadImpl.cs index 9c28ca3ef5..2c62d7a323 100644 --- a/source/Cosmos.Core_Plugs/System/Threading/ThreadImpl.cs +++ b/source/Cosmos.Core_Plugs/System/Threading/ThreadImpl.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using IL2CPU.API.Attribs; @@ -16,6 +17,11 @@ public static void MemoryBarrier() } + public static void Ctor(ThreadStart aThis, ThreadStart aEntry) + { + Console.WriteLine("Thread started"); + } + // public static void SleepInternal(int ms) // { // // Implementation of http://referencesource.microsoft.com/#mscorlib/system/threading/thread.cs,6a577476abf2f437,references diff --git a/source/Cosmos.HAL2/Global.cs b/source/Cosmos.HAL2/Global.cs index 540fc81bcc..0354e57dcd 100644 --- a/source/Cosmos.HAL2/Global.cs +++ b/source/Cosmos.HAL2/Global.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; - +using System.Threading; using Cosmos.Core; using Cosmos.Debug.Kernel; using Cosmos.HAL.BlockDevice; @@ -63,6 +63,10 @@ static public void Init(TextScreenBase textScreen) AHCI.InitDriver(); //EHCI.InitDriver(); + Console.WriteLine("Starting Processor Scheduler"); + mDebugger.Send("Processor Scheduler"); + Core.Processing.ProcessorScheduler.Initialize(); + mDebugger.Send("Done initializing Cosmos.HAL.Global"); } @@ -80,6 +84,16 @@ public static void EnableInterrupts() /// public static bool InterruptsEnabled => CPU.mInterruptsEnabled; + public static uint SpawnThread(ThreadStart aStart) + { + return Core.Processing.ProcessContext.StartContext("", aStart, Core.Processing.ProcessContext.Context_Type.THREAD); + } + + public static uint SpawnThread(ParameterizedThreadStart aStart, object param) + { + return Core.Processing.ProcessContext.StartContext("", aStart, Core.Processing.ProcessContext.Context_Type.THREAD, param); + } + /// /// Get keyboard devices. /// diff --git a/source/Cosmos.System2/Thread.cs b/source/Cosmos.System2/Thread.cs new file mode 100644 index 0000000000..16d9607ec9 --- /dev/null +++ b/source/Cosmos.System2/Thread.cs @@ -0,0 +1,45 @@ +using st = System.Threading; + +namespace Cosmos.System +{ + public class Thread + { + public uint ThreadID; + private Cosmos.Core.Processing.ProcessContext.Context Data; + + public Thread(st.ThreadStart start) + { + ThreadID = Cosmos.HAL.Global.SpawnThread(start); + ThreadFinalSetup(); + } + + public Thread(st.ParameterizedThreadStart start, object param) + { + ThreadID = Cosmos.HAL.Global.SpawnThread(start, param); + ThreadFinalSetup(); + } + + private void ThreadFinalSetup() + { + Data = Cosmos.Core.Processing.ProcessContext.GetContext(ThreadID); + Data.state = Core.Processing.ProcessContext.Thread_State.PAUSED; + } + + public void Start() + { + Data.state = Core.Processing.ProcessContext.Thread_State.ALIVE; + } + + public void Stop() + { + Data.state = Core.Processing.ProcessContext.Thread_State.PAUSED; + } + + public static void Sleep(int ms) + { + Cosmos.Core.Processing.ProcessContext.m_CurrentContext.arg = ms; + Cosmos.Core.Processing.ProcessContext.m_CurrentContext.state = Core.Processing.ProcessContext.Thread_State.WAITING_SLEEP; + while (Cosmos.Core.Processing.ProcessContext.m_CurrentContext.state == Core.Processing.ProcessContext.Thread_State.WAITING_SLEEP) { } + } + } +} From f2716cf8b7294262f249d5693a4b35606b7e1a6e Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Mon, 6 Jun 2022 20:14:22 +0200 Subject: [PATCH 02/15] Fix conflicts + Lock memory gate using new memory manager --- source/Cosmos.Core/Memory/Heap.cs | 30 +++++++++++++++++++ .../Cosmos.Core_Plugs/System/DelegateImpl.cs | 5 ++-- source/Cosmos.HAL2/Global.cs | 4 +-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/source/Cosmos.Core/Memory/Heap.cs b/source/Cosmos.Core/Memory/Heap.cs index 69fee9c49a..2820ce8cd0 100644 --- a/source/Cosmos.Core/Memory/Heap.cs +++ b/source/Cosmos.Core/Memory/Heap.cs @@ -20,6 +20,8 @@ public enum ObjectGCStatus : ushort public static unsafe class Heap { private static uint* StackStart; + private static Mutex mMemeoryGate = new Mutex(); + /// /// Init heap. /// @@ -39,26 +41,54 @@ public static unsafe void Init() /// Byte pointer to the start of the block. public static byte* Alloc(uint aSize) { + if (mMemeoryGate != null) + { + mMemeoryGate.Lock(); + } + CPU.DisableInterrupts(); if (aSize <= HeapSmall.mMaxItemSize) { byte* ptr = HeapSmall.Alloc((ushort)aSize); CPU.EnableInterrupts(); + + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } + return ptr; } else if (aSize <= HeapMedium.MaxItemSize) { byte* ptr = HeapMedium.Alloc(aSize); CPU.EnableInterrupts(); + + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } + return ptr; } else { byte* ptr = HeapLarge.Alloc(aSize); CPU.EnableInterrupts(); + + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } + return ptr; } + + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } } /// diff --git a/source/Cosmos.Core_Plugs/System/DelegateImpl.cs b/source/Cosmos.Core_Plugs/System/DelegateImpl.cs index 88936fc334..b27435b80d 100644 --- a/source/Cosmos.Core_Plugs/System/DelegateImpl.cs +++ b/source/Cosmos.Core_Plugs/System/DelegateImpl.cs @@ -25,16 +25,15 @@ public static unsafe bool InternalEqualTypes([ObjectPointerAccess] uint** a, [Ob return xTypeA == xTypeB; } -<<<<<<< HEAD public static int GetHashCode(Delegate aThis, [FieldAccess(Name = "System.IntPtr System.Delegate._methodPtr")] ref IntPtr aAddress) { return (int)aAddress.ToPointer(); -======= + } + [PlugMethod(Signature = "System_IRuntimeMethodInfo__System_Delegate_FindMethodHandle__")] public static object FindMethodHandle(Delegate aThis) { throw new NotImplementedException(); ->>>>>>> master } } diff --git a/source/Cosmos.HAL2/Global.cs b/source/Cosmos.HAL2/Global.cs index c75a7e0a85..4e56b191d7 100644 --- a/source/Cosmos.HAL2/Global.cs +++ b/source/Cosmos.HAL2/Global.cs @@ -76,13 +76,11 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In } AHCI.InitDriver(); //EHCI.InitDriver(); -<<<<<<< HEAD Console.WriteLine("Starting Processor Scheduler"); mDebugger.Send("Processor Scheduler"); Core.Processing.ProcessorScheduler.Initialize(); -======= if (InitNetwork) { mDebugger.Send("Network Devices Init"); @@ -94,7 +92,7 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In } Console.WriteLine("Enabling Serial Output on COM1"); Debug.Serial.Enable(); ->>>>>>> master + mDebugger.Send("Done initializing Cosmos.HAL.Global"); } From d7f50260b5df40cdfaa6d97ca77d35bd327c81b0 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Mon, 6 Jun 2022 20:18:28 +0200 Subject: [PATCH 03/15] Remove useless code --- source/Cosmos.Core/Memory/Old/Old_Heap.cs | 239 ---------------------- 1 file changed, 239 deletions(-) delete mode 100644 source/Cosmos.Core/Memory/Old/Old_Heap.cs diff --git a/source/Cosmos.Core/Memory/Old/Old_Heap.cs b/source/Cosmos.Core/Memory/Old/Old_Heap.cs deleted file mode 100644 index 11bca292c2..0000000000 --- a/source/Cosmos.Core/Memory/Old/Old_Heap.cs +++ /dev/null @@ -1,239 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Cosmos.Core; -using Cosmos.Core.Processing; -using Cosmos.Debug.Kernel; - -namespace Cosmos.Core.Memory.Old -{ - // This class must be static, as for creating objects, we need the heap - // this heap implementation it the very most basic one: no reentrancy, etc. - // Interrupts are disabled when trying to allocate a new block of memory. - public static unsafe class Heap - { - private static Debugger mDebugger = new Debugger("Core", "Memory"); - - private static uint mEndOfRam; - - private static DataLookupTable* mLastTable; - - private static uint mLastEntryIndex = 0u; - - private static Mutex mMemeoryGate = new Mutex(); - - private static bool mInitialized = false; - - private static void DoInitialize(uint aEndOfRam) - { - mLastTable = null; - mLastEntryIndex = 0u; - mEndOfRam = aEndOfRam; - // - } - - internal static void EnsureIsInitialized() - { - if (!mInitialized) - { - mInitialized = true; - DoInitialize((CPU.GetAmountOfRAM() - 1) * 1024 * 1024); - } - } - - private static void ClearMemory(void* aStartAddress, uint aLength) - { - //TODO: Move to memory. Internal access only... - CPU.ZeroFill((uint)aStartAddress, aLength); - } - - public static uint MemAlloc(uint aLength) - { - if (aLength == 0) - { - mDebugger.Send(" Request to retrieve block with size = 0 was halted!"); - while (true) - { - } - } - - bool xInterruptsWereEnabled = CPU.DisableInterrupts(); - try - { - EnsureIsInitialized(); - - if (mMemeoryGate != null) - { - mMemeoryGate.Lock(); - } - - DataLookupTable* xCurrentTable = GlobalSystemInfo.GlobalInformationTable->FirstDataLookupTable; - DataLookupTable* xPreviousTable = null; - uint xResult; - - if (mLastTable != null) - { - xCurrentTable = mLastTable; - } - - #region Loop through existing tables and see if we find a free spot - while (xCurrentTable != null) - { - if (ScanDataLookupTable(xCurrentTable, aLength, out xResult)) - { - if (xResult < CPU.GetEndOfKernel()) - { - Debugger.DoSend("Wrong handle returned!"); - while (true) - { - } - } - - if (mMemeoryGate != null) - { - mMemeoryGate.Unlock(); - } - - return xResult; - } - mLastTable = xPreviousTable; - xPreviousTable = xCurrentTable; - xCurrentTable = xCurrentTable->Next; - mLastEntryIndex = 0; - } - #endregion Loop through existing tables and see if we find a free spot - - // no tables found, lets create a new one, and use that - if (xPreviousTable == null) - { - // this check should theoretically be unnecessary, but lets keep it, to do some double-checking. - Debugger.DoSend("No PreviousTable found!"); - while (true) - { - } - } - - var xLastItem = xPreviousTable->GetEntry(DataLookupTable.EntriesPerTable - 1); - var xNextTablePointer = (DataLookupTable*)((uint)xLastItem->DataBlock + xLastItem->Size); - // the memory hasn't been cleared yet, so lets do that now. - ClearMemory(xNextTablePointer, GlobalSystemInfo.TotalDataLookupTableSize); - xPreviousTable->Next = xNextTablePointer; - xNextTablePointer->Previous = xPreviousTable; - if (!ScanDataLookupTable(xNextTablePointer, aLength, out xResult)) - { - // Something seriously weird happened: we could create a new DataLookupTable (with new entries) - // but couldn't allocate a new handle from it. - Debugger.DoSend(" Something seriously weird happened: we could create a new DataLookupTable (with new entries), but couldn't allocate a new handle from it."); - while (true) - { - } - } - mLastTable = xNextTablePointer; - mLastEntryIndex = 0; - - if (mMemeoryGate != null) - { - mMemeoryGate.Unlock(); - } - - return xResult; - } - finally - { - if (xInterruptsWereEnabled) - { - CPU.EnableInterrupts(); - } - else - { - //Debugger.DoSend(" Not enabling interrupts, because they weren't enabled yet!"); - } - if (mMemeoryGate != null) - { - mMemeoryGate.Unlock(); - } - } - } - - private static bool ScanDataLookupTable(DataLookupTable* aTable, uint aSize, out uint aHandle) - { - //Debugger.DoSend("At address:"); - //Debugger.DoSendNumber((uint)aTable); - - DataLookupEntry* xPreviousEntry = null; - for (uint i = mLastEntryIndex; i < DataLookupTable.EntriesPerTable; i++) - { - var xCurrentEntry = aTable->GetEntry(i); - //Debugger.DoSend($"Item.Size", xCurrentEntry->Size); - //Debugger.DoSend($"Item.Refcount", xCurrentEntry->Refcount); - if (xCurrentEntry->Size == 0) - { - #region Found an uninitialized entry - // found an entry now. Let's set it - if (aTable->Next != null) - { - // once a handle is used, the size should be set. But at this point, it somehow got unset again. - // This should never occur. - Debugger.DoSend("Found an entry which has no size, but there is a followup DataLookupTable"); - while (true) - { - } - } - - void* xDataBlock; - //Debugger.DoSend("Now calculate datablock pointer"); - // now we found ourself a free handle - if (i == 0) - { - //Debugger.DoSend("Using table end"); - // we don't have a previous handle yet, so we take the FirstByteAfterTable field of the DataLookupTable - // note: we're explicitly initializing all blocks, as memory hasn't been cleared yet. - var xTableAddr = (uint)aTable; - //Debugger.DoSend("xTableAddr"); - //Debugger.DoSendNumber(xTableAddr); - var xTotalTableSize = GlobalSystemInfo.TotalDataLookupTableSize; - //Debugger.DoSend("xTotalTableSize"); - //Debugger.DoSendNumber(xTotalTableSize); - xDataBlock = (void*)(xTableAddr + xTotalTableSize); - } - else - { - //Debugger.DoSend("Using previous entry"); - // We're not the very first handle being assigned, so calculate the start address using the previous block - xDataBlock = (void*)((uint)xPreviousEntry->DataBlock + xPreviousEntry->Size); - } - - // make sure the memory is empty - ClearMemory(xDataBlock, aSize); - //Debugger.DoSend("Cleared memory"); - xCurrentEntry->Size = aSize; - xCurrentEntry->DataBlock = xDataBlock; - xCurrentEntry->Refcount = 1; - aHandle = (uint)xCurrentEntry->DataBlock; - //Debugger.DoSend("Returning handle"); - //Debugger.DoSendNumber(aHandle); - mLastEntryIndex = i; - #endregion Found an uninitialized entry - return true; - } - - // Refcount == UInt32.MaxValue, it means that the block has been reclaimed, and can be reused now. - if (xCurrentEntry->Refcount == UInt32.MaxValue) - { - // we can reuse this entry if its Size >= aLength - if (xCurrentEntry->Size >= aSize) - { - // we can reuse this entry - xCurrentEntry->Refcount = 1; - aHandle = (uint)xCurrentEntry->DataBlock; - mLastEntryIndex = i; - return true; - } - } - xPreviousEntry = xCurrentEntry; - } - aHandle = 0; - return false; - } - } -} From c3540b03cfb7f2862a164460d57ba189bf9ee688 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Mon, 6 Jun 2022 20:25:13 +0200 Subject: [PATCH 04/15] Fix build --- source/Cosmos.Core/Memory/Heap.cs | 1 + .../10-CPU/Cosmos.CPU_Asm/Delegate/DelegateCtorAsm.cs | 2 +- .../10-CPU/Cosmos.CPU_Asm/Delegate/DelegateInvokeAsm.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/Cosmos.Core/Memory/Heap.cs b/source/Cosmos.Core/Memory/Heap.cs index 2820ce8cd0..b76c9c654b 100644 --- a/source/Cosmos.Core/Memory/Heap.cs +++ b/source/Cosmos.Core/Memory/Heap.cs @@ -1,4 +1,5 @@ using System; +using Cosmos.Core.Processing; using Cosmos.Debug.Kernel; using IL2CPU.API; diff --git a/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateCtorAsm.cs b/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateCtorAsm.cs index b19f16058d..bf48eb6f61 100644 --- a/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateCtorAsm.cs +++ b/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateCtorAsm.cs @@ -9,7 +9,7 @@ public class DelegateCtorAsm : AssemblerMethod { public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { // method signature: $this, object @object, IntPtr method var xAssembler = aAssembler; - var xMethodInfo = (_MethodInfo)aMethodInfo; + var xMethodInfo = (Il2cpuMethodInfo)aMethodInfo; XS.Comment("Save target ($this) to field"); XS.Comment("-- ldarg 0"); Ldarg.DoExecute(xAssembler, xMethodInfo, 0); diff --git a/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateInvokeAsm.cs b/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateInvokeAsm.cs index dc9b92a2fe..b7f00f21ba 100644 --- a/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateInvokeAsm.cs +++ b/source/Kernel-X86/10-CPU/Cosmos.CPU_Asm/Delegate/DelegateInvokeAsm.cs @@ -13,7 +13,7 @@ namespace Cosmos.CPU_Asm { public class DelegateInvokeAsm : AssemblerMethod { public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { var xAssembler = aAssembler; - var xMethodInfo = (_MethodInfo)aMethodInfo; + var xMethodInfo = (Il2cpuMethodInfo)aMethodInfo; var xMethodBaseAsInfo = xMethodInfo.MethodBase as global::System.Reflection.MethodInfo; if (xMethodBaseAsInfo.ReturnType != typeof(void)) { throw new Exception("Events with return type not yet supported!"); From 727a09097283c23961b92c56da5fd68d1e16a3b2 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Thu, 9 Jun 2022 10:45:53 +0200 Subject: [PATCH 05/15] Add Threading test --- .../Cosmos.TestRunner.Full/TestKernelSets.cs | 1 + Tests/Kernels/ThreadingTest/Kernel.cs | 50 +++++++++++++++++++ .../ThreadingTest/ThreadingTest.csproj | 16 ++++++ 3 files changed, 67 insertions(+) create mode 100644 Tests/Kernels/ThreadingTest/Kernel.cs create mode 100644 Tests/Kernels/ThreadingTest/ThreadingTest.csproj diff --git a/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs b/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs index fb6d83ba10..9e873a28bb 100644 --- a/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs +++ b/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs @@ -37,6 +37,7 @@ public static IEnumerable GetStableKernelTypes() // This is a bit slow and works only because ring check is disabled to decide if leave it enabled yield return typeof(MemoryOperationsTest.Kernel); yield return typeof(ProcessorTests.Kernel); + yield return typeof(ThreadingTests.Kernel); } } } diff --git a/Tests/Kernels/ThreadingTest/Kernel.cs b/Tests/Kernels/ThreadingTest/Kernel.cs new file mode 100644 index 0000000000..a6f566393b --- /dev/null +++ b/Tests/Kernels/ThreadingTest/Kernel.cs @@ -0,0 +1,50 @@ +using System; +using Sys = Cosmos.System; +using Cosmos.System; +using Cosmos.TestRunner; + +namespace ThreadingTests +{ + public class Kernel : Sys.Kernel + { + int variable = 0; + + int variableTwo = 0; + + int variableThree = 0; + + protected override void BeforeRun() + { + var threadOne = new Thread(ThreadOne); + var threadTwo = new Thread(ThreadTwo); + + threadOne.Start(); + threadTwo.Start(); + + variableThree = 3; + + Thread.Sleep(1000); + + Assert.AreEqual(variable, 1, "Changing global variable from thread works"); + + Assert.AreEqual(variableTwo, 2, "Changing global variable from second thread works"); + + Assert.AreEqual(variableThree, 3, "Changing global variable from main context works"); + } + + public void ThreadOne() + { + variable = 1; + } + + public void ThreadTwo() + { + variableTwo = 2; + } + + protected override void Run() + { + + } + } +} diff --git a/Tests/Kernels/ThreadingTest/ThreadingTest.csproj b/Tests/Kernels/ThreadingTest/ThreadingTest.csproj new file mode 100644 index 0000000000..8ab8f818a1 --- /dev/null +++ b/Tests/Kernels/ThreadingTest/ThreadingTest.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + False + Debug;Release;TEST + + + + + + + + + + From 30a1b9820854a07c08ec880acc37dc8d80b79061 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Thu, 9 Jun 2022 10:48:03 +0200 Subject: [PATCH 06/15] Update test --- Tests/Kernels/ThreadingTest/Kernel.cs | 40 +++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/Tests/Kernels/ThreadingTest/Kernel.cs b/Tests/Kernels/ThreadingTest/Kernel.cs index a6f566393b..7783196f71 100644 --- a/Tests/Kernels/ThreadingTest/Kernel.cs +++ b/Tests/Kernels/ThreadingTest/Kernel.cs @@ -2,6 +2,7 @@ using Sys = Cosmos.System; using Cosmos.System; using Cosmos.TestRunner; +using Console = System.Console; namespace ThreadingTests { @@ -15,21 +16,37 @@ public class Kernel : Sys.Kernel protected override void BeforeRun() { - var threadOne = new Thread(ThreadOne); - var threadTwo = new Thread(ThreadTwo); + Console.WriteLine("Cosmos booted successfully. Let's Test Threading!"); + } + + protected override void Run() + { + try + { + var threadOne = new Thread(ThreadOne); + var threadTwo = new Thread(ThreadTwo); + + threadOne.Start(); + threadTwo.Start(); - threadOne.Start(); - threadTwo.Start(); + variableThree = 3; - variableThree = 3; + Thread.Sleep(1000); - Thread.Sleep(1000); + Assert.AreEqual(variable, 1, "Changing global variable from thread works"); - Assert.AreEqual(variable, 1, "Changing global variable from thread works"); + Assert.AreEqual(variableTwo, 2, "Changing global variable from second thread works"); - Assert.AreEqual(variableTwo, 2, "Changing global variable from second thread works"); + Assert.AreEqual(variableThree, 3, "Changing global variable from main context works"); - Assert.AreEqual(variableThree, 3, "Changing global variable from main context works"); + TestController.Completed(); + } + catch (Exception e) + { + mDebugger.Send("Exception occurred: " + e.Message); + mDebugger.Send(e.Message); + TestController.Failed(); + } } public void ThreadOne() @@ -41,10 +58,5 @@ public void ThreadTwo() { variableTwo = 2; } - - protected override void Run() - { - - } } } From aeacb317de08649facb549c1b864109823c3b218 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Thu, 9 Jun 2022 11:01:47 +0200 Subject: [PATCH 07/15] Update sln + csproj --- Test.sln | 19 +++++++++++++++++-- .../Cosmos.TestRunner.Full.csproj | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Test.sln b/Test.sln index ee06450341..bb225e44e2 100644 --- a/Test.sln +++ b/Test.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29728.190 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32519.379 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{DAEF99B5-22F0-4885-B45B-9B600B857E1C}" EndProject @@ -172,6 +172,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DapperExtensions.StrongName EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resources", "Resources", "{A45F0D24-1AF3-42BC-91A6-0262AFB1234D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThreadingTest", "Tests\Kernels\ThreadingTest\ThreadingTest.csproj", "{9491798B-DE56-4300-9A3A-025A2F7B51C2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -889,6 +891,18 @@ Global {AC45D5B2-0D02-49B8-A88E-EABF34AE62B5}.TEST|Any CPU.Build.0 = Debug|Any CPU {AC45D5B2-0D02-49B8-A88E-EABF34AE62B5}.TEST|x86.ActiveCfg = Debug|Any CPU {AC45D5B2-0D02-49B8-A88E-EABF34AE62B5}.TEST|x86.Build.0 = Debug|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Debug|x86.ActiveCfg = Debug|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Debug|x86.Build.0 = Debug|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Release|Any CPU.Build.0 = Release|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Release|x86.ActiveCfg = Release|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.Release|x86.Build.0 = Release|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.TEST|Any CPU.ActiveCfg = TEST|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.TEST|Any CPU.Build.0 = TEST|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.TEST|x86.ActiveCfg = TEST|Any CPU + {9491798B-DE56-4300-9A3A-025A2F7B51C2}.TEST|x86.Build.0 = TEST|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -970,6 +984,7 @@ Global {30D9FA9C-0B4D-40FF-8903-6B9E9C825729} = {ECEA7778-E786-4317-90B9-A2D4427CB91C} {96855A39-A96B-4BDB-A6AE-29676DFEF637} = {29EEC029-6A2B-478A-B6E5-D63A91388ABA} {AC45D5B2-0D02-49B8-A88E-EABF34AE62B5} = {A45F0D24-1AF3-42BC-91A6-0262AFB1234D} + {9491798B-DE56-4300-9A3A-025A2F7B51C2} = {29EEC029-6A2B-478A-B6E5-D63A91388ABA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4418C803-277E-448F-A0A0-52788FA215AD} diff --git a/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj b/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj index 3755e72564..16c1560dc5 100644 --- a/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj +++ b/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj @@ -33,6 +33,7 @@ + From 52e530853da6b36b8582b0adba45b0527bee9146 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Thu, 9 Jun 2022 11:37:27 +0200 Subject: [PATCH 08/15] Update test --- Tests/Kernels/ThreadingTest/Kernel.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Tests/Kernels/ThreadingTest/Kernel.cs b/Tests/Kernels/ThreadingTest/Kernel.cs index 7783196f71..9d2504f3d8 100644 --- a/Tests/Kernels/ThreadingTest/Kernel.cs +++ b/Tests/Kernels/ThreadingTest/Kernel.cs @@ -29,9 +29,16 @@ protected override void Run() threadOne.Start(); threadTwo.Start(); + Console.WriteLine("Inside Run method!"); + variableThree = 3; - Thread.Sleep(1000); + //Since Run is not a thread call PIT wait + System.Threading.Thread.Sleep(3000); + + //Cosmos.HAL.Global.PIT.Wait(3000); + + Console.WriteLine("Waited 3 second."); Assert.AreEqual(variable, 1, "Changing global variable from thread works"); @@ -51,12 +58,22 @@ protected override void Run() public void ThreadOne() { + //Make thread WAITING + Thread.Sleep(1000); + variable = 1; + + Console.WriteLine("Inside first thread!"); } public void ThreadTwo() { + //Make thread WAITING + Thread.Sleep(1000); + variableTwo = 2; + + Console.WriteLine("Inside second thread!"); } } } From 68dc3e06ef87f6558e5ba920396d71dc3d275664 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Tue, 26 Dec 2023 10:57:04 +0100 Subject: [PATCH 09/15] =?UTF-8?q?=F0=9F=90=9B=20Fix=20memory=20manager=20w?= =?UTF-8?q?ith=20multithreading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/Cosmos.Core/Memory/Heap.cs | 36 ++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/source/Cosmos.Core/Memory/Heap.cs b/source/Cosmos.Core/Memory/Heap.cs index 07d1930341..862c10c7c3 100644 --- a/source/Cosmos.Core/Memory/Heap.cs +++ b/source/Cosmos.Core/Memory/Heap.cs @@ -47,6 +47,11 @@ public static unsafe void Init() /// New pointer with specified size while maintaining old data. public static byte* Realloc(byte* aPtr, uint newSize) { + if (mMemeoryGate != null) + { + mMemeoryGate.Lock(); + } + // TODO: don't move memory position if there is enough space in the current one. // Get existing size @@ -75,6 +80,12 @@ public static unsafe void Init() // Free the old data and return Free(aPtr); + + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } + return ToReturn; } @@ -128,11 +139,6 @@ public static unsafe void Init() return ptr; } - - if (mMemeoryGate != null) - { - mMemeoryGate.Unlock(); - } } /// @@ -159,6 +165,11 @@ public static uint SafeAlloc(uint aSize) /// public static void Free(void* aPtr) { + if (mMemeoryGate != null) + { + mMemeoryGate.Lock(); + } + //TODO find a better way to remove the double look up here for GetPageType and then again in the // .Free methods which actually free the entries in the RAT. //Debugger.DoSendNumber(0x77); @@ -177,6 +188,11 @@ public static void Free(void* aPtr) default: throw new Exception("Heap item not found in RAT."); } + + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } } /// @@ -185,6 +201,11 @@ public static void Free(void* aPtr) /// Number of objects freed public static int Collect() { + if (mMemeoryGate != null) + { + mMemeoryGate.Lock(); + } + //Disable interrupts: Prevent CPU exception when allocation is called from interrupt code CPU.DisableInterrupts(); @@ -322,6 +343,11 @@ public static int Collect() //Enable interrupts back CPU.EnableInterrupts(); + if (mMemeoryGate != null) + { + mMemeoryGate.Unlock(); + } + return freed; } From 0c5fdfdb6be0993ca9a7a6145b9a703b6d66341f Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Tue, 26 Dec 2023 11:02:45 +0100 Subject: [PATCH 10/15] =?UTF-8?q?=F0=9F=90=9B=20Fix=20IO=20ports=20call=20?= =?UTF-8?q?(now=20static=20call)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cosmos.Core/Processing/ProcessorScheduler.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/source/Cosmos.Core/Processing/ProcessorScheduler.cs b/source/Cosmos.Core/Processing/ProcessorScheduler.cs index 54ebde7e74..21f16b6249 100644 --- a/source/Cosmos.Core/Processing/ProcessorScheduler.cs +++ b/source/Cosmos.Core/Processing/ProcessorScheduler.cs @@ -23,18 +23,13 @@ public static void Initialize() ProcessContext.m_ContextList = context; ProcessContext.m_CurrentContext = context; - IOPort counter0 = new IOPort(0x40); - IOPort cmd = new IOPort(0x43); - int divisor = 1193182 / 25; - cmd.Byte = (0x06 | 0x30); - counter0.Byte = (byte)divisor; - counter0.Byte = (byte)(divisor >> 8); + IOPort.Write8(0x43, 0x06 | 0x30); // cmd + IOPort.Write8(0x40, (byte)divisor); // counter0 + IOPort.Write8(0x40, (byte)(divisor >> 8)); - IOPort pA1 = new IOPort(0xA1); - IOPort p21 = new IOPort(0xA1); - pA1.Byte = 0x00; - p21.Byte = 0x00; + IOPort.Write8(0xA1, 0x00); // pA1 + IOPort.Write8(0xA1, 0x00); // p21 } public static void EntryPoint() From 66fe85bd384356b2c3f328cf8937628fff9c564e Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Tue, 26 Dec 2023 11:03:22 +0100 Subject: [PATCH 11/15] =?UTF-8?q?=F0=9F=90=9B=20Fix=20build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/Cosmos.HAL2/Global.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Cosmos.HAL2/Global.cs b/source/Cosmos.HAL2/Global.cs index a8a41d7824..0af10fadbe 100644 --- a/source/Cosmos.HAL2/Global.cs +++ b/source/Cosmos.HAL2/Global.cs @@ -78,7 +78,7 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In //EHCI.InitDriver(); Console.WriteLine("Starting Processor Scheduler"); - mDebugger.Send("Processor Scheduler"); + debugger.Send("Processor Scheduler"); Core.Processing.ProcessorScheduler.Initialize(); if (InitNetwork) From d36bfd4f3ee4d3269b0130e4e2ac52936d5d3c44 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Tue, 26 Dec 2023 11:23:44 +0100 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=90=9B=20Fix=20build=20(wrong=20mSt?= =?UTF-8?q?ackContext=20path)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs index 5d49fd7012..61349c4bfb 100644 --- a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs +++ b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs @@ -129,9 +129,9 @@ public override void AssembleNew(Assembler aAssembler, object aMethodInfo) new LiteralAssemblerCode("mov fs, ax"); new LiteralAssemblerCode("mov gs, ax"); new LiteralAssemblerCode("mov eax, esp"); - XS.Set("static_field__Cosmos_Core_INTs_mStackContext", EAX, destinationIsIndirect: true); + XS.Set("static_field__A1Cosmos_Core_INTs_mStackContext", EAX, destinationIsIndirect: true); XS.Call(LabelName.Get(GetMethodDef(typeof(Cosmos.Core.Processing.ProcessorScheduler).Assembly, typeof(Cosmos.Core.Processing.ProcessorScheduler).FullName, "SwitchTask", true))); - XS.Set(EAX, "static_field__Cosmos_Core_INTs_mStackContext", sourceIsIndirect: true); + XS.Set(EAX, "static_field__A1Cosmos_Core_INTs_mStackContext", sourceIsIndirect: true); new LiteralAssemblerCode("mov esp, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov gs, eax"); From 8ae051b41b4a641998189f89a07867e399b7dec6 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Wed, 17 Jan 2024 16:20:31 +0100 Subject: [PATCH 13/15] =?UTF-8?q?=E2=9C=A8=20Use=20local=20APIC=20timer=20?= =?UTF-8?q?instead=20of=20PIT=20for=20scheduler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/Cosmos.Core/ACPI.cs | 877 +++++++++++++----- source/Cosmos.Core/LocalApic.cs | 130 +++ source/Cosmos.Core/MMIO.cs | 149 +++ source/Cosmos.Core/MemoryBlock.cs | 27 + .../Processing/ProcessorScheduler.cs | 20 +- source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs | 2 +- source/Cosmos.HAL2/ApicTimer.cs | 88 ++ source/Cosmos.HAL2/Global.cs | 42 +- 8 files changed, 1083 insertions(+), 252 deletions(-) create mode 100644 source/Cosmos.Core/LocalApic.cs create mode 100644 source/Cosmos.Core/MMIO.cs create mode 100644 source/Cosmos.HAL2/ApicTimer.cs diff --git a/source/Cosmos.Core/ACPI.cs b/source/Cosmos.Core/ACPI.cs index 20e4ef9fd8..8c910648cf 100644 --- a/source/Cosmos.Core/ACPI.cs +++ b/source/Cosmos.Core/ACPI.cs @@ -1,13 +1,49 @@ -using System; +using Cosmos.Debug.Kernel; +using System; +using System.Collections.Generic; +using System.IO; using System.Runtime.InteropServices; +using System.Text; namespace Cosmos.Core { + /// + /// PCI IRQ Routing information. + /// + public class IrqRouting + { + /// + /// The address of the PCI device. + /// + public uint Address; + + /// + /// The PCI pin number of the device. + /// + public byte Pin; + + /// + /// Source. + /// + public byte Source; + + /// + /// Source Index. + /// + public byte SourceIndex; + } + /// /// ACPI (Advanced Configuration and Power Interface) class. /// public unsafe class ACPI { + + /// + /// Debugger instance at the System ring, of the Global section. + /// + public static readonly Debugger debugger = new Debugger("Core"); + /// /// RSD table struct. /// @@ -18,29 +54,317 @@ public unsafe struct RSDPtr /// Signature. /// public fixed byte Signature[8]; + /// /// CheckSum /// public byte CheckSum; + /// /// OemID /// public fixed byte OemID[6]; + /// /// Revision /// public byte Revision; + /// /// RSDT Address /// public int RsdtAddress; }; - // New Port I/O + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AcpiHeader + { + /// + /// Signature. + /// + public fixed byte Signature[4]; + + /// + /// Length. + /// + public uint Length; + + /// + /// Revision. + /// + public byte Revision; + + /// + /// Checksum. + /// + public byte Checksum; + + /// + /// OEM ID. + /// + public fixed byte OEMID[6]; + + /// + /// OEM Table ID. + /// + public fixed byte OEMTableID[8]; + + /// + /// OEM Revision. + /// + public uint OEMRevision; + + /// + /// CreatorID. + /// + public uint CreatorID; + + /// + /// Creator Revision. + /// + public uint CreatorRevision; + }; + + /// + /// FADT struct. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct FADTPtr + { + /// + /// ACPI Header. + /// + public AcpiHeader Header; + + /// + /// Firmware Control. + /// + public uint FirmwareCtrl; + + /// + /// DSDT Signature. + /// + public uint Dsdt; + + public byte Reserved; + public byte PreferredPowerManagementProfile; + public ushort SCI_Interrupt; + public uint SMI_CommandPort; + + /// + /// ACPI Enable. + /// + public byte AcpiEnable; + + /// + /// ACPI Disable. + /// + public byte AcpiDisable; + + public byte S4BIOS_REQ; + public byte PSTATE_Control; + public uint PM1aEventBlock; + public uint PM1bEventBlock; + public uint PM1aControlBlock; + public uint PM1bControlBlock; + public uint PM2ControlBlock; + public uint PMTimerBlock; + public uint GPE0Block; + public uint GPE1Block; + public byte PM1EventLength; + public byte PM1ControlLength; + public byte PM2ControlLength; + public byte PMTimerLength; + public byte GPE0Length; + public byte GPE1Length; + public byte GPE1Base; + public byte CStateControl; + public ushort WorstC2Latency; + public ushort WorstC3Latency; + public ushort FlushSize; + public ushort FlushStride; + public byte DutyOffset; + public byte DutyWidth; + public byte DayAlarm; + public byte MonthAlarm; + public byte Century; + + public ushort BootArchitectureFlags; + + public byte Reserved2; + public uint Flags; + + // 12 public byte structure; see below for details + public GenericAddressStructure ResetReg; + + public byte ResetValue; + public byte Reserved3; + public byte Reserved34; + public byte Reserved35; + + // 64bit pointers - Available on ACPI 2.0+ + public ulong X_FirmwareControl; + public ulong X_Dsdt; + + public GenericAddressStructure X_PM1aEventBlock; + public GenericAddressStructure X_PM1bEventBlock; + public GenericAddressStructure X_PM1aControlBlock; + public GenericAddressStructure X_PM1bControlBlock; + public GenericAddressStructure X_PM2ControlBlock; + public GenericAddressStructure X_PMTimerBlock; + public GenericAddressStructure X_GPE0Block; + public GenericAddressStructure X_GPE1Block; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct GenericAddressStructure + { + public byte AddressSpace; + public byte BitWidth; + public byte BitOffset; + public byte AccessSize; + public ulong Address; + }; + /// - /// IO port. + /// MADT struct. /// - private static ushort smiIO, pm1aIO, pm1bIO; + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct MADTPtr + { + /// + /// ACPI Header. + /// + public AcpiHeader Header; + + /// + /// Local APIC Address. + /// + public uint LocalAPICAddress; + + /// + /// Flags. + /// + public uint Flags; + } + + /// + /// APIC Header struct. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ApicHeader + { + /// + /// APIC Type. + /// + public ApicType Type; + + /// + /// Length. + /// + public byte Length; + } + + /// + /// APIC Type enum. + /// + public enum ApicType : byte + { + LocalAPIC, + IOAPIC, + InterruptOverride + } + + /// + /// ApicLocalApic struct. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ApicLocalApic + { + /// + /// APIC Header. + /// + public ApicHeader Header; + + /// + /// ACPI Processor ID. + /// + public byte AcpiProcessorId; + + /// + /// APIC ID. + /// + public byte ApicId; + + /// + /// APIC Flags. + /// + public uint Flags; + } + + /// + /// ApicIOApic struct. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ApicIOApic + { + /// + /// APIC Header. + /// + public ApicHeader Header; + + /// + /// APIC ID. + /// + public byte IOApicId; + + /// + /// Reserved. + /// + public byte Reserved; + + /// + /// IO APIC Base Address. + /// + public uint IOApicAddress; + + /// + /// Global System Interrupt Base Address. + /// + public uint GlobalSystemInterruptBase; + } + + /// + /// ApicInterruptOverride struct. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ApicInterruptOverride + { + /// + /// APIC Header. + /// + public ApicHeader Header; + + /// + /// Bus. + /// + public byte Bus; + + /// + /// Source. + /// + public byte Source; + + /// + /// Interrupt. + /// + public uint Interrupt; + + /// + /// Floags. + /// + public ushort Flags; + } // ACPI variables /// @@ -56,6 +380,10 @@ public unsafe struct RSDPtr /// private static byte ACPI_DISABLE; /// + /// Reset value to write into reset register when you need to reboot + /// + private static byte ResetValue; + /// /// PM1a CNT /// private static int* PM1a_CNT; @@ -79,6 +407,30 @@ public unsafe struct RSDPtr /// PM1 CNT LEN1 /// private static byte PM1_CNT_LEN; + /// + /// Global MADT. + /// + public static MADTPtr* MADT; + /// + /// Global IO APIC. + /// + public static ApicIOApic* IOAPIC; + /// + /// FADT table + /// + public static FADTPtr* FADT; + + public static uint DSDTLenght = 0; + + /// + /// PCI IRQ Routing Table. + /// + public static List IrqRoutingTable; + + /// + /// PCI IRQ Routing Table. + /// + public static List LocalApicCpus; /// /// Check ACPI header. @@ -91,71 +443,6 @@ static int acpiCheckHeader(byte* ptr, string sig) return Compare(sig, ptr); } - /// - /// FACP. - /// - private static byte* Facp = null; - /// - /// FACP struct. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct FACP - { - /// - /// Signature. - /// - public fixed byte Signature[4]; - /// - /// Length. - /// - public int Length; - - /// - /// Unused. - /// - public fixed byte unneded1[40 - 8]; - /// - /// DSDT. - /// - public int* DSDT; - /// - /// Unused. - /// - public fixed byte unneded2[48 - 44]; - /// - /// SMI CMD. - /// - public int* SMI_CMD; - /// - /// ACPI ENABLE. - /// - public byte ACPI_ENABLE; - /// - /// ACPI DISABLE. - /// - public byte ACPI_DISABLE; - /// - /// Unused. - /// - public fixed byte unneded3[64 - 54]; - /// - /// PM1a CNT BLK. - /// - public int* PM1a_CNT_BLK; - /// - /// PM1b CNT BLK. - /// - public int* PM1b_CNT_BLK; - /// - /// Unused. - /// - public fixed byte unneded4[89 - 72]; - /// - /// PM1 CNT LEN. - /// - public byte PM1_CNT_LEN; - }; - /// /// Compare string to byte array. /// @@ -164,7 +451,7 @@ struct FACP /// 0 - identical, -1 different. static int Compare(string c1, byte* c2) { - for (int i = 0; i < c1.Length; i++) + for (var i = 0; i < c1.Length; i++) { if (c1[i] != c2[i]) { return -1; } } @@ -179,9 +466,9 @@ static int Compare(string c1, byte* c2) static bool Check_RSD(uint address) { byte sum = 0; - byte* check = (byte*)address; + var check = (byte*)address; - for (int i = 0; i < 20; i++) + for (var i = 0; i < 20; i++) { sum += *check++; } @@ -213,17 +500,16 @@ public static void Start(bool initialize = true, bool enable = true) /// Thrown on IO error. public static void Shutdown() { - Console.Clear(); if (PM1a_CNT == null) { Init(); } - IOPort.Write16(pm1aIO, (ushort)(SLP_TYPa | SLP_EN)); + IOPort.Write16((ushort)PM1a_CNT, (ushort)(SLP_TYPa | SLP_EN)); if (PM1b_CNT != null) { - IOPort.Write16(pm1bIO, (ushort)(SLP_TYPb | SLP_EN)); + IOPort.Write16((ushort)PM1b_CNT, (ushort)(SLP_TYPb | SLP_EN)); } CPU.Halt(); @@ -236,7 +522,22 @@ public static void Shutdown() /// Thrown always. public static void Reboot() { - throw new NotImplementedException("ACPI Reset not implemented yet."); //TODO + if (PM1a_CNT == null) + { + Init(); + } + + var header = FADT->Header; + if (header.Revision >= 2 && (FADT->Flags & (1 << 10)) != 0) + { + IOPort.Write16((ushort)FADT->ResetReg.Address, ResetValue); + } + else + { + throw new Exception("Hardware does not support ACPI reboot."); + } + + throw new Exception("ACPI reboot failed."); } /// @@ -245,106 +546,283 @@ public static void Reboot() /// true on success, false on failure. private static bool Init() { - byte* ptr = (byte*)RSDPAddress(); - int addr = 0; + IOAPIC = null; + IrqRoutingTable = new List(); + LocalApicCpus = new List(); + + var rsdp = RSDPAddress(); + var ptr = (byte*)rsdp; + + Global.debugger.Send("ACPI v" + rsdp->Revision); - for (int i = 19; i >= 16; i--) + var rsdt = (AcpiHeader*)rsdp->RsdtAddress; + ptr = (byte*)rsdt; + + var p = (uint*)(rsdt + 1); + var end = (uint*)((byte*)rsdt + rsdt->Length); + + while (p < end) { - addr += *(ptr + i); - addr = i == 16 ? addr : addr << 8; - } + var address = *p++; - ptr = (byte*)addr; - ptr += 4; addr = 0; + ParseDT((AcpiHeader*)address); + } - for (int i = 3; i >= 0; i--) + if (LocalApicCpus.Count > 0) { - addr += *(ptr + i); - addr = i == 0 ? addr : addr << 8; + Global.debugger.Send("Found " + LocalApicCpus.Count + " CPUs via MADT."); } - int length = addr; - ptr -= 4; + return true; + } + + private static uint SdtLength = 0; + + private static void ReadHeader(BinaryReader _reader) + { + Global.debugger.Send("SDT header:"); + + //Signature + Global.debugger.Send("\tSignature: " + Encoding.ASCII.GetString(_reader.ReadBytes(4))); + + //Length + SdtLength = _reader.ReadUInt32(); + Global.debugger.Send("\tLendth: " + SdtLength.ToString()); + + //Revision + Global.debugger.Send("\tRevision: " + _reader.ReadByte().ToString()); - if (ptr != null && acpiCheckHeader(ptr, "RSDT") == 0) + //Checksum + Global.debugger.Send("\tChecksum: " + _reader.ReadByte().ToString()); + + //OEM ID + Global.debugger.Send("\tOEM ID: " + Encoding.ASCII.GetString(_reader.ReadBytes(6))); + + //OEMTableID + Global.debugger.Send("\tOEMTableID: " + Encoding.ASCII.GetString(_reader.ReadBytes(8))); + + //OEMRevision + Global.debugger.Send("\tOEMRevision: " + _reader.ReadUInt32().ToString()); + + //OEMRevision + Global.debugger.Send("\tCreatorID: " + _reader.ReadUInt32().ToString()); + + //OEMRevision + Global.debugger.Send("\tCreatorRevision: " + _reader.ReadUInt32().ToString()); + } + + private static void ParseS5() + { + byte* S5Addr = (byte*)FADT->Dsdt; + + while (0 < DSDTLenght--) { - addr = 0; - int entrys = length; - entrys = (entrys - 36) / 4; - ptr += 36; - byte* yeuse; + if (Compare("_S5_", S5Addr) == 0) + { + break; + } + S5Addr++; + } - while (0 < entrys--) + if (DSDTLenght > 0) + { + if ((*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) && *(S5Addr + 4) == 0x12) { - for (int i = 3; i >= 0; i--) + S5Addr += 5; + S5Addr += ((*S5Addr & 0xC0) >> 6) + 2; + if (*S5Addr == 0x0A) + { + S5Addr++; + } + SLP_TYPa = (short)(*(S5Addr) << 10); + S5Addr++; + if (*S5Addr == 0x0A) { - addr += *(ptr + i); - addr = i == 0 ? addr : addr << 8; + S5Addr++; } + SLP_TYPb = (short)(*(S5Addr) << 10); + + Global.debugger.Send("SLP_TYPa=" + SLP_TYPa); + Global.debugger.Send("SLP_TYPb=" + SLP_TYPb); + } + } + } + + private static void ParsePRT() + { + /* + if (DSDTLenght > 0) + { + var dsdtBlock = new MemoryBlock08(FADT->Dsdt + (uint)sizeof(AcpiHeader), SdtLength - (uint)sizeof(AcpiHeader)); - yeuse = (byte*)addr; - Facp = yeuse; + Stream stream = new MemoryStream(dsdtBlock.ToArray()); - if (acpiCheckHeader((byte*)facpget(0), "DSDT") == 0) + Global.debugger.Send("Create parser..."); + + var root = new Parser(stream); + + Global.debugger.Send("Parse first node..."); + + var node = root.Parse(); + foreach (var item in node.Nodes) + { + Global.debugger.Send("Node: " + item.Name); + } + }*/ + } + + private static void ParseDT(AcpiHeader* hdr) + { + var signature = Encoding.ASCII.GetString(hdr->Signature, 4); + + Global.debugger.Send(signature + " detected"); + + if (signature == "FACP") + { + Global.debugger.Send("Parse FACP"); + + FADT = (FADTPtr*)hdr; + + SMI_CMD = (int*)FADT->SMI_CommandPort; + ACPI_ENABLE = FADT->AcpiEnable; + ACPI_DISABLE = FADT->AcpiDisable; + PM1a_CNT = (int*)FADT->PM1aControlBlock; + PM1b_CNT = (int*)FADT->PM1bControlBlock; + PM1_CNT_LEN = FADT->PM1ControlLength; + SLP_EN = 1 << 13; + + + if (acpiCheckHeader((byte*)FADT->Dsdt, "DSDT") == 0) + { + uint dsdtAddress = FADT->Dsdt; + uint dsdtLength = (uint)(*((int*)FADT->Dsdt + 1) - sizeof(AcpiHeader)); + + var dsdtHeader = new MemoryBlock08(dsdtAddress, 36); + var _reader = new BinaryReader(new MemoryStream(dsdtHeader.ToArray())); + + ReadHeader(_reader); + + Global.debugger.Send("Parsing _S5..."); + + ParseS5(); + + Global.debugger.Send("Parsing _PRT..."); + + ParsePRT(); + } + } + else if (signature == "APIC") + { + Global.debugger.Send("Parse APIC"); + + MADT = (MADTPtr*)hdr; + + var p = (byte*)(MADT + 1); + var end = (byte*)MADT + MADT->Header.Length; + while (p < end) + { + var header = (ApicHeader*)p; + var type = header->Type; + var length = header->Length; + + if (type == ApicType.LocalAPIC) { - byte* S5Addr = (byte*)facpget(0) + 36; - int dsdtLength = *(facpget(0) + 1) - 36; + var pic = (ApicLocalApic*)p; - while (0 < dsdtLength--) + if (((pic->Flags & 1) ^ ((pic->Flags >> 1) & 1)) != 0) { - if (Compare("_S5_", S5Addr) == 0) - { - break; - } - S5Addr++; - } + LocalApicCpus.Add(pic->ApicId); - if (dsdtLength > 0) + Global.debugger.Send("Found APIC " + (ulong)pic->ApicId + " (Address:0x" + ((ulong)MADT->LocalAPICAddress).ToString("X") + ", Processor ID:" + pic->AcpiProcessorId + ")"); + } + } + else if (type == ApicType.IOAPIC) + { + var ioapic = (ApicIOApic*)p; + if (IOAPIC == null) { - if ((*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) && *(S5Addr + 4) == 0x12) - { - S5Addr += 5; - S5Addr += ((*S5Addr & 0xC0) >> 6) + 2; - if (*S5Addr == 0x0A) - { - S5Addr++; - } - SLP_TYPa = (short)(*S5Addr << 10); - S5Addr++; - if (*S5Addr == 0x0A) - { - S5Addr++; - } - SLP_TYPb = (short)(*S5Addr << 10); - SMI_CMD = facpget(1); - ACPI_ENABLE = facpbget(0); - ACPI_DISABLE = facpbget(1); - PM1a_CNT = facpget(2); - PM1b_CNT = facpget(3); - PM1_CNT_LEN = facpbget(3); - SLP_EN = 1 << 13; - - smiIO = (ushort)SMI_CMD; - pm1aIO = (ushort)PM1a_CNT; - pm1bIO = (ushort)PM1b_CNT; - - return true; - } + IOAPIC = ioapic; } + Global.debugger.Send("Found IO APIC " + (ulong)ioapic->IOApicId + " (Address:0x" + ((ulong)ioapic->IOApicAddress).ToString("X") + ", GSIB:" + (ulong)ioapic->GlobalSystemInterruptBase + ")"); } - ptr += 4; + else if (type == ApicType.InterruptOverride) + { + var ovr = (ApicInterruptOverride*)p; + + Global.debugger.Send("Found APIC Interrupt Override (Bus: " + ((ulong)ovr->Bus).ToString() + ", Source:" + ((ulong)ovr->Source).ToString() + ", Interrupt:0x" + ((ulong)ovr->Interrupt).ToString("X") + ", Flags:" + ((ulong)ovr->Flags).ToString() + ")"); + } + + p += length; } } + } + + /* + private static void PopulateNode(ParseNode op) + { + //Recursive function does a null reference exception trick the matrice with a Stack and iterative function + var sthack = new Stack(); + + sthack.Push(op); + + while (sthack.Count != 0) + { + ParseNode current = sthack.Pop(); + + if (current.Arguments.Count > 0) + { + SearchPackage(current); + } - return false; + if (current != null) + { + for (int i = current.Nodes.Count - 1; i >= 0; i--) + { + sthack.Push(current.Nodes[i]); + } + } + } } + + private static void SearchPackage(ParseNode op) + { + for (int x = 0; x < op.Op.ParseArgs.Length; x++) + { + if (op.Op.ParseArgs[x] == ParseArgFlags.DataObjectList || op.Op.ParseArgs[x] == ParseArgFlags.TermList || op.Op.ParseArgs[x] == ParseArgFlags.ObjectList) + continue; + + if (op.Arguments[x].ToString() == "Package") + { + Global.debugger.Send("Package found!"); + + //var arg = (ParseNode)op.Arguments[x]; + + /* + for (int y = 0; y < arg.Nodes.Count; y++) + { + List package = arg.Nodes[y].Nodes; + + var irqRouting = new IrqRouting() + { + Address = (uint)package[0].ConstantValue, + Pin = (byte)package[1].ConstantValue, + Source = (byte)package[2].ConstantValue, + SourceIndex = (byte)package[3].ConstantValue + }; + + IrqRoutingTable.Add(irqRouting); + } + + } + } + }*/ + /// /// Enable ACPI. /// public static void Enable() { - smiIO = ACPI_ENABLE; } /// @@ -352,14 +830,13 @@ public static void Enable() /// public static void Disable() { - smiIO = ACPI_DISABLE; } /// /// Get the RSDP address. /// /// uint value. - private static unsafe uint RSDPAddress() + private static unsafe RSDPtr* RSDPAddress() { for (uint addr = 0xE0000; addr < 0x100000; addr += 4) { @@ -367,118 +844,52 @@ private static unsafe uint RSDPAddress() { if (Check_RSD(addr)) { - return addr; + return (RSDPtr*)addr; } } } - uint ebda_address = *(uint*)0x040E; - ebda_address = (ebda_address * 0x10) & 0x000fffff; + var ebda_address = *(uint*)0x040E; + ebda_address = ebda_address * 0x10 & 0x000fffff; - for (uint addr = ebda_address; addr < ebda_address + 1024; addr += 4) + for (var addr = ebda_address; addr < ebda_address + 1024; addr += 4) { if (Compare("RSD PTR ", (byte*)addr) == 0) { - return addr; + return (RSDPtr*)addr; } } - return 0; + return null; } - /// - /// Check RSDT table - /// - /// A pointer to the RSDT - /// RSDT table address - private static uint* acpiCheckRSDPtr(uint* ptr) + public static uint RemapIRQ(uint irq) { - string sig = "RSD PTR "; - var rsdp = (RSDPtr*)ptr; + var p = (byte*)(MADT + 1); + var end = (byte*)MADT + MADT->Header.Length; - byte* bptr; - byte check = 0; - int i; - - if (Compare(sig, (byte*)rsdp) == 0) + while (p < end) { - bptr = (byte*)ptr; + var header = (ApicHeader*)p; + var type = header->Type; + var length = header->Length; - for (i = 0; i < 20; i++) + if (type == ApicType.InterruptOverride) { - check += *bptr; - bptr++; - } + var ovr = (ApicInterruptOverride*)p; - if (check == 0) - { - Compare("RSDT", (byte*)rsdp->RsdtAddress); - - if (rsdp->RsdtAddress != 0) + if (ovr->Source == irq) { - return (uint*)rsdp->RsdtAddress; + Global.debugger.Send("IRQ" + irq + " remapped to IRQ" + ovr->Interrupt); + + return ovr->Interrupt; } } - } - - return null; - } - /// - /// Get data from the FACP table. - /// - /// Index number of the data to get. - /// - /// 0 - ACPI ENABLE - /// 1 - ACPI DISABLE - /// 2 - PM1 CNT LEN - /// other - 0 - /// - /// - /// byte value. - private static byte facpbget(int number) - { - switch (number) - { - case 0: - return *(Facp + 52); - case 1: - return *(Facp + 53); - case 2: - return *(Facp + 89); - default: - return 0; + p += length; } - } - /// - /// Get pointer to the data on the FACP. - /// - /// Index number of the data to get. - /// - /// 0 - DSDT - /// 1 - SMI CMD - /// 2 - PM1a - /// 3 - PM1b - /// other - null - /// - /// - /// int pointer. - private static int* facpget(int number) - { - switch (number) - { - case 0: - return (int*)*(int*)(Facp + 40); - case 1: - return (int*)*(int*)(Facp + 48); - case 2: - return (int*)*(int*)(Facp + 64); - case 3: - return (int*)*(int*)(Facp + 68); - default: - return null; - } + return irq; } } } \ No newline at end of file diff --git a/source/Cosmos.Core/LocalApic.cs b/source/Cosmos.Core/LocalApic.cs new file mode 100644 index 0000000000..1ac1c45710 --- /dev/null +++ b/source/Cosmos.Core/LocalApic.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Cosmos.Core.MemoryGroup; + +namespace Cosmos.Core +{ + /// + /// Local APIC class. + /// + public static unsafe class LocalAPIC + { + public const ushort LAPIC_ID = 0x0020; + public const ushort LAPIC_VER = 0x0030; + public const ushort LAPIC_TPR = 0x0080; + public const ushort LAPIC_APR = 0x0090; + public const ushort LAPIC_PPR = 0x00a0; + public const ushort LAPIC_EOI = 0x00b0; + public const ushort LAPIC_RRD = 0x00c0; + public const ushort LAPIC_LDR = 0x00d0; + public const ushort LAPIC_DFR = 0x00e0; + public const ushort LAPIC_SVR = 0x00f0; + public const ushort LAPIC_ISR = 0x0100; + public const ushort LAPIC_TMR = 0x0180; + public const ushort LAPIC_IRR = 0x0200; + public const ushort LAPIC_ESR = 0x0280; + public const ushort LAPIC_ICRLO = 0x0300; + public const ushort LAPIC_ICRHI = 0x0310; + public const ushort LAPIC_TIMER = 0x0320; + public const ushort LAPIC_THERMAL = 0x0330; + public const ushort LAPIC_PERF = 0x0340; + public const ushort LAPIC_LINT0 = 0x0350; + public const ushort LAPIC_LINT1 = 0x0360; + public const ushort LAPIC_ERROR = 0x0370; + public const ushort LAPIC_TICR = 0x0380; + public const ushort LAPIC_TCCR = 0x0390; + public const ushort LAPIC_TDCR = 0x03e0; + + public const ushort ICR_FIXED = 0x00000000; + public const ushort ICR_LOWEST = 0x00000100; + public const ushort ICR_SMI = 0x00000200; + public const ushort ICR_NMI = 0x00000400; + public const ushort ICR_INIT = 0x00000500; + public const ushort ICR_STARTUP = 0x00000600; + + public const ushort ICR_PHYSICAL = 0x00000000; + public const ushort ICR_LOGICAL = 0x00000800; + + public const ushort ICR_IDLE = 0x00000000; + public const ushort ICR_SEND_PENDING = 0x00001000; + + public const ushort ICR_DEASSERT = 0x00000000; + public const ushort ICR_ASSERT = 0x00004000; + + public const ushort ICR_EDGE = 0x00000000; + public const ushort ICR_LEVEL = 0x00008000; + + public const int ICR_NO_SHORTHAND = 0x00000000; + public const int ICR_SELF = 0x00040000; + public const int ICR_ALL_INCLUDING_SELF = 0x00080000; + public const int ICR_ALL_EXCLUDING_SELF = 0x000c0000; + + public const int ICR_DESTINATION_SHIFT = 24; + + /// + /// Local APIC Base Address. + /// + private static uint Address = 0; + + /// + /// Initialize local APIC. + /// + public static void Initialize() + { + //TODO: Fix ACPI tables on Bochs + if (ACPI.LocalApicCpus.Count == 0) + { + //No APIC detected, hardcode APIC address + Address = 0xFEE00000; + } + else + { + Address = ACPI.MADT->LocalAPICAddress; + } + + Out(LAPIC_TPR, 0); + Out(LAPIC_SVR, 0x100 | 0xFF); + + Global.debugger.Send("Local APIC " + GetId() + " initialized"); + } + + /// + /// IO APIC MMIO Out. + /// + /// IO APIC Register. + /// Data. + public static void Out(uint reg, uint val) + { + MMIOBase.Write32(Address + reg, val); + } + + /// + /// IO APIC MMIO In. + /// + /// IO APIC Register. + public static uint In(uint reg) + { + return MMIOBase.Read32(Address + reg); + } + + /// + /// End of Interrupt. + /// + public static void EndOfInterrupt() + { + Out(LAPIC_EOI, 0); + } + + /// + /// Get Local APIC ID. + /// + /// integer value. + public static uint GetId() + { + return In(LAPIC_ID) >> 24; + } + } +} \ No newline at end of file diff --git a/source/Cosmos.Core/MMIO.cs b/source/Cosmos.Core/MMIO.cs new file mode 100644 index 0000000000..ed943a5e0f --- /dev/null +++ b/source/Cosmos.Core/MMIO.cs @@ -0,0 +1,149 @@ +using IL2CPU.API.Attribs; + +namespace Cosmos.Core +{ + /// + /// MMIOBase abstract class. + /// + public unsafe abstract class MMIOBase + { + /// + /// Address. + /// + protected readonly uint Address; + + // all ctors are internal - Only Core ring can create it.. but hardware ring can use it. + /// + /// Create new instance of the class. + /// + /// An address. + protected MMIOBase(uint address) + { + Address = address; + } + + /// + /// Create new instance of the class. + /// + /// A base address. + /// An offset from the base address. + protected MMIOBase(uint address, uint aOffset) + { + // C# math promotes things to integers, so we have this constructor + // to relieve the use from having to do so many casts + Address = address + aOffset; + } + + /// + /// Write byte to adress. + /// + /// An address to write to. + /// A data. + public static void Write8(uint address, byte aData) + { + *(uint*)address = aData; + } + + /// + /// Write Word to address. + /// + /// A address to write to. + /// A data. + public static void Write16(uint address, ushort aData) + { + *(uint*)address = aData; + } + + /// + /// Write DWord to address. + /// + /// An address to write to. + /// A data. + public static void Write32(uint address, uint aData) + { + *(uint*)address = aData; + } + + /// + /// Read byte from address. + /// + /// An address to read from. + /// byte value. + public static byte Read8(uint address) + { + return (byte)*(uint*)address; + } + + /// + /// Read Word from address. + /// + /// An address to read from. + /// ushort value. + public static ushort Read16(uint address) + { + return (ushort)*(uint*)address; + } + + /// + /// Read DWord from address. + /// + /// An address to read from. + /// uint value. + public static uint Read32(uint address) + { + return *(uint*)address; + } + } + + /// + /// MMIO class. Used to read and write to address. + /// + public class MMIO : MMIOBase + { + /// + /// Create new instance of the class. + /// + /// An address. + public MMIO(uint address) + : base(address) + { + } + + /// + /// Create new instance of the class. + /// + /// A base address. + /// Offset from the base address. + public MMIO(uint address, uint aOffset) + : base(address, aOffset) + { + } + + /// + /// Get and set Byte value in address. + /// + public byte Byte + { + get => Read8(Address); + set => Write8(Address, value); + } + + /// + /// Get and set Word value in address. + /// + public ushort Word + { + get => Read16(Address); + set => Write16(Address, value); + } + + /// + /// Get and set DWord value in address. + /// + public uint DWord + { + get => Read32(Address); + set => Write32(Address, value); + } + } +} \ No newline at end of file diff --git a/source/Cosmos.Core/MemoryBlock.cs b/source/Cosmos.Core/MemoryBlock.cs index bed3816176..31d94fa613 100644 --- a/source/Cosmos.Core/MemoryBlock.cs +++ b/source/Cosmos.Core/MemoryBlock.cs @@ -486,6 +486,33 @@ public unsafe byte this[uint aByteOffset] (*(byte*)(Base + aByteOffset)) = value; } } + + /// + /// Convert part for the memory block to array. + /// + /// A starting position of the data at the source memory block. + /// A index to be the staring index at the destination array. + /// Number of bytes to get. + /// uint array. + public unsafe byte[] ToArray(int aStart, int aIndex, int aCount) + { + byte* xDest = (byte*)(Base + aStart); + byte[] array = new byte[aCount]; + fixed (byte* aArrayPtr = array) + { + MemoryOperations.Copy(aArrayPtr + aIndex, xDest, aCount); + } + return array; + } + + /// + /// Convert the memory block to array. + /// + /// uint array. + public byte[] ToArray() + { + return ToArray(0, 0, (int)Size); + } } /// diff --git a/source/Cosmos.Core/Processing/ProcessorScheduler.cs b/source/Cosmos.Core/Processing/ProcessorScheduler.cs index 21f16b6249..b598d1aedd 100644 --- a/source/Cosmos.Core/Processing/ProcessorScheduler.cs +++ b/source/Cosmos.Core/Processing/ProcessorScheduler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Cosmos.Core.Memory; using IL2CPU.API.Attribs; namespace Cosmos.Core.Processing @@ -22,14 +23,6 @@ public static void Initialize() context.parent = 0; ProcessContext.m_ContextList = context; ProcessContext.m_CurrentContext = context; - - int divisor = 1193182 / 25; - IOPort.Write8(0x43, 0x06 | 0x30); // cmd - IOPort.Write8(0x40, (byte)divisor); // counter0 - IOPort.Write8(0x40, (byte)(divisor >> 8)); - - IOPort.Write8(0xA1, 0x00); // pA1 - IOPort.Write8(0xA1, 0x00); // p21 } public static void EntryPoint() @@ -40,11 +33,10 @@ public static void EntryPoint() while (true) { } // remove from thread pool later } - public static int interruptCount; + public static uint TickFrequency = 1; public static void SwitchTask() { - interruptCount++; if (ProcessContext.m_CurrentContext != null) { ProcessContext.Context ctx = ProcessContext.m_ContextList; @@ -64,7 +56,9 @@ public static void SwitchTask() { if (ctx.state == ProcessContext.Thread_State.WAITING_SLEEP) { - ctx.arg -= 1000 / 25; + ctx.arg -= 1000 / (int)TickFrequency; + Cosmos.Core.Global.debugger.Send("ctx.arg=" + ctx.arg); + Cosmos.Core.Global.debugger.Send("TickFrequency=" + TickFrequency); if (ctx.arg <= 0) { ctx.state = ProcessContext.Thread_State.ALIVE; @@ -90,8 +84,8 @@ public static void SwitchTask() ProcessContext.m_CurrentContext.age = ProcessContext.m_CurrentContext.priority; INTs.mStackContext = ProcessContext.m_CurrentContext.esp; } - Global.PIC.EoiMaster(); - Global.PIC.EoiSlave(); + + LocalAPIC.EndOfInterrupt(); } } } diff --git a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs index 61349c4bfb..f48e403335 100644 --- a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs +++ b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs @@ -80,7 +80,7 @@ public override void AssembleNew(Assembler aAssembler, object aMethodInfo) } XS.Push((uint)j); - if (j != 0x20) + if (j != 0x28) { XS.PushAllRegisters(); diff --git a/source/Cosmos.HAL2/ApicTimer.cs b/source/Cosmos.HAL2/ApicTimer.cs new file mode 100644 index 0000000000..f6b7fa9a1e --- /dev/null +++ b/source/Cosmos.HAL2/ApicTimer.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Cosmos.Core; +using Cosmos.Core.MemoryGroup; + +namespace Cosmos.HAL +{ + /// + /// Local APIC Timer class. + /// + public static class ApicTimer + { + /// + /// Tick Counter. + /// + public static uint Tick = 0; + + /// + /// Tick Frequency. + /// + public static uint TickFrequency = 0; + + /// + /// Initialize local APIC timer. + /// + public static void Initialize() + { + // setup timer, Intel IA manual 10-16 Vol. 3A + LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0xB); // divide timer counts by 1 + + Calibrate(); + + if (TickFrequency == 0) + { + throw new Exception("APIC timer is not calibrated"); + } + + LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x20000 | 0x28); // periodic, bind to corresponding IRQ (this RTC IRQ but unused so...) + LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0xB); + + Global.debugger.Send("Local APIC Timer Initialized"); + } + + public static void Start() + { + SetTimerCount(TickFrequency); + } + + /// + /// Stop local APIC timer. + /// + public static void Stop() + { + LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x10000); + } + + public static void SetTimerCount(uint count) + { + LocalAPIC.Out(LocalAPIC.LAPIC_TICR, count); + } + + public static void Calibrate() + { + Global.debugger.Send("Calibrating APIC timer..."); + + SetTimerCount(0xFFFFFFFF); // Set APIC init counter to -1 + + Global.debugger.Send("PIT START"); + + Global.PIT.Wait(10000); // PIT sleep for 1000ms + + Global.debugger.Send("PIT END"); + + Stop(); + + ulong ticks = 0xFFFFFFFF - LocalAPIC.In(LocalAPIC.LAPIC_TCCR); // Now we know how often the APIC timer has ticked in 10ms + + Global.debugger.Send("APIC timer ticks per 1s: " + ticks); + + TickFrequency = (uint)(ticks); + + Global.debugger.Send("APIC timer tick frequency: " + TickFrequency); + } + } +} \ No newline at end of file diff --git a/source/Cosmos.HAL2/Global.cs b/source/Cosmos.HAL2/Global.cs index 0af10fadbe..2768b13d09 100644 --- a/source/Cosmos.HAL2/Global.cs +++ b/source/Cosmos.HAL2/Global.cs @@ -5,6 +5,7 @@ using Cosmos.Debug.Kernel; using Cosmos.HAL.BlockDevice; using Cosmos.HAL.Network; +using static Cosmos.HAL.PIT; namespace Cosmos.HAL { @@ -12,13 +13,13 @@ public static class Global { public static readonly Debugger debugger = new("Global"); - public static PIT PIT = new(); + public static PIT PIT; // Must be static init, other static inits rely on it not being null public static TextScreenBase TextScreen = new TextScreen(); public static PCI Pci; - public static readonly PS2Controller PS2Controller = new(); + public static PS2Controller PS2Controller; // TODO: continue adding exceptions to the list, as HAL and Core would be documented. /// @@ -46,14 +47,39 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In // system level and not accessible from Core. Need to think about this // for the future. Console.Clear(); - Console.WriteLine("Finding PCI Devices"); - debugger.Send("PCI Devices"); - PCI.Setup(); Console.WriteLine("Starting ACPI"); debugger.Send("ACPI Init"); ACPI.Start(); + Console.WriteLine("Starting PIT"); + debugger.Send("PIT init"); + PIT = new(); + + Global.debugger.Send("PIT START"); + + Global.PIT.Wait(10000); // PIT sleep for 10000ms + + Global.debugger.Send("PIT END"); + + Console.WriteLine("Starting APIC"); + debugger.Send("Local APIC Init"); + LocalAPIC.Initialize(); + + Global.debugger.Send("PIT START"); + + Global.PIT.Wait(10000); // PIT sleep for 10000ms + + Global.debugger.Send("PIT END"); + + Console.WriteLine("Finding PCI Devices"); + debugger.Send("PCI Devices"); + PCI.Setup(); + + Console.WriteLine("Starting PS/2"); + debugger.Send("PS/2 init"); + PS2Controller = new(); + // http://wiki.osdev.org/%228042%22_PS/2_Controller#Initialising_the_PS.2F2_Controller // TODO: USB should be initialized before the PS/2 controller // TODO: ACPI should be used to check if a PS/2 controller exists @@ -81,6 +107,12 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In debugger.Send("Processor Scheduler"); Core.Processing.ProcessorScheduler.Initialize(); + debugger.Send("Local APIC Timer Init"); + ApicTimer.Initialize(); + ApicTimer.Start(); + + Core.Processing.ProcessorScheduler.TickFrequency = ApicTimer.TickFrequency; + if (InitNetwork) { debugger.Send("Network Devices Init"); From fd497d1005a9f53b2074bdb82b741fef270128c1 Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Tue, 23 Jan 2024 12:03:31 +0100 Subject: [PATCH 14/15] =?UTF-8?q?=F0=9F=90=9B=20Fix=20scheduler=20with=20l?= =?UTF-8?q?ocal=20apic=20timer=20(now=20works)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tests/Kernels/ThreadingTest/Kernel.cs | 23 +++--- .../Processing/ProcessorScheduler.cs | 15 ++-- source/Cosmos.HAL2/ApicTimer.cs | 79 ++++++++----------- source/Cosmos.HAL2/Global.cs | 38 +++------ 4 files changed, 62 insertions(+), 93 deletions(-) diff --git a/Tests/Kernels/ThreadingTest/Kernel.cs b/Tests/Kernels/ThreadingTest/Kernel.cs index 9d2504f3d8..cb86220ebb 100644 --- a/Tests/Kernels/ThreadingTest/Kernel.cs +++ b/Tests/Kernels/ThreadingTest/Kernel.cs @@ -2,43 +2,40 @@ using Sys = Cosmos.System; using Cosmos.System; using Cosmos.TestRunner; -using Console = System.Console; namespace ThreadingTests { public class Kernel : Sys.Kernel { int variable = 0; - int variableTwo = 0; - int variableThree = 0; protected override void BeforeRun() { - Console.WriteLine("Cosmos booted successfully. Let's Test Threading!"); + Global.Debugger.Send("Cosmos booted successfully. Let's Test Threading!"); } protected override void Run() { try { + Global.Debugger.Send("[MainThread] Inside Run method! Starting threads..."); + var threadOne = new Thread(ThreadOne); var threadTwo = new Thread(ThreadTwo); threadOne.Start(); threadTwo.Start(); - Console.WriteLine("Inside Run method!"); - variableThree = 3; //Since Run is not a thread call PIT wait - System.Threading.Thread.Sleep(3000); + System.Threading.Thread.Sleep(4000); //Cosmos.HAL.Global.PIT.Wait(3000); - Console.WriteLine("Waited 3 second."); + Global.Debugger.Send("[MainThread] Waited 4 sec."); Assert.AreEqual(variable, 1, "Changing global variable from thread works"); @@ -61,19 +58,23 @@ public void ThreadOne() //Make thread WAITING Thread.Sleep(1000); + Global.Debugger.Send("[FirstThread] Hello"); + variable = 1; - Console.WriteLine("Inside first thread!"); + Global.Debugger.Send("[FirstThread] Bye"); } public void ThreadTwo() { //Make thread WAITING - Thread.Sleep(1000); + Thread.Sleep(2000); + + Global.Debugger.Send("[SecondThread] Hello"); variableTwo = 2; - Console.WriteLine("Inside second thread!"); + Global.Debugger.Send("[SecondThread] Bye"); } } } diff --git a/source/Cosmos.Core/Processing/ProcessorScheduler.cs b/source/Cosmos.Core/Processing/ProcessorScheduler.cs index b598d1aedd..d265d5e77e 100644 --- a/source/Cosmos.Core/Processing/ProcessorScheduler.cs +++ b/source/Cosmos.Core/Processing/ProcessorScheduler.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Text; -using Cosmos.Core.Memory; using IL2CPU.API.Attribs; namespace Cosmos.Core.Processing @@ -33,10 +32,10 @@ public static void EntryPoint() while (true) { } // remove from thread pool later } - public static uint TickFrequency = 1; - public static void SwitchTask() { + CPU.DisableInterrupts(); + if (ProcessContext.m_CurrentContext != null) { ProcessContext.Context ctx = ProcessContext.m_ContextList; @@ -56,9 +55,7 @@ public static void SwitchTask() { if (ctx.state == ProcessContext.Thread_State.WAITING_SLEEP) { - ctx.arg -= 1000 / (int)TickFrequency; - Cosmos.Core.Global.debugger.Send("ctx.arg=" + ctx.arg); - Cosmos.Core.Global.debugger.Send("TickFrequency=" + TickFrequency); + ctx.arg -= 1; //Since Local APIC Frequency = 1000Hz remove 1ms per interrupt if (ctx.arg <= 0) { ctx.state = ProcessContext.Thread_State.ALIVE; @@ -68,7 +65,7 @@ public static void SwitchTask() ctx = ctx.next; } ProcessContext.m_CurrentContext.esp = INTs.mStackContext; - tryagain:; + tryagain: if (ProcessContext.m_CurrentContext.next != null) { ProcessContext.m_CurrentContext = ProcessContext.m_CurrentContext.next; @@ -85,7 +82,9 @@ public static void SwitchTask() INTs.mStackContext = ProcessContext.m_CurrentContext.esp; } + CPU.EnableInterrupts(); + LocalAPIC.EndOfInterrupt(); } } -} +} \ No newline at end of file diff --git a/source/Cosmos.HAL2/ApicTimer.cs b/source/Cosmos.HAL2/ApicTimer.cs index f6b7fa9a1e..5eb66a4e58 100644 --- a/source/Cosmos.HAL2/ApicTimer.cs +++ b/source/Cosmos.HAL2/ApicTimer.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Cosmos.Core; -using Cosmos.Core.MemoryGroup; +using Cosmos.Core; namespace Cosmos.HAL { @@ -14,39 +8,38 @@ namespace Cosmos.HAL public static class ApicTimer { /// - /// Tick Counter. + /// APIC base frequency /// - public static uint Tick = 0; + public static ulong BaseFrequency; /// - /// Tick Frequency. + /// APIC frequency /// - public static uint TickFrequency = 0; + public static ulong Frequency; + + private static ulong Ticks => LocalAPIC.In(LocalAPIC.LAPIC_TCCR); /// /// Initialize local APIC timer. /// public static void Initialize() { - // setup timer, Intel IA manual 10-16 Vol. 3A - LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0xB); // divide timer counts by 1 - - Calibrate(); - - if (TickFrequency == 0) - { - throw new Exception("APIC timer is not calibrated"); - } - - LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x20000 | 0x28); // periodic, bind to corresponding IRQ (this RTC IRQ but unused so...) - LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0xB); + Frequency = 1000; + BaseFrequency = EstimateBusSpeed(); + Global.debugger.Send("APIC timer frequency: " + Frequency + "Hz, Divisor: " + 16 + ", IRQ: 8"); + Global.debugger.Send("Base frequency is " + BaseFrequency / 1048576 + "mhz"); Global.debugger.Send("Local APIC Timer Initialized"); } + /// + /// Start local APIC timer. + /// public static void Start() { - SetTimerCount(TickFrequency); + LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x00020000 | 0x28); + LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0x3); //Divide 16 + LocalAPIC.Out(LocalAPIC.LAPIC_TICR, (uint)((BaseFrequency / 16) / Frequency)); } /// @@ -54,35 +47,25 @@ public static void Start() /// public static void Stop() { - LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x10000); + LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x20000 | 0x10000); } - public static void SetTimerCount(uint count) - { - LocalAPIC.Out(LocalAPIC.LAPIC_TICR, count); - } - - public static void Calibrate() + /// + /// Calculate BUS Speed using PIT + /// + private static uint EstimateBusSpeed() { - Global.debugger.Send("Calibrating APIC timer..."); - - SetTimerCount(0xFFFFFFFF); // Set APIC init counter to -1 - - Global.debugger.Send("PIT START"); - - Global.PIT.Wait(10000); // PIT sleep for 1000ms - - Global.debugger.Send("PIT END"); - - Stop(); - - ulong ticks = 0xFFFFFFFF - LocalAPIC.In(LocalAPIC.LAPIC_TCCR); // Now we know how often the APIC timer has ticked in 10ms - - Global.debugger.Send("APIC timer ticks per 1s: " + ticks); + LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x10000); + LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0x3); + LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0); - TickFrequency = (uint)(ticks); + uint T0 = 0xFFFFFFFF; // -1 + LocalAPIC.Out(0x380, T0); + Global.PIT.Wait(100); //100ms + LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x10000); - Global.debugger.Send("APIC timer tick frequency: " + TickFrequency); + ulong Freq = (T0 - Ticks) * 16; + return (uint)(Freq * 1000000 / 100000); } } } \ No newline at end of file diff --git a/source/Cosmos.HAL2/Global.cs b/source/Cosmos.HAL2/Global.cs index 2768b13d09..5aa42c7739 100644 --- a/source/Cosmos.HAL2/Global.cs +++ b/source/Cosmos.HAL2/Global.cs @@ -52,29 +52,25 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In debugger.Send("ACPI Init"); ACPI.Start(); - Console.WriteLine("Starting PIT"); - debugger.Send("PIT init"); - PIT = new(); - - Global.debugger.Send("PIT START"); - - Global.PIT.Wait(10000); // PIT sleep for 10000ms - - Global.debugger.Send("PIT END"); + Console.WriteLine("Finding PCI Devices"); + debugger.Send("PCI Devices"); + PCI.Setup(); Console.WriteLine("Starting APIC"); debugger.Send("Local APIC Init"); LocalAPIC.Initialize(); - Global.debugger.Send("PIT START"); - - Global.PIT.Wait(10000); // PIT sleep for 10000ms + Console.WriteLine("Starting PIT"); + debugger.Send("PIT init"); + PIT = new(); - Global.debugger.Send("PIT END"); + Console.WriteLine("Starting Processor Scheduler"); + debugger.Send("Processor Scheduler"); + Core.Processing.ProcessorScheduler.Initialize(); - Console.WriteLine("Finding PCI Devices"); - debugger.Send("PCI Devices"); - PCI.Setup(); + debugger.Send("Local APIC Timer Init"); + ApicTimer.Initialize(); + ApicTimer.Start(); Console.WriteLine("Starting PS/2"); debugger.Send("PS/2 init"); @@ -103,16 +99,6 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In AHCI.InitDriver(); //EHCI.InitDriver(); - Console.WriteLine("Starting Processor Scheduler"); - debugger.Send("Processor Scheduler"); - Core.Processing.ProcessorScheduler.Initialize(); - - debugger.Send("Local APIC Timer Init"); - ApicTimer.Initialize(); - ApicTimer.Start(); - - Core.Processing.ProcessorScheduler.TickFrequency = ApicTimer.TickFrequency; - if (InitNetwork) { debugger.Send("Network Devices Init"); From 72c14361894ff7596e0495875d1e622b13be72fa Mon Sep 17 00:00:00 2001 From: valentinbreiz Date: Tue, 23 Jan 2024 12:10:47 +0100 Subject: [PATCH 15/15] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Set=20100Hz=20instea?= =?UTF-8?q?d=20of=201000Hz?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/Cosmos.Core/Processing/ProcessorScheduler.cs | 10 +++++----- source/Cosmos.HAL2/ApicTimer.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/Cosmos.Core/Processing/ProcessorScheduler.cs b/source/Cosmos.Core/Processing/ProcessorScheduler.cs index d265d5e77e..733971de69 100644 --- a/source/Cosmos.Core/Processing/ProcessorScheduler.cs +++ b/source/Cosmos.Core/Processing/ProcessorScheduler.cs @@ -34,10 +34,10 @@ public static void EntryPoint() public static void SwitchTask() { - CPU.DisableInterrupts(); - if (ProcessContext.m_CurrentContext != null) { + CPU.DisableInterrupts(); + ProcessContext.Context ctx = ProcessContext.m_ContextList; ProcessContext.Context last = ctx; while (ctx != null) @@ -55,7 +55,7 @@ public static void SwitchTask() { if (ctx.state == ProcessContext.Thread_State.WAITING_SLEEP) { - ctx.arg -= 1; //Since Local APIC Frequency = 1000Hz remove 1ms per interrupt + ctx.arg -= 10; //Since Local APIC Frequency = 100Hz remove 10ms per interrupt if (ctx.arg <= 0) { ctx.state = ProcessContext.Thread_State.ALIVE; @@ -80,9 +80,9 @@ public static void SwitchTask() } ProcessContext.m_CurrentContext.age = ProcessContext.m_CurrentContext.priority; INTs.mStackContext = ProcessContext.m_CurrentContext.esp; - } - CPU.EnableInterrupts(); + CPU.EnableInterrupts(); + } LocalAPIC.EndOfInterrupt(); } diff --git a/source/Cosmos.HAL2/ApicTimer.cs b/source/Cosmos.HAL2/ApicTimer.cs index 5eb66a4e58..e2bdcba413 100644 --- a/source/Cosmos.HAL2/ApicTimer.cs +++ b/source/Cosmos.HAL2/ApicTimer.cs @@ -24,7 +24,7 @@ public static class ApicTimer /// public static void Initialize() { - Frequency = 1000; + Frequency = 100; BaseFrequency = EstimateBusSpeed(); Global.debugger.Send("APIC timer frequency: " + Frequency + "Hz, Divisor: " + 16 + ", IRQ: 8");