diff --git a/Test.sln b/Test.sln
index be21518af8..b47c833e4d 100644
--- a/Test.sln
+++ b/Test.sln
@@ -140,6 +140,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
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudioTests", "Tests\Kernels\AudioTests\AudioTests.csproj", "{8455DCAE-275E-47B3-B89B-2D9F3AB9977C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cosmos.Plugs", "source\Cosmos.Plugs\Cosmos.Plugs.csproj", "{0C65F6CA-C897-40A3-A36E-0CCCAD01D567}"
@@ -791,6 +793,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
{8455DCAE-275E-47B3-B89B-2D9F3AB9977C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8455DCAE-275E-47B3-B89B-2D9F3AB9977C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8455DCAE-275E-47B3-B89B-2D9F3AB9977C}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -881,6 +895,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}
{8455DCAE-275E-47B3-B89B-2D9F3AB9977C} = {29EEC029-6A2B-478A-B6E5-D63A91388ABA}
{0C65F6CA-C897-40A3-A36E-0CCCAD01D567} = {9A923E6F-FF63-4F02-A4EA-C2D44F9323FD}
EndGlobalSection
diff --git a/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj b/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj
index 6246b420ed..1b9f177d91 100644
--- a/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj
+++ b/Tests/Cosmos.TestRunner.Full/Cosmos.TestRunner.Full.csproj
@@ -34,6 +34,7 @@
+
diff --git a/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs b/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs
index 6e2f0e1c35..b91a29397c 100644
--- a/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs
+++ b/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs
@@ -38,6 +38,7 @@ public static IEnumerable GetStableKernelTypes()
//yield return typeof(ConsoleTest.Kernel);
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..cb86220ebb
--- /dev/null
+++ b/Tests/Kernels/ThreadingTest/Kernel.cs
@@ -0,0 +1,80 @@
+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()
+ {
+ 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();
+
+ variableThree = 3;
+
+ //Since Run is not a thread call PIT wait
+ System.Threading.Thread.Sleep(4000);
+
+ //Cosmos.HAL.Global.PIT.Wait(3000);
+
+ Global.Debugger.Send("[MainThread] Waited 4 sec.");
+
+ 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");
+
+ TestController.Completed();
+ }
+ catch (Exception e)
+ {
+ mDebugger.Send("Exception occurred: " + e.Message);
+ mDebugger.Send(e.Message);
+ TestController.Failed();
+ }
+ }
+
+ public void ThreadOne()
+ {
+ //Make thread WAITING
+ Thread.Sleep(1000);
+
+ Global.Debugger.Send("[FirstThread] Hello");
+
+ variable = 1;
+
+ Global.Debugger.Send("[FirstThread] Bye");
+ }
+
+ public void ThreadTwo()
+ {
+ //Make thread WAITING
+ Thread.Sleep(2000);
+
+ Global.Debugger.Send("[SecondThread] Hello");
+
+ variableTwo = 2;
+
+ Global.Debugger.Send("[SecondThread] Bye");
+ }
+ }
+}
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
+
+
+
+
+
+
+
+
+
+
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/GCImplementation.cs b/source/Cosmos.Core/GCImplementation.cs
index 66b4ef5c05..bedf95cc71 100644
--- a/source/Cosmos.Core/GCImplementation.cs
+++ b/source/Cosmos.Core/GCImplementation.cs
@@ -1,202 +1,202 @@
-#if DEBUG
-//#define GC_DEBUG
-#endif
-//#define COSMOSDEBUG
-using System;
-using Cosmos.Core.Memory;
-
-namespace Cosmos.Core
-{
- ///
- /// GCImplementation class. Garbage collector. Mostly not implemented.
- ///
- /// Most of the class is yet to be implemented.
- [System.Diagnostics.DebuggerStepThrough]
- public unsafe static class GCImplementation
- {
- private unsafe static byte* memPtr = null;
- private static ulong memLength = 0;
- private static bool StartedMemoryManager = false;
- ///
- ///
- /// Acquire lock. Not implemented.
- ///
- /// Thrown always.
- private static void AcquireLock()
- {
- throw new NotImplementedException();
- }
-
- ///
- /// Release lock. Not implemented.
- ///
- /// Thrown always.
- private static void ReleaseLock()
- {
- throw new NotImplementedException();
- }
- ///
- /// Alloc new object.
- ///
- public unsafe static uint AllocNewObject(uint aSize)
- {
- return (uint)Heap.Alloc(aSize);
- }
- ///
- /// Free Object from Memory
- ///
- /// Takes a memory allocated object
- public unsafe static void Free(object aObj)
- {
- Heap.Free(GetPointer(aObj));
- }
-
- ///
- /// Get amount of available Ram
- ///
- /// Returns amount of available memory to the System in MB
- public static ulong GetAvailableRAM()
- {
- return memLength / 1024 / 1024;
- }
- ///
- /// Get a rough estimate of used Memory by the System
- ///
- /// Returns the used PageSize by the MemoryManager in Bytes.
- public static uint GetUsedRAM()
- {
- return (RAT.TotalPageCount - RAT.GetPageCount((byte)RAT.PageType.Empty)) * RAT.PageSize;
- }
- ///
- /// Initialise the Memory Manager, this should not be called anymore since it is done very early during the boot process.
- ///
- public static unsafe void Init()
- {
- if (StartedMemoryManager)
- {
- return;
- }
- StartedMemoryManager = true;
-
- var largestBlock = CPU.GetLargestMemoryBlock();
-
- if (largestBlock != null)
- {
- memPtr = (byte*)largestBlock->Address;
- memLength = largestBlock->Length;
- if ((uint)memPtr < CPU.GetEndOfKernel() + 1024)
- {
- memPtr = (byte*)CPU.GetEndOfKernel() + 1024;
- memPtr += RAT.PageSize - ((uint)memPtr % RAT.PageSize);
- memLength = largestBlock->Length - ((uint)memPtr - (uint)largestBlock->Address);
- memLength -= memLength % RAT.PageSize;
- }
- }
- else
- {
- memPtr = (byte*)CPU.GetEndOfKernel() + 1024;
- memPtr += RAT.PageSize - (uint)memPtr % RAT.PageSize;
- memLength = 128 * 1024 * 1024;
- }
- RAT.Init(memPtr, (uint)memLength);
- }
- ///
- /// Get the Pointer of any object needed for Free()
- ///
- /// Takes any kind of object
- /// Returns a pointer to the area in memory where the object is located
- public static unsafe uint* GetPointer(object aObj) => throw null; // this is plugged
-
- ///
- /// Get the pointer of any object as a uint
- ///
- ///
- ///
- public static unsafe uint GetSafePointer(object aObj)
- {
- return (uint)GetPointer(aObj);
- }
-
- ///
- /// Get cosmos internal type from object
- ///
- ///
- ///
- public static unsafe uint GetType(object aObj)
- {
- return *GetPointer(aObj);
- }
-
- ///
- /// Increments the root count of the object at the pointer by 1
- ///
- ///
- public static unsafe void IncRootCount(ushort* aPtr)
- {
- if (RAT.GetPageType(aPtr) != 0)
- {
- var rootCount = *(aPtr - 1) >> 1; // lowest bit is used to set if hit
- *(aPtr - 1) = (ushort)((rootCount + 1) << 1); // loest bit can be zero since we shouldnt be doing this while gc is collecting
- }
- }
-
- ///
- /// Decrements the root count of the object at the pointer by 1
- ///
- ///
- public static unsafe void DecRootCount(ushort* aPtr)
- {
- if (RAT.GetPageType(aPtr) != 0)
- {
- var rootCount = *(aPtr - 1) >> 1; // lowest bit is used to set if hit
- *(aPtr - 1) = (ushort)((rootCount - 1) << 1); // lowest bit can be zero since we shouldnt be doing this while gc is collecting
- }
- }
-
- ///
- /// Increments the root count of all object stored in this struct by 1
- ///
- ///
- /// Type of the struct
- public static unsafe void IncRootCountsInStruct(ushort* aPtr, uint aType)
- {
- uint count = VTablesImpl.GetGCFieldCount(aType);
- uint[] offset = VTablesImpl.GetGCFieldOffsets(aType);
- uint[] types = VTablesImpl.GetGCFieldTypes(aType);
- for (int i = 0; i < count; i++)
- {
- if (VTablesImpl.IsStruct(types[i]))
- {
- IncRootCountsInStruct(aPtr + offset[i] / 2, types[i]);
- }
- else
- {
- IncRootCount(*(ushort**)(aPtr + offset[i] / 2));
- }
- }
- }
-
- ///
- /// Decrements the root count of all object stored in this struct by 1
- ///
- ///
- /// Type of the struct
- public static unsafe void DecRootCountsInStruct(ushort* aPtr, uint aType)
- {
- uint count = VTablesImpl.GetGCFieldCount(aType);
- uint[] offset = VTablesImpl.GetGCFieldOffsets(aType);
- uint[] types = VTablesImpl.GetGCFieldTypes(aType);
- for (int i = 0; i < count; i++)
- {
- if (VTablesImpl.IsStruct(types[i]))
- {
- DecRootCountsInStruct(aPtr + offset[i] / 2, types[i]);
- }
- else
- {
- DecRootCount(*(ushort**)(aPtr + offset[i] / 2));
- }
- }
- }
- }
-}
+#if DEBUG
+//#define GC_DEBUG
+#endif
+//#define COSMOSDEBUG
+using System;
+using Cosmos.Core.Memory;
+
+namespace Cosmos.Core
+{
+ ///
+ /// GCImplementation class. Garbage collector. Mostly not implemented.
+ ///
+ /// Most of the class is yet to be implemented.
+ [System.Diagnostics.DebuggerStepThrough]
+ public unsafe static class GCImplementation
+ {
+ private unsafe static byte* memPtr = null;
+ private static ulong memLength = 0;
+ private static bool StartedMemoryManager = false;
+ ///
+ ///
+ /// Acquire lock. Not implemented.
+ ///
+ /// Thrown always.
+ private static void AcquireLock()
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Release lock. Not implemented.
+ ///
+ /// Thrown always.
+ private static void ReleaseLock()
+ {
+ throw new NotImplementedException();
+ }
+ ///
+ /// Alloc new object.
+ ///
+ public unsafe static uint AllocNewObject(uint aSize)
+ {
+ return (uint)Heap.Alloc(aSize);
+ }
+ ///
+ /// Free Object from Memory
+ ///
+ /// Takes a memory allocated object
+ public unsafe static void Free(object aObj)
+ {
+ Heap.Free(GetPointer(aObj));
+ }
+
+ ///
+ /// Get amount of available Ram
+ ///
+ /// Returns amount of available memory to the System in MB
+ public static ulong GetAvailableRAM()
+ {
+ return memLength / 1024 / 1024;
+ }
+ ///
+ /// Get a rough estimate of used Memory by the System
+ ///
+ /// Returns the used PageSize by the MemoryManager in Bytes.
+ public static uint GetUsedRAM()
+ {
+ return (RAT.TotalPageCount - RAT.GetPageCount((byte)RAT.PageType.Empty)) * RAT.PageSize;
+ }
+ ///
+ /// Initialise the Memory Manager, this should not be called anymore since it is done very early during the boot process.
+ ///
+ public static unsafe void Init()
+ {
+ if (StartedMemoryManager)
+ {
+ return;
+ }
+ StartedMemoryManager = true;
+
+ var largestBlock = CPU.GetLargestMemoryBlock();
+
+ if (largestBlock != null)
+ {
+ memPtr = (byte*)largestBlock->Address;
+ memLength = largestBlock->Length;
+ if ((uint)memPtr < CPU.GetEndOfKernel() + 1024)
+ {
+ memPtr = (byte*)CPU.GetEndOfKernel() + 1024;
+ memPtr += RAT.PageSize - ((uint)memPtr % RAT.PageSize);
+ memLength = largestBlock->Length - ((uint)memPtr - (uint)largestBlock->Address);
+ memLength -= memLength % RAT.PageSize;
+ }
+ }
+ else
+ {
+ memPtr = (byte*)CPU.GetEndOfKernel() + 1024;
+ memPtr += RAT.PageSize - (uint)memPtr % RAT.PageSize;
+ memLength = 128 * 1024 * 1024;
+ }
+ RAT.Init(memPtr, (uint)memLength);
+ }
+ ///
+ /// Get the Pointer of any object needed for Free()
+ ///
+ /// Takes any kind of object
+ /// Returns a pointer to the area in memory where the object is located
+ public static unsafe uint* GetPointer(object aObj) => throw null; // this is plugged
+
+ ///
+ /// Get the pointer of any object as a uint
+ ///
+ ///
+ ///
+ public static unsafe uint GetSafePointer(object aObj)
+ {
+ return (uint)GetPointer(aObj);
+ }
+
+ ///
+ /// Get cosmos internal type from object
+ ///
+ ///
+ ///
+ public static unsafe uint GetType(object aObj)
+ {
+ return *GetPointer(aObj);
+ }
+
+ ///
+ /// Increments the root count of the object at the pointer by 1
+ ///
+ ///
+ public static unsafe void IncRootCount(ushort* aPtr)
+ {
+ if (RAT.GetPageType(aPtr) != 0)
+ {
+ var rootCount = *(aPtr - 1) >> 1; // lowest bit is used to set if hit
+ *(aPtr - 1) = (ushort)((rootCount + 1) << 1); // loest bit can be zero since we shouldnt be doing this while gc is collecting
+ }
+ }
+
+ ///
+ /// Decrements the root count of the object at the pointer by 1
+ ///
+ ///
+ public static unsafe void DecRootCount(ushort* aPtr)
+ {
+ if (RAT.GetPageType(aPtr) != 0)
+ {
+ var rootCount = *(aPtr - 1) >> 1; // lowest bit is used to set if hit
+ *(aPtr - 1) = (ushort)((rootCount - 1) << 1); // lowest bit can be zero since we shouldnt be doing this while gc is collecting
+ }
+ }
+
+ ///
+ /// Increments the root count of all object stored in this struct by 1
+ ///
+ ///
+ /// Type of the struct
+ public static unsafe void IncRootCountsInStruct(ushort* aPtr, uint aType)
+ {
+ uint count = VTablesImpl.GetGCFieldCount(aType);
+ uint[] offset = VTablesImpl.GetGCFieldOffsets(aType);
+ uint[] types = VTablesImpl.GetGCFieldTypes(aType);
+ for (int i = 0; i < count; i++)
+ {
+ if (VTablesImpl.IsStruct(types[i]))
+ {
+ IncRootCountsInStruct(aPtr + offset[i] / 2, types[i]);
+ }
+ else
+ {
+ IncRootCount(*(ushort**)(aPtr + offset[i] / 2));
+ }
+ }
+ }
+
+ ///
+ /// Decrements the root count of all object stored in this struct by 1
+ ///
+ ///
+ /// Type of the struct
+ public static unsafe void DecRootCountsInStruct(ushort* aPtr, uint aType)
+ {
+ uint count = VTablesImpl.GetGCFieldCount(aType);
+ uint[] offset = VTablesImpl.GetGCFieldOffsets(aType);
+ uint[] types = VTablesImpl.GetGCFieldTypes(aType);
+ for (int i = 0; i < count; i++)
+ {
+ if (VTablesImpl.IsStruct(types[i]))
+ {
+ DecRootCountsInStruct(aPtr + offset[i] / 2, types[i]);
+ }
+ else
+ {
+ DecRootCount(*(ushort**)(aPtr + offset[i] / 2));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/Cosmos.Core/INTs.cs b/source/Cosmos.Core/INTs.cs
index 662e970ff3..20b47bd007 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 = 0;
+ public static uint mStackContext;
+
///
/// IRQ handlers.
///
@@ -852,6 +854,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/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/Memory/Heap.cs b/source/Cosmos.Core/Memory/Heap.cs
index 5d86e4412b..862c10c7c3 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;
@@ -20,6 +21,8 @@ public enum ObjectGCStatus : ushort
public static unsafe class Heap
{
private static uint* StackStart;
+ private static Mutex mMemeoryGate = new Mutex();
+
///
/// Init heap.
///
@@ -44,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
@@ -72,6 +80,12 @@ public static unsafe void Init()
// Free the old data and return
Free(aPtr);
+
+ if (mMemeoryGate != null)
+ {
+ mMemeoryGate.Unlock();
+ }
+
return ToReturn;
}
@@ -82,24 +96,47 @@ 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;
}
}
@@ -128,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);
@@ -146,6 +188,11 @@ public static void Free(void* aPtr)
default:
throw new Exception("Heap item not found in RAT.");
}
+
+ if (mMemeoryGate != null)
+ {
+ mMemeoryGate.Unlock();
+ }
}
///
@@ -154,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();
@@ -291,6 +343,11 @@ public static int Collect()
//Enable interrupts back
CPU.EnableInterrupts();
+ if (mMemeoryGate != null)
+ {
+ mMemeoryGate.Unlock();
+ }
+
return freed;
}
diff --git a/source/Cosmos.Core/Memory/HeapLarge.cs b/source/Cosmos.Core/Memory/HeapLarge.cs
index 7436f0e86d..eae50f0514 100644
--- a/source/Cosmos.Core/Memory/HeapLarge.cs
+++ b/source/Cosmos.Core/Memory/HeapLarge.cs
@@ -1,59 +1,59 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using Cosmos.Debug.Kernel;
-using Native = System.UInt32;
-
-namespace Cosmos.Core.Memory
-{
- ///
- /// HeapLarge class. Used to alloc and free large memory blocks on the heap.
- ///
- public static unsafe class HeapLarge
- {
- ///
- /// Prefix block. Used to store meta information.
- ///
- public const uint PrefixBytes = 4 * sizeof(uint);
-
- ///
- /// Init HeapLarge instance.
- ///
- /// Empty function
- public static void Init()
- {
- }
-
- ///
- /// Alloc memory block, of a given size.
- ///
- /// A size of block to alloc, in bytes.
- /// Byte pointer to the start of the block.
- public static byte* Alloc(uint aSize, RAT.PageType aType = RAT.PageType.HeapLarge)
- {
- uint xPages = (aSize + PrefixBytes) / RAT.PageSize + 1;
- var xPtr = (uint*)RAT.AllocPages(aType, xPages);
- if (xPtr == null)
- {
- Debugger.SendKernelPanic(0x67); // out of pages
- while (true) { }
- }
- xPtr[0] = xPages * RAT.PageSize - PrefixBytes; // Allocated data size
- xPtr[1] = aSize; // Actual data size
- xPtr[3] = 0; // padding for now?,
- xPtr[2] = 0; // padding + GC object status
- return (byte*)xPtr + PrefixBytes;
- }
-
- ///
- /// Free block.
- ///
- /// A pointer to the block.
- /// Thrown if page type is not found.
- public static void Free(void* aPtr)
- {
- var xPageIdx = RAT.GetFirstRATIndex(aPtr);
- RAT.Free(xPageIdx);
- }
- }
-}
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Cosmos.Debug.Kernel;
+using Native = System.UInt32;
+
+namespace Cosmos.Core.Memory
+{
+ ///
+ /// HeapLarge class. Used to alloc and free large memory blocks on the heap.
+ ///
+ public static unsafe class HeapLarge
+ {
+ ///
+ /// Prefix block. Used to store meta information.
+ ///
+ public const uint PrefixBytes = 4 * sizeof(uint);
+
+ ///
+ /// Init HeapLarge instance.
+ ///
+ /// Empty function
+ public static void Init()
+ {
+ }
+
+ ///
+ /// Alloc memory block, of a given size.
+ ///
+ /// A size of block to alloc, in bytes.
+ /// Byte pointer to the start of the block.
+ public static byte* Alloc(uint aSize, RAT.PageType aType = RAT.PageType.HeapLarge)
+ {
+ uint xPages = (aSize + PrefixBytes) / RAT.PageSize + 1;
+ var xPtr = (uint*)RAT.AllocPages(aType, xPages);
+ if (xPtr == null)
+ {
+ Debugger.SendKernelPanic(0x67); // out of pages
+ while (true) { }
+ }
+ xPtr[0] = xPages * RAT.PageSize - PrefixBytes; // Allocated data size
+ xPtr[1] = aSize; // Actual data size
+ xPtr[3] = 0; // padding for now?,
+ xPtr[2] = 0; // padding + GC object status
+ return (byte*)xPtr + PrefixBytes;
+ }
+
+ ///
+ /// Free block.
+ ///
+ /// A pointer to the block.
+ /// Thrown if page type is not found.
+ public static void Free(void* aPtr)
+ {
+ var xPageIdx = RAT.GetFirstRATIndex(aPtr);
+ RAT.Free(xPageIdx);
+ }
+ }
+}
diff --git a/source/Cosmos.Core/Memory/HeapSmall.cs b/source/Cosmos.Core/Memory/HeapSmall.cs
index 26b5f56ba4..9d0c18b361 100644
--- a/source/Cosmos.Core/Memory/HeapSmall.cs
+++ b/source/Cosmos.Core/Memory/HeapSmall.cs
@@ -1,626 +1,626 @@
-using System;
-using Cosmos.Debug.Kernel;
-using IL2CPU.API;
-using IL2CPU.API.Attribs;
-
-namespace Cosmos.Core.Memory
-{
- ///
- /// Page containing Size Map Table
- ///
- public unsafe struct SMTPage
- {
- ///
- /// Pointer to the next page
- ///
- public SMTPage* Next;
- ///
- /// Pointer to the root of the smallest block stored on this page
- ///
- public RootSMTBlock* First;
- }
-
- public unsafe struct RootSMTBlock
- {
- ///
- /// Elements stored in the page have a size less or equal to this
- /// Does not include the prefix bytes
- ///
- public uint Size;
- ///
- /// Pointer to the first block for this size
- ///
- public SMTBlock* First;
- ///
- /// Next larger size root block
- ///
- public RootSMTBlock* LargerSize;
- }
- // Changing the ordering will break SMTBlock* NextFreeBlock(SMTPage* aPage)
- public unsafe struct SMTBlock
- {
- ///
- /// Pointer to the actual page, where the elements are stored
- ///
- public byte* PagePtr;
- ///
- /// How much space is left on the page, makes it easier to skip full pages
- ///
- public uint SpacesLeft;
- ///
- /// Pointer to the next block for this size
- ///
- public SMTBlock* NextBlock;
- }
-
- //TODO Remove empty pages as necessary
- ///
- /// HeapSmall class. Used to alloc and free small memory blocks on the heap.
- ///
- unsafe static public class HeapSmall
- {
- ///
- /// Number of prefix bytes for each item.
- /// We technically only need 2 but to keep it aligned we have two padding
- ///
- public const uint PrefixItemBytes = 2 * sizeof(ushort);
- ///
- /// Max item size in the heap.
- ///
- public static uint mMaxItemSize;
-
- ///
- /// Size map table
- ///
- public static SMTPage* SMT;
-
- #region SMT
-
- ///
- /// Find the next free block in a page
- ///
- /// Pointer to the start of block in the SMT. null if all SMT pages are full
- private static SMTBlock* NextFreeBlock(SMTPage* aPage)
- {
- SMTBlock* ptr = (SMTBlock*)aPage->First; // since both RootSMTBlock and SMTBlock have the same size (20) it doesnt matter if cast is wrong
- while (ptr->PagePtr != null) // this would check Size if its actually a RootSMTBlock, which is always non-zero
- {
- ptr += 1;
- if (ptr >= (byte*)aPage + RAT.PageSize - 8)
- {
- return null;
- }
- }
- return ptr;
-
- }
-
- ///
- /// Gets the root block in the SMT for objects of this size
- ///
- /// Size of allocated block
- /// Page to seach in
- /// Pointer of block in SMT.
- private static RootSMTBlock* GetFirstBlock(SMTPage* aPage, uint aSize)
- {
- RootSMTBlock* ptr = aPage->First;
- uint curSize = ptr->Size;
- while (curSize < aSize)
- {
- ptr = ptr->LargerSize;
- if (ptr == null)
- {
- return null;
- }
- curSize = ptr->Size;
- }
- return ptr;
- }
-
- ///
- /// Gets the last block on a certain page for objects of this size
- ///
- /// Page to search
- ///
- ///
- private static SMTBlock* GetLastBlock(SMTPage* page, uint aSize)
- {
- SMTBlock* ptr = GetFirstBlock(page, aSize)->First;
- if (ptr == null)
- {
- return null;
- }
-
- while (ptr->NextBlock != null)
- {
- ptr = ptr->NextBlock;
- }
- return ptr;
- }
-
- ///
- /// Get the first block for this size on any SMT page, which has space left to allocate to
- ///
- ///
- /// Null if no more space on any block of this size
- private static SMTBlock* GetFirstWithSpace(uint aSize)
- {
- SMTPage* page = SMT;
- SMTBlock* block = null;
- do
- {
- block = GetFirstWithSpace(page, aSize);
- page = page->Next;
- } while (block == null && page != null);
- return block;
- }
-
- ///
- /// Get the first block for this size on this SMT page, which has space left to allocate to
- ///
- ///
- /// Null if no more space on this page
- private static SMTBlock* GetFirstWithSpace(SMTPage* aPage, uint aSize)
- {
- return GetFirstWithSpace(GetFirstBlock(aPage, aSize), aSize);
- }
-
- ///
- /// Get the first block for this size in this SMT block chain, which has space left to allocate to
- ///
- /// The root node to start the search at
- ///
- ///
- private static SMTBlock* GetFirstWithSpace(RootSMTBlock* aRoot, uint aSize)
- {
- SMTBlock* ptr = aRoot->First;
- if (ptr == null) // Can this ever happen?
- {
- return null;
- }
- while (ptr->SpacesLeft == 0)
- {
- ptr = ptr->NextBlock;
- if (ptr == null)
- {
- return null;
- }
- }
- return ptr;
- }
-
- ///
- /// Add a new root block for a certain size to a certain SMT page
- ///
- /// Size must be divisible by 2 otherwise Alloc breaks
- private static void AddRootSMTBlock(SMTPage* aPage, uint aSize)
- {
- RootSMTBlock* ptr = aPage->First;
- while (ptr->LargerSize != null)
- {
- ptr = ptr->LargerSize;
- }
-
- if (aSize < ptr->Size)
- {
- // we cant later add a block with a size smaller than an earlier block. That would break the algorithm
- Debugger.DoSendNumber(aSize);
- Debugger.DoSendNumber(ptr->Size);
- Debugger.SendKernelPanic(0x83);
- while (true) { }
- }
-
- if (ptr->Size == 0) // This is the first block to be allocated on the page
- {
- ptr->Size = aSize;
- }
- else
- {
- RootSMTBlock* block = (RootSMTBlock*)NextFreeBlock(aPage); // we should actually check that this is not null
- //but we should also only call this code right at the beginning so it should be fine
- block->Size = aSize;
- ptr->LargerSize = block;
- }
- CreatePage(aPage, aSize);
- }
-
- ///
- /// Get the Last Page of the SMT
- ///
- ///
- private static SMTPage* GetSMTLastPage()
- {
- var page = SMT;
- while (page->Next != null)
- {
- page = page->Next;
- }
- return page;
- }
-
- ///
- /// Return the size a certain element will be allocated as
- ///
- ///
- public static uint GetRoundedSize(uint aSize)
- {
- return GetFirstBlock(SMT, aSize)->Size;
- }
-
- #endregion
-
- ///
- /// Init small heap.
- ///
- /// Thrown on fatal error, contact support.
- static public void Init()
- {
- //TODO Adjust for new page and header sizes
- // 4 slots, ~1k ea
- uint xMaxItemSize = RAT.PageSize / 4 - PrefixItemBytes;
- // Word align it
- mMaxItemSize = xMaxItemSize / sizeof(uint) * sizeof(uint);
-
- SMT = InitSMTPage();
- }
-
- ///
- /// Allocates and initialise a page for the SMT table
- ///
- ///
- private static SMTPage* InitSMTPage()
- {
- SMTPage* page = (SMTPage*)RAT.AllocPages(RAT.PageType.SMT, 1);
- page->First = (RootSMTBlock*)page + 1;
-
- // TODO Change these sizes after further study and also when page size changes.
- // SMT can be grown as needed. Also can adjust and create new ones dynamicaly as it runs.
- // The current algorithm only works if we create the inital pages in increasing order
- AddRootSMTBlock(page, 16);
- AddRootSMTBlock(page, 24);
- AddRootSMTBlock(page, 48);
- AddRootSMTBlock(page, 64);
- AddRootSMTBlock(page, 128);
- AddRootSMTBlock(page, 256);
- AddRootSMTBlock(page, 512);
- AddRootSMTBlock(page, mMaxItemSize);
- return page;
- }
-
- ///
- /// Create a page with the size of an item and try add it to the SMT at a certain page
- /// If the SMT page is full, it will be added to the first SMT page with space or a new SMT page is allocated
- ///
- /// Object size in bytes
- /// Thrown if:
- ///
- /// - aItemSize is 0.
- /// - aItemSize is not word aligned.
- /// - SMT is not initialized.
- /// - The item size is bigger then a small heap size.
- ///
- ///
- static void CreatePage(SMTPage* aPage, uint aItemSize)
- {
- byte* xPtr = (byte*)RAT.AllocPages(RAT.PageType.HeapSmall, 1);
- if (xPtr == null)
- {
- return; // we failed to create the page, Alloc should still handle this case
- }
-
- uint xSlotSize = aItemSize + PrefixItemBytes;
- uint xItemCount = RAT.PageSize / xSlotSize;
- for (uint i = 0; i < xItemCount; i++)
- {
- byte* xSlotPtr = xPtr + i * xSlotSize;
- ushort* xMetaDataPtr = (ushort*)xSlotPtr;
- xMetaDataPtr[0] = 0; // Actual data size. 0 is empty.
- xMetaDataPtr[1] = 0; // Ref count
- }
-
- //now add it to the smt
- SMTBlock* parent = GetLastBlock(aPage, aItemSize);
- SMTBlock* smtBlock = NextFreeBlock(aPage); //get the next free block in the smt
-
- if (smtBlock == null) // we could not allocate a new block since the SMT table is all full on this page
- {
- // we now have two options:
- // 1. there exists a later page in the chain, which has space
- // 2. all SMT Pages are full and we need to allocate a new one
-
- // first, check if we find a later page with space
- SMTPage* currentSMTPage = aPage->Next;
- while (currentSMTPage != null)
- {
- smtBlock = NextFreeBlock(currentSMTPage);
- if(smtBlock != null)
- {
- break;
- }
- currentSMTPage = currentSMTPage->Next;
- }
-
- if (smtBlock == null)
- {
- // we need to expand the SMT table by a page
- SMTPage* last = GetSMTLastPage();
- last->Next = InitSMTPage();
- aPage = last->Next;
- parent = GetLastBlock(aPage, aItemSize);
- smtBlock = NextFreeBlock(aPage);
-
- if (smtBlock == null)
- {
- Debugger.SendKernelPanic(0x93);
- while (true) { };
- }
- }
- else
- {
- aPage = currentSMTPage;
- parent = GetLastBlock(aPage, aItemSize);
- // we have already found the smt block above
- }
- }
-
- if (parent != null)
- {
- // there is already a block for the same size on the same page
- parent->NextBlock = smtBlock;
- }
- else
- {
- // in this case this is the first block of the size, so we can link it to root
- RootSMTBlock* root = GetFirstBlock(aPage, aItemSize);
- root->First = smtBlock;
- }
-
- smtBlock->SpacesLeft = xItemCount;
- smtBlock->PagePtr = xPtr;
- }
-
- ///
- /// Alloc memory block, of a given size.
- ///
- /// A size of block to alloc, in bytes.
- /// Byte pointer to the start of the block.
- public static byte* Alloc(ushort aSize)
- {
- SMTBlock* pageBlock = GetFirstWithSpace(aSize);
- if (pageBlock == null) // This happens when the page is full and we need to allocate a new page for this size
- {
- CreatePage(SMT, GetRoundedSize(aSize)); // CreatePage will try add this page to any page of the SMT until it finds one with space
- pageBlock = GetFirstWithSpace(aSize);
- if (pageBlock == null)
- {
- //this means that we cant allocate another page
- Debugger.SendKernelPanic(0x121);
- }
- }
-
- //now find position in the block
- ushort* page = (ushort*)pageBlock->PagePtr;
- uint elementSize = GetRoundedSize(aSize) + PrefixItemBytes;
- uint positions = RAT.PageSize / elementSize;
- for (int i = 0; i < positions; i++)
- {
- if (page[i * elementSize / 2] == 0)
- {
- // we have found an empty slot
-
- // update SMT block info
- pageBlock->SpacesLeft--;
-
- // set info in page
- ushort* heapObject = &page[i * elementSize / 2];
- heapObject[0] = aSize; // size of actual object being allocated
- heapObject[1] = 0; // gc status starts as 0
-
- return (byte*)&heapObject[2];
-
- }
- }
-
- // if we get here, RAM is corrupted, since we know we had a space but it turns out we didnt
- Debugger.DoSendNumber((uint)pageBlock);
- Debugger.DoSendNumber(aSize);
- Debugger.SendKernelPanic(0x122);
- while (true) { }
- }
-
- ///
- /// Free a object
- ///
- /// A pointer to the start object.
- public static void Free(void* aPtr)
- {
- ushort* heapObject = (ushort*)aPtr;
- ushort size = heapObject[-2];
- if (size == 0)
- {
- // double free, this object has already been freed
- Debugger.DoBochsBreak();
- Debugger.DoSendNumber((uint)heapObject);
- Debugger.SendKernelPanic(0x99);
- }
-
- uint* allocated = (uint*)aPtr;
- allocated[-1] = 0; // zero both size and gc status at once
-
- // now zero the object so its ready for next allocation
- if (size < 4) // so we dont actually forget to clean up too small items
- {
- size = 4;
- }
- int bytes = size / 4;
- if (size % 4 != 0)
- {
- bytes += 1;
- }
- for (int i = 0; i < bytes; i++)
- {
- allocated[i] = 0;
- }
-
- // need to increase count in SMT again
- // todo: store this info somewhere so this can be done in constant time
- byte* allocatedOnPage = RAT.GetPagePtr(aPtr);
- SMTPage* smtPage = SMT;
- SMTBlock* blockPtr = null;
- while (smtPage != null)
- {
- blockPtr = GetFirstBlock(smtPage, size)->First;
- while (blockPtr != null)
- {
- if(blockPtr->PagePtr == allocatedOnPage)
- {
- blockPtr->SpacesLeft++;
- return;
- }
- blockPtr = blockPtr->NextBlock;
- }
- smtPage = smtPage->Next;
- }
-
- // this shouldnt happen
- Debugger.DoSendNumber((uint)aPtr);
- Debugger.DoSendNumber((uint)SMT);
- Debugger.SendKernelPanic(0x98);
- while (true) { }
- }
-
- #region Statistics
-
- ///
- /// Counts how many elements are currently allocated
- ///
- public static int GetAllocatedObjectCount()
- {
- var ptr = SMT;
- int count = 0;
- do
- {
- count += GetAllocatedObjectCount(ptr);
- ptr = ptr->Next;
- } while (ptr != null);
- return count;
- }
-
- ///
- /// Counts how many elements are currently allocated on a certain page
- ///
- ///
- ///
- private static int GetAllocatedObjectCount(SMTPage* aPage)
- {
- var ptr = aPage->First;
- int count = 0;
- while (ptr != null)
- {
- count += GetAllocatedObjectCount(aPage, ptr->Size);
- ptr = ptr->LargerSize;
- }
- return count;
- }
-
- ///
- /// Counts how many elements are currently allocated in this category on a certain page
- ///
- ///
- ///
- private static int GetAllocatedObjectCount(SMTPage* aPage, uint aSize)
- {
- RootSMTBlock* root = GetFirstBlock(aPage, aSize);
- SMTBlock* ptr = root->First;
-
- uint size = root->Size;
- int count = 0;
-
- while (ptr != null)
- {
- count += (int)(RAT.PageSize / (size + PrefixItemBytes)) - (int)ptr->SpacesLeft;
- ptr = ptr->NextBlock;
- }
-
- return count;
- }
-
- #endregion
-
- #region Cleanup
-
- ///
- /// This function will free all pages allocated for small objects which are emnpty
- ///
- /// Number of pages freed
- public static int PruneSMT()
- {
- int freed = 0;
- SMTPage* page = SMT;
- while (page != null)
- {
- freed += PruneSMT(page);
- page = page->Next;
- }
- return freed;
- }
-
- ///
- /// Prune all empty pages allocated on a certain page
- ///
- ///
- ///
- private static int PruneSMT(SMTPage* aPage)
- {
- int freed = 0;
- RootSMTBlock* ptr = (RootSMTBlock*)aPage->First; // since both RootSMTBlock and SMTBlock have the same size (20) it doesnt matter if cast is wrong
- while(ptr != null)
- {
- freed += PruneSMT(ptr, ptr->Size);
- ptr = ptr->LargerSize;
- }
- return freed;
- }
-
- ///
- /// Prune all empty pages which are linked to root block for a certain size
- /// The root block or first one following it will not be removed!
- ///
- ///
- ///
- ///
- private static int PruneSMT(RootSMTBlock* aBlock, uint aSize)
- {
- int freed = 0;
- int maxElements = (int)(RAT.PageSize / (aSize + PrefixItemBytes));
- SMTBlock* prev = aBlock->First;
- SMTBlock* block = prev->NextBlock;
- while(block != null)
- {
- if (block->SpacesLeft == maxElements)
- {
- // This block is currently empty so free it
- prev->NextBlock = block->NextBlock;
- RAT.Free(block->PagePtr);
-
- uint* toCleanUp = (uint*) block;
- block = prev->NextBlock;
-
- toCleanUp[0] = 0;
- toCleanUp[1] = 0;
- toCleanUp[2] = 0;
-
- freed++;
- }
- else
- {
- prev = block;
- block = block->NextBlock;
- }
- }
- return freed;
- }
-
- #endregion
- }
-}
+using System;
+using Cosmos.Debug.Kernel;
+using IL2CPU.API;
+using IL2CPU.API.Attribs;
+
+namespace Cosmos.Core.Memory
+{
+ ///
+ /// Page containing Size Map Table
+ ///
+ public unsafe struct SMTPage
+ {
+ ///
+ /// Pointer to the next page
+ ///
+ public SMTPage* Next;
+ ///
+ /// Pointer to the root of the smallest block stored on this page
+ ///
+ public RootSMTBlock* First;
+ }
+
+ public unsafe struct RootSMTBlock
+ {
+ ///
+ /// Elements stored in the page have a size less or equal to this
+ /// Does not include the prefix bytes
+ ///
+ public uint Size;
+ ///
+ /// Pointer to the first block for this size
+ ///
+ public SMTBlock* First;
+ ///
+ /// Next larger size root block
+ ///
+ public RootSMTBlock* LargerSize;
+ }
+ // Changing the ordering will break SMTBlock* NextFreeBlock(SMTPage* aPage)
+ public unsafe struct SMTBlock
+ {
+ ///
+ /// Pointer to the actual page, where the elements are stored
+ ///
+ public byte* PagePtr;
+ ///
+ /// How much space is left on the page, makes it easier to skip full pages
+ ///
+ public uint SpacesLeft;
+ ///
+ /// Pointer to the next block for this size
+ ///
+ public SMTBlock* NextBlock;
+ }
+
+ //TODO Remove empty pages as necessary
+ ///
+ /// HeapSmall class. Used to alloc and free small memory blocks on the heap.
+ ///
+ unsafe static public class HeapSmall
+ {
+ ///
+ /// Number of prefix bytes for each item.
+ /// We technically only need 2 but to keep it aligned we have two padding
+ ///
+ public const uint PrefixItemBytes = 2 * sizeof(ushort);
+ ///
+ /// Max item size in the heap.
+ ///
+ public static uint mMaxItemSize;
+
+ ///
+ /// Size map table
+ ///
+ public static SMTPage* SMT;
+
+ #region SMT
+
+ ///
+ /// Find the next free block in a page
+ ///
+ /// Pointer to the start of block in the SMT. null if all SMT pages are full
+ private static SMTBlock* NextFreeBlock(SMTPage* aPage)
+ {
+ SMTBlock* ptr = (SMTBlock*)aPage->First; // since both RootSMTBlock and SMTBlock have the same size (20) it doesnt matter if cast is wrong
+ while (ptr->PagePtr != null) // this would check Size if its actually a RootSMTBlock, which is always non-zero
+ {
+ ptr += 1;
+ if (ptr >= (byte*)aPage + RAT.PageSize - 8)
+ {
+ return null;
+ }
+ }
+ return ptr;
+
+ }
+
+ ///
+ /// Gets the root block in the SMT for objects of this size
+ ///
+ /// Size of allocated block
+ /// Page to seach in
+ /// Pointer of block in SMT.
+ private static RootSMTBlock* GetFirstBlock(SMTPage* aPage, uint aSize)
+ {
+ RootSMTBlock* ptr = aPage->First;
+ uint curSize = ptr->Size;
+ while (curSize < aSize)
+ {
+ ptr = ptr->LargerSize;
+ if (ptr == null)
+ {
+ return null;
+ }
+ curSize = ptr->Size;
+ }
+ return ptr;
+ }
+
+ ///
+ /// Gets the last block on a certain page for objects of this size
+ ///
+ /// Page to search
+ ///
+ ///
+ private static SMTBlock* GetLastBlock(SMTPage* page, uint aSize)
+ {
+ SMTBlock* ptr = GetFirstBlock(page, aSize)->First;
+ if (ptr == null)
+ {
+ return null;
+ }
+
+ while (ptr->NextBlock != null)
+ {
+ ptr = ptr->NextBlock;
+ }
+ return ptr;
+ }
+
+ ///
+ /// Get the first block for this size on any SMT page, which has space left to allocate to
+ ///
+ ///
+ /// Null if no more space on any block of this size
+ private static SMTBlock* GetFirstWithSpace(uint aSize)
+ {
+ SMTPage* page = SMT;
+ SMTBlock* block = null;
+ do
+ {
+ block = GetFirstWithSpace(page, aSize);
+ page = page->Next;
+ } while (block == null && page != null);
+ return block;
+ }
+
+ ///
+ /// Get the first block for this size on this SMT page, which has space left to allocate to
+ ///
+ ///
+ /// Null if no more space on this page
+ private static SMTBlock* GetFirstWithSpace(SMTPage* aPage, uint aSize)
+ {
+ return GetFirstWithSpace(GetFirstBlock(aPage, aSize), aSize);
+ }
+
+ ///
+ /// Get the first block for this size in this SMT block chain, which has space left to allocate to
+ ///
+ /// The root node to start the search at
+ ///
+ ///
+ private static SMTBlock* GetFirstWithSpace(RootSMTBlock* aRoot, uint aSize)
+ {
+ SMTBlock* ptr = aRoot->First;
+ if (ptr == null) // Can this ever happen?
+ {
+ return null;
+ }
+ while (ptr->SpacesLeft == 0)
+ {
+ ptr = ptr->NextBlock;
+ if (ptr == null)
+ {
+ return null;
+ }
+ }
+ return ptr;
+ }
+
+ ///
+ /// Add a new root block for a certain size to a certain SMT page
+ ///
+ /// Size must be divisible by 2 otherwise Alloc breaks
+ private static void AddRootSMTBlock(SMTPage* aPage, uint aSize)
+ {
+ RootSMTBlock* ptr = aPage->First;
+ while (ptr->LargerSize != null)
+ {
+ ptr = ptr->LargerSize;
+ }
+
+ if (aSize < ptr->Size)
+ {
+ // we cant later add a block with a size smaller than an earlier block. That would break the algorithm
+ Debugger.DoSendNumber(aSize);
+ Debugger.DoSendNumber(ptr->Size);
+ Debugger.SendKernelPanic(0x83);
+ while (true) { }
+ }
+
+ if (ptr->Size == 0) // This is the first block to be allocated on the page
+ {
+ ptr->Size = aSize;
+ }
+ else
+ {
+ RootSMTBlock* block = (RootSMTBlock*)NextFreeBlock(aPage); // we should actually check that this is not null
+ //but we should also only call this code right at the beginning so it should be fine
+ block->Size = aSize;
+ ptr->LargerSize = block;
+ }
+ CreatePage(aPage, aSize);
+ }
+
+ ///
+ /// Get the Last Page of the SMT
+ ///
+ ///
+ private static SMTPage* GetSMTLastPage()
+ {
+ var page = SMT;
+ while (page->Next != null)
+ {
+ page = page->Next;
+ }
+ return page;
+ }
+
+ ///
+ /// Return the size a certain element will be allocated as
+ ///
+ ///
+ public static uint GetRoundedSize(uint aSize)
+ {
+ return GetFirstBlock(SMT, aSize)->Size;
+ }
+
+ #endregion
+
+ ///
+ /// Init small heap.
+ ///
+ /// Thrown on fatal error, contact support.
+ static public void Init()
+ {
+ //TODO Adjust for new page and header sizes
+ // 4 slots, ~1k ea
+ uint xMaxItemSize = RAT.PageSize / 4 - PrefixItemBytes;
+ // Word align it
+ mMaxItemSize = xMaxItemSize / sizeof(uint) * sizeof(uint);
+
+ SMT = InitSMTPage();
+ }
+
+ ///
+ /// Allocates and initialise a page for the SMT table
+ ///
+ ///
+ private static SMTPage* InitSMTPage()
+ {
+ SMTPage* page = (SMTPage*)RAT.AllocPages(RAT.PageType.SMT, 1);
+ page->First = (RootSMTBlock*)page + 1;
+
+ // TODO Change these sizes after further study and also when page size changes.
+ // SMT can be grown as needed. Also can adjust and create new ones dynamicaly as it runs.
+ // The current algorithm only works if we create the inital pages in increasing order
+ AddRootSMTBlock(page, 16);
+ AddRootSMTBlock(page, 24);
+ AddRootSMTBlock(page, 48);
+ AddRootSMTBlock(page, 64);
+ AddRootSMTBlock(page, 128);
+ AddRootSMTBlock(page, 256);
+ AddRootSMTBlock(page, 512);
+ AddRootSMTBlock(page, mMaxItemSize);
+ return page;
+ }
+
+ ///
+ /// Create a page with the size of an item and try add it to the SMT at a certain page
+ /// If the SMT page is full, it will be added to the first SMT page with space or a new SMT page is allocated
+ ///
+ /// Object size in bytes
+ /// Thrown if:
+ ///
+ /// - aItemSize is 0.
+ /// - aItemSize is not word aligned.
+ /// - SMT is not initialized.
+ /// - The item size is bigger then a small heap size.
+ ///
+ ///
+ static void CreatePage(SMTPage* aPage, uint aItemSize)
+ {
+ byte* xPtr = (byte*)RAT.AllocPages(RAT.PageType.HeapSmall, 1);
+ if (xPtr == null)
+ {
+ return; // we failed to create the page, Alloc should still handle this case
+ }
+
+ uint xSlotSize = aItemSize + PrefixItemBytes;
+ uint xItemCount = RAT.PageSize / xSlotSize;
+ for (uint i = 0; i < xItemCount; i++)
+ {
+ byte* xSlotPtr = xPtr + i * xSlotSize;
+ ushort* xMetaDataPtr = (ushort*)xSlotPtr;
+ xMetaDataPtr[0] = 0; // Actual data size. 0 is empty.
+ xMetaDataPtr[1] = 0; // Ref count
+ }
+
+ //now add it to the smt
+ SMTBlock* parent = GetLastBlock(aPage, aItemSize);
+ SMTBlock* smtBlock = NextFreeBlock(aPage); //get the next free block in the smt
+
+ if (smtBlock == null) // we could not allocate a new block since the SMT table is all full on this page
+ {
+ // we now have two options:
+ // 1. there exists a later page in the chain, which has space
+ // 2. all SMT Pages are full and we need to allocate a new one
+
+ // first, check if we find a later page with space
+ SMTPage* currentSMTPage = aPage->Next;
+ while (currentSMTPage != null)
+ {
+ smtBlock = NextFreeBlock(currentSMTPage);
+ if(smtBlock != null)
+ {
+ break;
+ }
+ currentSMTPage = currentSMTPage->Next;
+ }
+
+ if (smtBlock == null)
+ {
+ // we need to expand the SMT table by a page
+ SMTPage* last = GetSMTLastPage();
+ last->Next = InitSMTPage();
+ aPage = last->Next;
+ parent = GetLastBlock(aPage, aItemSize);
+ smtBlock = NextFreeBlock(aPage);
+
+ if (smtBlock == null)
+ {
+ Debugger.SendKernelPanic(0x93);
+ while (true) { };
+ }
+ }
+ else
+ {
+ aPage = currentSMTPage;
+ parent = GetLastBlock(aPage, aItemSize);
+ // we have already found the smt block above
+ }
+ }
+
+ if (parent != null)
+ {
+ // there is already a block for the same size on the same page
+ parent->NextBlock = smtBlock;
+ }
+ else
+ {
+ // in this case this is the first block of the size, so we can link it to root
+ RootSMTBlock* root = GetFirstBlock(aPage, aItemSize);
+ root->First = smtBlock;
+ }
+
+ smtBlock->SpacesLeft = xItemCount;
+ smtBlock->PagePtr = xPtr;
+ }
+
+ ///
+ /// Alloc memory block, of a given size.
+ ///
+ /// A size of block to alloc, in bytes.
+ /// Byte pointer to the start of the block.
+ public static byte* Alloc(ushort aSize)
+ {
+ SMTBlock* pageBlock = GetFirstWithSpace(aSize);
+ if (pageBlock == null) // This happens when the page is full and we need to allocate a new page for this size
+ {
+ CreatePage(SMT, GetRoundedSize(aSize)); // CreatePage will try add this page to any page of the SMT until it finds one with space
+ pageBlock = GetFirstWithSpace(aSize);
+ if (pageBlock == null)
+ {
+ //this means that we cant allocate another page
+ Debugger.SendKernelPanic(0x121);
+ }
+ }
+
+ //now find position in the block
+ ushort* page = (ushort*)pageBlock->PagePtr;
+ uint elementSize = GetRoundedSize(aSize) + PrefixItemBytes;
+ uint positions = RAT.PageSize / elementSize;
+ for (int i = 0; i < positions; i++)
+ {
+ if (page[i * elementSize / 2] == 0)
+ {
+ // we have found an empty slot
+
+ // update SMT block info
+ pageBlock->SpacesLeft--;
+
+ // set info in page
+ ushort* heapObject = &page[i * elementSize / 2];
+ heapObject[0] = aSize; // size of actual object being allocated
+ heapObject[1] = 0; // gc status starts as 0
+
+ return (byte*)&heapObject[2];
+
+ }
+ }
+
+ // if we get here, RAM is corrupted, since we know we had a space but it turns out we didnt
+ Debugger.DoSendNumber((uint)pageBlock);
+ Debugger.DoSendNumber(aSize);
+ Debugger.SendKernelPanic(0x122);
+ while (true) { }
+ }
+
+ ///
+ /// Free a object
+ ///
+ /// A pointer to the start object.
+ public static void Free(void* aPtr)
+ {
+ ushort* heapObject = (ushort*)aPtr;
+ ushort size = heapObject[-2];
+ if (size == 0)
+ {
+ // double free, this object has already been freed
+ Debugger.DoBochsBreak();
+ Debugger.DoSendNumber((uint)heapObject);
+ Debugger.SendKernelPanic(0x99);
+ }
+
+ uint* allocated = (uint*)aPtr;
+ allocated[-1] = 0; // zero both size and gc status at once
+
+ // now zero the object so its ready for next allocation
+ if (size < 4) // so we dont actually forget to clean up too small items
+ {
+ size = 4;
+ }
+ int bytes = size / 4;
+ if (size % 4 != 0)
+ {
+ bytes += 1;
+ }
+ for (int i = 0; i < bytes; i++)
+ {
+ allocated[i] = 0;
+ }
+
+ // need to increase count in SMT again
+ // todo: store this info somewhere so this can be done in constant time
+ byte* allocatedOnPage = RAT.GetPagePtr(aPtr);
+ SMTPage* smtPage = SMT;
+ SMTBlock* blockPtr = null;
+ while (smtPage != null)
+ {
+ blockPtr = GetFirstBlock(smtPage, size)->First;
+ while (blockPtr != null)
+ {
+ if(blockPtr->PagePtr == allocatedOnPage)
+ {
+ blockPtr->SpacesLeft++;
+ return;
+ }
+ blockPtr = blockPtr->NextBlock;
+ }
+ smtPage = smtPage->Next;
+ }
+
+ // this shouldnt happen
+ Debugger.DoSendNumber((uint)aPtr);
+ Debugger.DoSendNumber((uint)SMT);
+ Debugger.SendKernelPanic(0x98);
+ while (true) { }
+ }
+
+ #region Statistics
+
+ ///
+ /// Counts how many elements are currently allocated
+ ///
+ public static int GetAllocatedObjectCount()
+ {
+ var ptr = SMT;
+ int count = 0;
+ do
+ {
+ count += GetAllocatedObjectCount(ptr);
+ ptr = ptr->Next;
+ } while (ptr != null);
+ return count;
+ }
+
+ ///
+ /// Counts how many elements are currently allocated on a certain page
+ ///
+ ///
+ ///
+ private static int GetAllocatedObjectCount(SMTPage* aPage)
+ {
+ var ptr = aPage->First;
+ int count = 0;
+ while (ptr != null)
+ {
+ count += GetAllocatedObjectCount(aPage, ptr->Size);
+ ptr = ptr->LargerSize;
+ }
+ return count;
+ }
+
+ ///
+ /// Counts how many elements are currently allocated in this category on a certain page
+ ///
+ ///
+ ///
+ private static int GetAllocatedObjectCount(SMTPage* aPage, uint aSize)
+ {
+ RootSMTBlock* root = GetFirstBlock(aPage, aSize);
+ SMTBlock* ptr = root->First;
+
+ uint size = root->Size;
+ int count = 0;
+
+ while (ptr != null)
+ {
+ count += (int)(RAT.PageSize / (size + PrefixItemBytes)) - (int)ptr->SpacesLeft;
+ ptr = ptr->NextBlock;
+ }
+
+ return count;
+ }
+
+ #endregion
+
+ #region Cleanup
+
+ ///
+ /// This function will free all pages allocated for small objects which are emnpty
+ ///
+ /// Number of pages freed
+ public static int PruneSMT()
+ {
+ int freed = 0;
+ SMTPage* page = SMT;
+ while (page != null)
+ {
+ freed += PruneSMT(page);
+ page = page->Next;
+ }
+ return freed;
+ }
+
+ ///
+ /// Prune all empty pages allocated on a certain page
+ ///
+ ///
+ ///
+ private static int PruneSMT(SMTPage* aPage)
+ {
+ int freed = 0;
+ RootSMTBlock* ptr = (RootSMTBlock*)aPage->First; // since both RootSMTBlock and SMTBlock have the same size (20) it doesnt matter if cast is wrong
+ while(ptr != null)
+ {
+ freed += PruneSMT(ptr, ptr->Size);
+ ptr = ptr->LargerSize;
+ }
+ return freed;
+ }
+
+ ///
+ /// Prune all empty pages which are linked to root block for a certain size
+ /// The root block or first one following it will not be removed!
+ ///
+ ///
+ ///
+ ///
+ private static int PruneSMT(RootSMTBlock* aBlock, uint aSize)
+ {
+ int freed = 0;
+ int maxElements = (int)(RAT.PageSize / (aSize + PrefixItemBytes));
+ SMTBlock* prev = aBlock->First;
+ SMTBlock* block = prev->NextBlock;
+ while(block != null)
+ {
+ if (block->SpacesLeft == maxElements)
+ {
+ // This block is currently empty so free it
+ prev->NextBlock = block->NextBlock;
+ RAT.Free(block->PagePtr);
+
+ uint* toCleanUp = (uint*) block;
+ block = prev->NextBlock;
+
+ toCleanUp[0] = 0;
+ toCleanUp[1] = 0;
+ toCleanUp[2] = 0;
+
+ freed++;
+ }
+ else
+ {
+ prev = block;
+ block = block->NextBlock;
+ }
+ }
+ return freed;
+ }
+
+ #endregion
+ }
+}
diff --git a/source/Cosmos.Core/Memory/RAT.cs b/source/Cosmos.Core/Memory/RAT.cs
index 3413e3e687..aa590927ab 100644
--- a/source/Cosmos.Core/Memory/RAT.cs
+++ b/source/Cosmos.Core/Memory/RAT.cs
@@ -1,359 +1,359 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using Cosmos.Debug.Kernel;
-using Native = System.UInt32;
-
-namespace Cosmos.Core.Memory
-{
- ///
- /// RAT (RAM Allocation Table) class.
- ///
- unsafe static public class RAT
- {
- // RAT: RAM Allocation Table
- //
- // A byte table which defines the code which owns the page.
- // Owners can further subdivide table types on their own and RAT
- // code must not assume anything about contents of pages other
- // than who owns them.
-
- ///
- /// PageType enum. Used to define the type of the page.
- ///
- public enum PageType : byte
- {
- ///
- /// Empty page.
- /// Can also indicate invalid page.
- ///
- Empty = 0,
-
- // Data Types from 1, special meanings from 255 down.
- ///
- /// Indicates that the page contains objects managed by the GC
- ///
- GCManaged = 1,
- ///
- /// Small heap page.
- ///
- HeapSmall = 3,
- ///
- /// Medium heap page.
- ///
- HeapMedium = 5,
- ///
- /// Large heap page.
- ///
- HeapLarge = 7,
-
- ///
- /// RAT type page.
- ///
- RAT = 32,
- ///
- /// Page which is part of the SMT
- ///
- SMT = 64,
- // Extension of previous page.
- ///
- /// Extension of pre-existing page.
- ///
- Extension = 128,
- }
-
- ///
- /// Debug flag.
- ///
- /// Used to bypass certain checks that will fail during tests and debugging.
- static internal bool Debug = false;
-
- ///
- /// Native Intel page size.
- ///
- ///
- /// - x86 Page Size: 4k, 2m (PAE only), 4m.
- /// - x64 Page Size: 4k, 2m
- ///
- public const uint PageSize = 4096;
-
- ///
- /// Start of area usable for heap, and also start of heap.
- ///
- public static byte* RamStart;
- ///
- /// Pointer to end of the heap
- ///
- public static byte* HeapEnd;
- ///
- /// Size of heap.
- ///
- public static uint RamSize;
- ///
- /// Number of pages in the heap.
- ///
- /// Calculated from mSize.
- public static uint TotalPageCount;
-
- ///
- /// Number of pages which are currently not in use
- ///
- public static uint FreePageCount;
-
- ///
- /// If number of free pages drops below this number, we trigger the GC.Collect automatically
- /// If set to -1 it is disabled
- ///
- public static int MinFreePages = -1;
-
- ///
- /// Number of the times the GC has been triggered automatically
- ///
- public static uint GCTriggered = 0;
-
- ///
- /// Pointer to the RAT.
- ///
- /// Covers Data area only.
- // We need a pointer as the RAT can move around in future with dynamic RAM etc.
- public static byte* mRAT;
-
- ///
- /// Init RAT.
- ///
- /// A pointer to the start of the heap.
- /// A heap size, in bytes.
- /// Thrown if:
- ///
- /// - RAM start or size is not page aligned.
- ///
- ///
- public static void Init(byte* aStartPtr, uint aSize)
- {
- if ((uint)aStartPtr % PageSize != 0 && !Debug)
- {
- Debugger.DoSendNumber((uint)aStartPtr % PageSize);
- Debugger.DoBochsBreak();
- throw new Exception("RAM start must be page aligned.");
- }
-
- if (aSize % PageSize != 0)
- {
- Debugger.DoSendNumber(aSize % PageSize);
- Debugger.SendKernelPanic(11);
- throw new Exception("RAM size must be page aligned.");
- }
-
- RamStart = aStartPtr;
- RamSize = aSize;
- HeapEnd = aStartPtr + aSize;
- TotalPageCount = aSize / PageSize;
- FreePageCount = TotalPageCount;
-
- // We need one status byte for each block.
- // Intel blocks are 4k (10 bits). So for 4GB, this means
- // 32 - 12 = 20 bits, 1 MB for a RAT for 4GB. 0.025%
- uint xRatPageCount = (TotalPageCount - 1) / PageSize + 1;
- uint xRatTotalSize = xRatPageCount * PageSize;
- mRAT = RamStart + RamSize - xRatTotalSize;
-
- if (mRAT > HeapEnd)
- {
- throw new Exception("mRAT is greater than heap. rattotalsize is "+xRatTotalSize);
- }
-
- // Mark empty pages as such in the RAT Table
- for (byte* p = mRAT; p < mRAT + TotalPageCount - xRatPageCount; p++)
- {
- *p = (byte)PageType.Empty;
- }
- // Mark the rat pages as such
- for (byte* p = mRAT + TotalPageCount - xRatPageCount; p < mRAT + xRatTotalSize; p++)
- {
- *p = (byte)PageType.RAT;
- }
- // Remove pages needed for RAT table from count
- FreePageCount -= xRatPageCount;
-
- Heap.Init();
- }
-
- ///
- /// Get page count.
- ///
- /// A page type to count.
- /// Number of pages of this type including extension pages
- public static uint GetPageCount(byte aType = 0)
- {
- uint xResult = 0;
- bool xCounting = false;
- for (byte* p = mRAT; p < mRAT + TotalPageCount; p++)
- {
- if (*p == aType)
- {
- xResult++;
- xCounting = true;
- }
- else if (xCounting)
- {
- if (*p == (byte)PageType.Extension || *p == aType)
- {
- xResult++;
- }
- else
- {
- xCounting = false;
- }
- }
- }
- return xResult;
- }
-
- ///
- /// Alloc a given number of pages, all of the same type.
- ///
- /// A type of pages to alloc.
- /// Number of pages to alloc. (default = 1)
- /// A pointer to the first page on success, null on failure.
- public static void* AllocPages(PageType aType, uint aPageCount = 1)
- {
- if (MinFreePages > FreePageCount)
- {
- Heap.Collect();
- GCTriggered++;
- }
-
- byte* xPos = null;
-
- // Could combine with an external method or delegate, but will slow things down
- // unless we can force it to be inlined.
- // Alloc single blocks at bottom, larger blocks at top to help reduce fragmentation.
- uint xCount = 0;
- if (aPageCount == 1)
- {
- for (byte* p = mRAT; p < mRAT + TotalPageCount; p++)
- {
- if (*p == (byte)PageType.Empty)
- {
- xPos = p;
- break;
- }
- }
- }
- else
- {
- // This loop will FAIL if mRAT is ever 0. This should be impossible though
- // so we don't bother to account for such a case. xPos would also have issues.
- for (byte* p = mRAT + TotalPageCount - 1; p >= mRAT; p--)
- {
- if (*p == (byte)PageType.Empty)
- {
- if (++xCount == aPageCount)
- {
- xPos = p;
- break;
- }
- }
- else
- {
- xCount = 0;
- }
- }
- }
-
- // If we found enough space, mark it as used.
- if (xPos != null)
- {
- var diff = xPos - mRAT;
- byte* xResult = RamStart + diff * PageSize;
- *xPos = (byte)aType;
- for (byte* p = xPos + 1; p < xPos + xCount; p++)
- {
- *p = (byte)PageType.Extension;
- }
- CPU.ZeroFill((uint)xResult, PageSize * aPageCount);
-
- // Decrement free page count
- FreePageCount -= aPageCount;
-
- return xResult;
- }
- return null;
-
- }
-
- ///
- /// Get the first RAT address.
- ///
- /// A pointer to the block.
- /// The index in RAT to which this pointer belongs
- /// Thrown if page type is not found.
- public static uint GetFirstRATIndex(void* aPtr)
- {
- var xPos = (uint)((byte*)aPtr - RamStart) / PageSize;
- // See note about when mRAT = 0 in Alloc.
- for (byte* p = mRAT + xPos; p >= mRAT; p--)
- {
- if (*p != (byte)PageType.Extension)
- {
- return (uint)(p - mRAT);
- }
- }
- throw new Exception("Page type not found. Likely RAT is rotten.");
- }
-
- ///
- /// Get the pointer to the start of the page containing the pointer's address
- ///
- ///
- ///
- public static byte* GetPagePtr(void* aPtr)
- {
- return (byte*)aPtr - ((byte*)aPtr - RamStart) % PageSize;
- }
-
- ///
- /// Get the page type pointed by a pointer to the RAT entry.
- ///
- /// A pointer to the page to get the type of.
- /// byte value.
- /// Thrown if page type is not found.
- public static PageType GetPageType(void* aPtr)
- {
- if(aPtr < RamStart || aPtr > HeapEnd)
- {
- return PageType.Empty;
- }
- return (PageType)mRAT[GetFirstRATIndex(aPtr)];
- }
-
- ///
- /// Free page.
- ///
- /// A index to the page to be freed.
- public static void Free(uint aPageIdx)
- {
- byte* p = mRAT + aPageIdx;
- *p = (byte)PageType.Empty;
- FreePageCount++;
- for (; p < mRAT + TotalPageCount;)
- {
- if (*++p != (byte)PageType.Extension)
- {
- break;
- }
- *p = (byte)PageType.Empty;
- FreePageCount++;
- }
- }
-
- ///
- /// Free the page this pointer points to
- ///
- ///
- public static void Free(void* aPtr)
- {
- Free(GetFirstRATIndex(aPtr));
- }
- }
-}
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Cosmos.Debug.Kernel;
+using Native = System.UInt32;
+
+namespace Cosmos.Core.Memory
+{
+ ///
+ /// RAT (RAM Allocation Table) class.
+ ///
+ unsafe static public class RAT
+ {
+ // RAT: RAM Allocation Table
+ //
+ // A byte table which defines the code which owns the page.
+ // Owners can further subdivide table types on their own and RAT
+ // code must not assume anything about contents of pages other
+ // than who owns them.
+
+ ///
+ /// PageType enum. Used to define the type of the page.
+ ///
+ public enum PageType : byte
+ {
+ ///
+ /// Empty page.
+ /// Can also indicate invalid page.
+ ///
+ Empty = 0,
+
+ // Data Types from 1, special meanings from 255 down.
+ ///
+ /// Indicates that the page contains objects managed by the GC
+ ///
+ GCManaged = 1,
+ ///
+ /// Small heap page.
+ ///
+ HeapSmall = 3,
+ ///
+ /// Medium heap page.
+ ///
+ HeapMedium = 5,
+ ///
+ /// Large heap page.
+ ///
+ HeapLarge = 7,
+
+ ///
+ /// RAT type page.
+ ///
+ RAT = 32,
+ ///
+ /// Page which is part of the SMT
+ ///
+ SMT = 64,
+ // Extension of previous page.
+ ///
+ /// Extension of pre-existing page.
+ ///
+ Extension = 128,
+ }
+
+ ///
+ /// Debug flag.
+ ///
+ /// Used to bypass certain checks that will fail during tests and debugging.
+ static internal bool Debug = false;
+
+ ///
+ /// Native Intel page size.
+ ///
+ ///
+ /// - x86 Page Size: 4k, 2m (PAE only), 4m.
+ /// - x64 Page Size: 4k, 2m
+ ///
+ public const uint PageSize = 4096;
+
+ ///
+ /// Start of area usable for heap, and also start of heap.
+ ///
+ public static byte* RamStart;
+ ///
+ /// Pointer to end of the heap
+ ///
+ public static byte* HeapEnd;
+ ///
+ /// Size of heap.
+ ///
+ public static uint RamSize;
+ ///
+ /// Number of pages in the heap.
+ ///
+ /// Calculated from mSize.
+ public static uint TotalPageCount;
+
+ ///
+ /// Number of pages which are currently not in use
+ ///
+ public static uint FreePageCount;
+
+ ///
+ /// If number of free pages drops below this number, we trigger the GC.Collect automatically
+ /// If set to -1 it is disabled
+ ///
+ public static int MinFreePages = -1;
+
+ ///
+ /// Number of the times the GC has been triggered automatically
+ ///
+ public static uint GCTriggered = 0;
+
+ ///
+ /// Pointer to the RAT.
+ ///
+ /// Covers Data area only.
+ // We need a pointer as the RAT can move around in future with dynamic RAM etc.
+ public static byte* mRAT;
+
+ ///
+ /// Init RAT.
+ ///
+ /// A pointer to the start of the heap.
+ /// A heap size, in bytes.
+ /// Thrown if:
+ ///
+ /// - RAM start or size is not page aligned.
+ ///
+ ///
+ public static void Init(byte* aStartPtr, uint aSize)
+ {
+ if ((uint)aStartPtr % PageSize != 0 && !Debug)
+ {
+ Debugger.DoSendNumber((uint)aStartPtr % PageSize);
+ Debugger.DoBochsBreak();
+ throw new Exception("RAM start must be page aligned.");
+ }
+
+ if (aSize % PageSize != 0)
+ {
+ Debugger.DoSendNumber(aSize % PageSize);
+ Debugger.SendKernelPanic(11);
+ throw new Exception("RAM size must be page aligned.");
+ }
+
+ RamStart = aStartPtr;
+ RamSize = aSize;
+ HeapEnd = aStartPtr + aSize;
+ TotalPageCount = aSize / PageSize;
+ FreePageCount = TotalPageCount;
+
+ // We need one status byte for each block.
+ // Intel blocks are 4k (10 bits). So for 4GB, this means
+ // 32 - 12 = 20 bits, 1 MB for a RAT for 4GB. 0.025%
+ uint xRatPageCount = (TotalPageCount - 1) / PageSize + 1;
+ uint xRatTotalSize = xRatPageCount * PageSize;
+ mRAT = RamStart + RamSize - xRatTotalSize;
+
+ if (mRAT > HeapEnd)
+ {
+ throw new Exception("mRAT is greater than heap. rattotalsize is "+xRatTotalSize);
+ }
+
+ // Mark empty pages as such in the RAT Table
+ for (byte* p = mRAT; p < mRAT + TotalPageCount - xRatPageCount; p++)
+ {
+ *p = (byte)PageType.Empty;
+ }
+ // Mark the rat pages as such
+ for (byte* p = mRAT + TotalPageCount - xRatPageCount; p < mRAT + xRatTotalSize; p++)
+ {
+ *p = (byte)PageType.RAT;
+ }
+ // Remove pages needed for RAT table from count
+ FreePageCount -= xRatPageCount;
+
+ Heap.Init();
+ }
+
+ ///
+ /// Get page count.
+ ///
+ /// A page type to count.
+ /// Number of pages of this type including extension pages
+ public static uint GetPageCount(byte aType = 0)
+ {
+ uint xResult = 0;
+ bool xCounting = false;
+ for (byte* p = mRAT; p < mRAT + TotalPageCount; p++)
+ {
+ if (*p == aType)
+ {
+ xResult++;
+ xCounting = true;
+ }
+ else if (xCounting)
+ {
+ if (*p == (byte)PageType.Extension || *p == aType)
+ {
+ xResult++;
+ }
+ else
+ {
+ xCounting = false;
+ }
+ }
+ }
+ return xResult;
+ }
+
+ ///
+ /// Alloc a given number of pages, all of the same type.
+ ///
+ /// A type of pages to alloc.
+ /// Number of pages to alloc. (default = 1)
+ /// A pointer to the first page on success, null on failure.
+ public static void* AllocPages(PageType aType, uint aPageCount = 1)
+ {
+ if (MinFreePages > FreePageCount)
+ {
+ Heap.Collect();
+ GCTriggered++;
+ }
+
+ byte* xPos = null;
+
+ // Could combine with an external method or delegate, but will slow things down
+ // unless we can force it to be inlined.
+ // Alloc single blocks at bottom, larger blocks at top to help reduce fragmentation.
+ uint xCount = 0;
+ if (aPageCount == 1)
+ {
+ for (byte* p = mRAT; p < mRAT + TotalPageCount; p++)
+ {
+ if (*p == (byte)PageType.Empty)
+ {
+ xPos = p;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // This loop will FAIL if mRAT is ever 0. This should be impossible though
+ // so we don't bother to account for such a case. xPos would also have issues.
+ for (byte* p = mRAT + TotalPageCount - 1; p >= mRAT; p--)
+ {
+ if (*p == (byte)PageType.Empty)
+ {
+ if (++xCount == aPageCount)
+ {
+ xPos = p;
+ break;
+ }
+ }
+ else
+ {
+ xCount = 0;
+ }
+ }
+ }
+
+ // If we found enough space, mark it as used.
+ if (xPos != null)
+ {
+ var diff = xPos - mRAT;
+ byte* xResult = RamStart + diff * PageSize;
+ *xPos = (byte)aType;
+ for (byte* p = xPos + 1; p < xPos + xCount; p++)
+ {
+ *p = (byte)PageType.Extension;
+ }
+ CPU.ZeroFill((uint)xResult, PageSize * aPageCount);
+
+ // Decrement free page count
+ FreePageCount -= aPageCount;
+
+ return xResult;
+ }
+ return null;
+
+ }
+
+ ///
+ /// Get the first RAT address.
+ ///
+ /// A pointer to the block.
+ /// The index in RAT to which this pointer belongs
+ /// Thrown if page type is not found.
+ public static uint GetFirstRATIndex(void* aPtr)
+ {
+ var xPos = (uint)((byte*)aPtr - RamStart) / PageSize;
+ // See note about when mRAT = 0 in Alloc.
+ for (byte* p = mRAT + xPos; p >= mRAT; p--)
+ {
+ if (*p != (byte)PageType.Extension)
+ {
+ return (uint)(p - mRAT);
+ }
+ }
+ throw new Exception("Page type not found. Likely RAT is rotten.");
+ }
+
+ ///
+ /// Get the pointer to the start of the page containing the pointer's address
+ ///
+ ///
+ ///
+ public static byte* GetPagePtr(void* aPtr)
+ {
+ return (byte*)aPtr - ((byte*)aPtr - RamStart) % PageSize;
+ }
+
+ ///
+ /// Get the page type pointed by a pointer to the RAT entry.
+ ///
+ /// A pointer to the page to get the type of.
+ /// byte value.
+ /// Thrown if page type is not found.
+ public static PageType GetPageType(void* aPtr)
+ {
+ if(aPtr < RamStart || aPtr > HeapEnd)
+ {
+ return PageType.Empty;
+ }
+ return (PageType)mRAT[GetFirstRATIndex(aPtr)];
+ }
+
+ ///
+ /// Free page.
+ ///
+ /// A index to the page to be freed.
+ public static void Free(uint aPageIdx)
+ {
+ byte* p = mRAT + aPageIdx;
+ *p = (byte)PageType.Empty;
+ FreePageCount++;
+ for (; p < mRAT + TotalPageCount;)
+ {
+ if (*++p != (byte)PageType.Extension)
+ {
+ break;
+ }
+ *p = (byte)PageType.Empty;
+ FreePageCount++;
+ }
+ }
+
+ ///
+ /// Free the page this pointer points to
+ ///
+ ///
+ public static void Free(void* aPtr)
+ {
+ Free(GetFirstRATIndex(aPtr));
+ }
+ }
+}
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/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..733971de69
--- /dev/null
+++ b/source/Cosmos.Core/Processing/ProcessorScheduler.cs
@@ -0,0 +1,90 @@
+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;
+ }
+
+ 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 void SwitchTask()
+ {
+ if (ProcessContext.m_CurrentContext != null)
+ {
+ CPU.DisableInterrupts();
+
+ 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 -= 10; //Since Local APIC Frequency = 100Hz remove 10ms per interrupt
+ 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;
+
+ CPU.EnableInterrupts();
+ }
+
+ LocalAPIC.EndOfInterrupt();
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs
index f5f5acde80..f48e403335 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 != 0x28)
{
- 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__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__A1Cosmos_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 bb4e48e2af..2009571699 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)
@@ -25,6 +25,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();
+ }
+
[PlugMethod(Signature = "System_IRuntimeMethodInfo__System_Delegate_FindMethodHandle__")]
public static object FindMethodHandle(Delegate aThis)
{
diff --git a/source/Cosmos.Core_Plugs/System/Threading/ThreadImpl.cs b/source/Cosmos.Core_Plugs/System/Threading/ThreadImpl.cs
new file mode 100644
index 0000000000..2c62d7a323
--- /dev/null
+++ b/source/Cosmos.Core_Plugs/System/Threading/ThreadImpl.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Threading;
+using IL2CPU.API.Attribs;
+
+namespace Cosmos.Core_Plugs.System.Threading
+{
+ [Plug("System.Threading.Thread, System.Private.CoreLib")]
+ public static class ThreadImpl
+ {
+ public static Thread GetCurrentThreadNative()
+ {
+ return null;
+ }
+
+ 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
+ // // see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx for more details
+
+ // if ((ms > 0) && (ms != Timeout.Infinite))
+ // {
+ // double fac = CPU.GetCycleRate() / 1000d;
+ // double ticks = ms / 1000d * Stopwatch.Frequency + CPU.GetCycleCount() * fac;
+
+ // while (ticks < CPU.GetCycleCount() * fac)
+ // new Action(() => { }).Invoke(); // execute an empty operation
+ // }
+ // else if (ms < 0)
+ // throw new ThreadInterruptedException();
+ // }
+ }
+}
diff --git a/source/Cosmos.HAL2/ApicTimer.cs b/source/Cosmos.HAL2/ApicTimer.cs
new file mode 100644
index 0000000000..e2bdcba413
--- /dev/null
+++ b/source/Cosmos.HAL2/ApicTimer.cs
@@ -0,0 +1,71 @@
+using Cosmos.Core;
+
+namespace Cosmos.HAL
+{
+ ///
+ /// Local APIC Timer class.
+ ///
+ public static class ApicTimer
+ {
+ ///
+ /// APIC base frequency
+ ///
+ public static ulong BaseFrequency;
+
+ ///
+ /// APIC frequency
+ ///
+ public static ulong Frequency;
+
+ private static ulong Ticks => LocalAPIC.In(LocalAPIC.LAPIC_TCCR);
+
+ ///
+ /// Initialize local APIC timer.
+ ///
+ public static void Initialize()
+ {
+ Frequency = 100;
+ 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()
+ {
+ LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x00020000 | 0x28);
+ LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0x3); //Divide 16
+ LocalAPIC.Out(LocalAPIC.LAPIC_TICR, (uint)((BaseFrequency / 16) / Frequency));
+ }
+
+ ///
+ /// Stop local APIC timer.
+ ///
+ public static void Stop()
+ {
+ LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x20000 | 0x10000);
+ }
+
+ ///
+ /// Calculate BUS Speed using PIT
+ ///
+ private static uint EstimateBusSpeed()
+ {
+ LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x10000);
+ LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0x3);
+ LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0);
+
+ uint T0 = 0xFFFFFFFF; // -1
+ LocalAPIC.Out(0x380, T0);
+ Global.PIT.Wait(100); //100ms
+ LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x10000);
+
+ 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 c088298b5b..5aa42c7739 100644
--- a/source/Cosmos.HAL2/Global.cs
+++ b/source/Cosmos.HAL2/Global.cs
@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
-
+using System.Threading;
using Cosmos.Core;
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,35 @@ 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("Finding PCI Devices");
+ debugger.Send("PCI Devices");
+ PCI.Setup();
+
+ Console.WriteLine("Starting APIC");
+ debugger.Send("Local APIC Init");
+ LocalAPIC.Initialize();
+
+ Console.WriteLine("Starting PIT");
+ debugger.Send("PIT init");
+ PIT = new();
+
+ Console.WriteLine("Starting Processor Scheduler");
+ debugger.Send("Processor Scheduler");
+ Core.Processing.ProcessorScheduler.Initialize();
+
+ debugger.Send("Local APIC Timer Init");
+ ApicTimer.Initialize();
+ ApicTimer.Start();
+
+ 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
@@ -76,6 +98,7 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In
}
AHCI.InitDriver();
//EHCI.InitDriver();
+
if (InitNetwork)
{
debugger.Send("Network Devices Init");
@@ -104,6 +127,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) { }
+ }
+ }
+}