diff --git a/source/Cosmos.Core/GCImplementation.cs b/source/Cosmos.Core/GCImplementation.cs index 66b4ef5c05..f57ec7353a 100644 --- a/source/Cosmos.Core/GCImplementation.cs +++ b/source/Cosmos.Core/GCImplementation.cs @@ -99,6 +99,7 @@ public static unsafe void Init() memLength = 128 * 1024 * 1024; } RAT.Init(memPtr, (uint)memLength); + Paging.Init(); } /// /// Get the Pointer of any object needed for Free() diff --git a/source/Cosmos.Core/Paging.cs b/source/Cosmos.Core/Paging.cs new file mode 100644 index 0000000000..65b359bf95 --- /dev/null +++ b/source/Cosmos.Core/Paging.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Cosmos.Core.Memory; +using IL2CPU.API.Attribs; + +namespace Cosmos.Core +{ + public unsafe class Paging + { + internal static ulong* PageDirectoryPointerTable; + private static bool IsEnabled = false; + public static void Init() + { + if (IsEnabled) + { + return; + } + IsEnabled = true; + + var video = (byte*)0xB8000; + + // Setup page tables + video[0] = (byte)'!'; + video[1] = 0x0f; + + PageDirectoryPointerTable = (ulong*)new ManagedMemoryBlock(4 * sizeof(long), 0x20, true).Offset; + + // identity map kernel + for (ulong i = 0x2000000; i < 0x2500000; i += 0x200000) + { + Map(i, i, PageSize._2MB, PageFlags.ReadWrite); + } + + // identity map RAT + for (ulong i = (ulong)RAT.mRAT; i < (ulong)RAT.HeapEnd; i += 0x200000) + { + Map(i, i, PageSize._2MB, PageFlags.ReadWrite); + } + + // identity map console + Map(0xB8000, 0xB8000, PageSize._2MB, PageFlags.ReadWrite); + + // Enable paging + video[0] = (byte)'E'; + video[1] = 0x0f; + + DoEnable((uint)PageDirectoryPointerTable); + + // Print C for now as memory manager would need rework + video[0] = (byte)':'; + video[1] = 0x0f; + video[1] = (byte)')'; + video[2] = 0x0f; + } + private static ulong* GetNextLevel(ulong* topLevel, ulong index, bool allocate, ulong flags = 3) + { + if ((topLevel[index] & 1) != 0) + { + return (ulong*)((topLevel[index] & ~((ulong)0xFFF))); + } + + if (!allocate) + { + return null; + } + + var nextLevel = (ulong*)new ManagedMemoryBlock(512 * sizeof(ulong), 0x1000, true).Offset; + topLevel[index] = (ulong)nextLevel | flags; + return nextLevel; + } + public static void Map(ulong PhysicalAddress, ulong VirtualAddress, PageSize size, PageFlags flags) + { + var pdpteIndex = (VirtualAddress >> 30) & 0x03; // 2 bits for PDPT + var pdeIndex = (VirtualAddress >> 21) & 0x1FF; // 9 bits for PD + var pteIndex = (VirtualAddress >> 12) & 0x1FF; // 9 bits for PT + + var pdpte = GetNextLevel(PageDirectoryPointerTable, pdpteIndex, true, 1); + if (size == PageSize._2MB) + { + pdpte[pdeIndex] = (ulong)(PhysicalAddress | ((ulong)3 | (1 << 7))); + } + else if (size == PageSize._4KB) + { + var pde = GetNextLevel(pdpte, pdeIndex, true); + var pt = GetNextLevel(pde, pteIndex, true); + pt[pteIndex] = (ulong)(PhysicalAddress | (ulong)(3)); + } + } + + //plugged + internal static void DoEnable(uint addr) + { + throw new NotImplementedException(); + } + + internal static void RefreshPages() + { + throw new NotImplementedException(); + } + } + + public enum PageSize + { + _2MB, + _4KB, + } + [Flags] + public enum PageFlags + { + Present = 1 << 0, + ReadWrite = 1 << 1, + Supervisor = 1 << 2 + } +} \ No newline at end of file diff --git a/source/Cosmos.Core_Asm/EnablePagingAsm.cs b/source/Cosmos.Core_Asm/EnablePagingAsm.cs new file mode 100644 index 0000000000..5b492a2f79 --- /dev/null +++ b/source/Cosmos.Core_Asm/EnablePagingAsm.cs @@ -0,0 +1,92 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using IL2CPU.API.Attribs; +using XSharp; +using XSharp.Assembler; +using XSharp.Assembler.x86; + +namespace Cosmos.Core_Asm.Memory +{ + class EnablePagingAsm : AssemblerMethod + { + public override void AssembleNew(Assembler aAssembler, object aMethodInfo) + { + // Set PDPTR address to cr3 from addr argument + XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: 8); + XS.Set(XSRegisters.CR3, XSRegisters.EAX); + + // Enable PAE and PSE + new Mov + { + DestinationReg = RegistersEnum.EAX, + SourceReg = RegistersEnum.CR4 + }; + + new Or() + { + DestinationReg = RegistersEnum.EAX, + SourceValue = (1 << 5) | (1 << 4) + }; + + new Mov + { + DestinationReg = RegistersEnum.CR4, + SourceReg = RegistersEnum.EAX + }; + + //Set the paging bit + new Mov + { + DestinationReg = RegistersEnum.EAX, + SourceReg = RegistersEnum.CR0 + }; + + new Or() + { + DestinationReg = RegistersEnum.EAX, + SourceValue = 0x80000001 + }; + + new Mov + { + DestinationReg = RegistersEnum.CR0, + SourceReg = RegistersEnum.EAX + }; + } + } + class RefreshPagesAsm : AssemblerMethod + { + public override void AssembleNew(Assembler aAssembler, object aMethodInfo) + { + //reload CR3 + new Mov + { + DestinationReg = RegistersEnum.EAX, + SourceReg = RegistersEnum.CR3 + }; + new Mov + { + DestinationReg = RegistersEnum.CR3, + SourceReg = RegistersEnum.EAX + }; + } + } + [Plug(Target = typeof(Core.Paging))] + public class PagingImpl + { + [PlugMethod(Assembler = typeof(EnablePagingAsm))] + public static void DoEnable(uint addr) + { + throw new NotImplementedException(); + } + [PlugMethod(Assembler = typeof(RefreshPagesAsm))] + public static void RefreshPages() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file