diff --git a/source/Cosmos.Core/Memory/RAT.cs b/source/Cosmos.Core/Memory/RAT.cs
index 4a649e72e..2e573876e 100644
--- a/source/Cosmos.Core/Memory/RAT.cs
+++ b/source/Cosmos.Core/Memory/RAT.cs
@@ -3,175 +3,301 @@ using System.Linq;
using System.Threading.Tasks;
using Native = System.UInt32;
-namespace Cosmos.Core.Memory {
- 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.
+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.
- static public class PageType {
- public const byte Empty = 0;
+ ///
+ /// PageType class. Used like a enum to define the type of the page.
+ ///
+ /// Only used to define page type.
+ static public class PageType
+ {
+ ///
+ /// Empty page.
+ ///
+ public const byte Empty = 0;
- // Data Types from 1, special meanings from 255 down.
- public const byte RAT = 1;
- public const byte HeapSmall = 2;
- public const byte HeapMedium = 3;
- public const byte HeapLarge = 4;
- // Code
- // Stack
- // Disk Cache
+ // Data Types from 1, special meanings from 255 down.
+ ///
+ /// RAT type page.
+ ///
+ public const byte RAT = 1;
+ ///
+ /// Small heap page.
+ ///
+ public const byte HeapSmall = 2;
+ ///
+ /// Medium heap page.
+ ///
+ public const byte HeapMedium = 3;
+ ///
+ /// Large heap page.
+ ///
+ public const byte HeapLarge = 4;
+ // Code
+ // Stack
+ // Disk Cache
- // Extension of previous page.
- public const byte Extension = 255;
- }
-
- // 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 Native PageSize = 4096;
-
- // Start of area usable for heap, and also start of heap.
- static private byte* mRamStart;
- // Size of heap
- static private Native mRamSize;
- // Calculated from mSize
- static private Native mPageCount;
-
- // RAT - RAM Allocation Table (Covers Data area only)
- // We need a pointer as the RAT can move around in future with dynamic RAM etc.
- static private byte* mRAT;
-
- static public void Init(byte* aStartPtr, Native aSize) {
- if ((Native)aStartPtr % PageSize != 0 && !Debug) {
- throw new Exception("RAM start must be page aligned.");
- }
-
- if (aSize % PageSize != 0) {
- throw new Exception("RAM size must be page aligned.");
- }
-
- mRamStart = aStartPtr;
- mRamSize = aSize;
- mPageCount = aSize / PageSize;
-
- // 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%
- Native xRatPageCount = (mPageCount - 1) / PageSize + 1;
- Native xRatPageBytes = xRatPageCount * PageSize;
- mRAT = mRamStart + mRamSize - xRatPageBytes;
- for (byte* p = mRAT; p < mRAT + xRatPageBytes - xRatPageCount; p++) {
- *p = PageType.Empty;
- }
- for (byte* p = mRAT + xRatPageBytes - xRatPageCount; p < mRAT + xRatPageBytes; p++) {
- *p = PageType.RAT;
- }
-
- Heap.Init();
- }
-
- static public Native GetPageCount(byte aType = 0) {
- Native xResult = 0;
- byte xType = 0; // Could us nullable type instead of this + xCounting, but this is faster.
- bool xCounting = false;
- for (byte* p = mRAT; p < mRAT + mPageCount; p++) {
- if (*p == aType) {
- xType = *p;
- xResult++;
- xCounting = true;
- } else if (xCounting) {
- if (xType == PageType.Extension) {
- xResult++;
- } else {
- xCounting = false;
- }
+ // Extension of previous page.
+ ///
+ /// Extension of pre-existing page.
+ ///
+ public const byte Extension = 255;
}
- }
- return xResult;
- }
- static public void* AllocBytes(byte aType, Native aBytes) {
- return AllocPages(aType, aBytes / PageSize);
- }
- static public void* AllocPages(byte aType, Native aPageCount = 1) {
- byte* xPos = null;
+ ///
+ /// Debug flag.
+ ///
+ /// Used to bypass certain checks that will fail during tests and debugging.
+ static internal bool Debug = false;
- // 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.
- Native xCount = 0;
- if (aPageCount == 1) {
- for (byte* p = mRAT; p < mRAT + mPageCount; p++) {
- if (*p == PageType.Empty) {
- xCount++;
- if (xCount == aPageCount) {
- xPos = p - xCount + 1;
- break;
+ ///
+ /// Native Intel page size.
+ ///
+ ///
+ /// - x86 Page Size: 4k, 2m (PAE only), 4m.
+ /// - x64 Page Size: 4k, 2m
+ ///
+ public const Native PageSize = 4096;
+
+ ///
+ /// Start of area usable for heap, and also start of heap.
+ ///
+ static private byte* mRamStart;
+ ///
+ /// Size of heap.
+ ///
+ static private Native mRamSize;
+ ///
+ /// Number of pages in the heap.
+ ///
+ /// Calculated from mSize.
+ static private Native mPageCount;
+
+ ///
+ /// Pointer to the RAT.
+ ///
+ /// Covers Data area only.
+ // We need a pointer as the RAT can move around in future with dynamic RAM etc.
+ static private 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.
+ ///
+ ///
+ static public void Init(byte* aStartPtr, Native aSize)
+ {
+ if ((Native)aStartPtr % PageSize != 0 && !Debug)
+ {
+ throw new Exception("RAM start must be page aligned.");
}
- } else {
- xCount = 0;
- }
- }
- } 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 + mPageCount - 1; p >= mRAT; p--) {
- if (*p == PageType.Empty) {
- xCount++;
- if (xCount == aPageCount) {
- xPos = p;
- break;
+
+ if (aSize % PageSize != 0)
+ {
+ throw new Exception("RAM size must be page aligned.");
}
- } else {
- xCount = 0;
- }
+
+ mRamStart = aStartPtr;
+ mRamSize = aSize;
+ mPageCount = aSize / PageSize;
+
+ // 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%
+ Native xRatPageCount = (mPageCount - 1) / PageSize + 1;
+ Native xRatPageBytes = xRatPageCount * PageSize;
+ mRAT = mRamStart + mRamSize - xRatPageBytes;
+ for (byte* p = mRAT; p < mRAT + xRatPageBytes - xRatPageCount; p++)
+ {
+ *p = PageType.Empty;
+ }
+ for (byte* p = mRAT + xRatPageBytes - xRatPageCount; p < mRAT + xRatPageBytes; p++)
+ {
+ *p = PageType.RAT;
+ }
+
+ Heap.Init();
}
- }
- // If we found enough space, mark it as used.
- if (xPos != null) {
- byte* xResult = mRamStart + (xPos - mRAT) * PageSize;
- *xPos = aType;
- for (byte* p = xPos + 1; p < xPos + xCount; p++) {
- *p = PageType.Extension;
+ ///
+ /// Get page count.
+ ///
+ /// A page type to count.
+ /// Native value.
+ static public Native GetPageCount(byte aType = 0)
+ {
+ Native xResult = 0;
+ byte xType = 0; // Could us nullable type instead of this + xCounting, but this is faster.
+ bool xCounting = false;
+ for (byte* p = mRAT; p < mRAT + mPageCount; p++)
+ {
+ if (*p == aType)
+ {
+ xType = *p;
+ xResult++;
+ xCounting = true;
+ }
+ else if (xCounting)
+ {
+ if (xType == PageType.Extension)
+ {
+ xResult++;
+ }
+ else
+ {
+ xCounting = false;
+ }
+ }
+ }
+ return xResult;
}
- return xResult;
- }
- return null;
- }
-
- static public Native GetFirstRAT(void* aPtr) {
- var xPos = (Native)((byte*)aPtr - mRamStart) / RAT.PageSize;
- // See note about when mRAT = 0 in Alloc.
- for (byte* p = mRAT + xPos; p >= mRAT; p--) {
- if (*p != PageType.Extension) {
- return (Native)(p - mRAT);
+ ///
+ /// Alloc a block with a given type and size.
+ ///
+ /// A type of block to alloc.
+ /// Number of bytes to alloc.
+ /// A pointer to the first page on success, null on failure.
+ static public void* AllocBytes(byte aType, Native aBytes)
+ {
+ return AllocPages(aType, aBytes / PageSize);
}
- }
- throw new Exception("Page type not found. Likely RAT is rotten.");
- }
- static public byte GetPageType(void* aPtr) {
- return mRAT[GetFirstRAT(aPtr)];
- }
+ ///
+ /// 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.
+ static public void* AllocPages(byte aType, Native aPageCount = 1)
+ {
+ byte* xPos = null;
- static public void Free(Native aPageIdx) {
- byte* p = mRAT + aPageIdx;
- *p = PageType.Empty;
- for (; p < mRAT + mPageCount; p++) {
- if (*p != PageType.Extension) {
- break;
+ // 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.
+ Native xCount = 0;
+ if (aPageCount == 1)
+ {
+ for (byte* p = mRAT; p < mRAT + mPageCount; p++)
+ {
+ if (*p == PageType.Empty)
+ {
+ xCount++;
+ if (xCount == aPageCount)
+ {
+ xPos = p - xCount + 1;
+ break;
+ }
+ }
+ else
+ {
+ xCount = 0;
+ }
+ }
+ }
+ 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 + mPageCount - 1; p >= mRAT; p--)
+ {
+ if (*p == PageType.Empty)
+ {
+ xCount++;
+ if (xCount == aPageCount)
+ {
+ xPos = p;
+ break;
+ }
+ }
+ else
+ {
+ xCount = 0;
+ }
+ }
+ }
+
+ // If we found enough space, mark it as used.
+ if (xPos != null)
+ {
+ byte* xResult = mRamStart + (xPos - mRAT) * PageSize;
+ *xPos = aType;
+ for (byte* p = xPos + 1; p < xPos + xCount; p++)
+ {
+ *p = PageType.Extension;
+ }
+ return xResult;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Get the first RAT address.
+ ///
+ /// A pointer to the block.
+ /// Native value.
+ /// Thrown if page type is not found.
+ static public Native GetFirstRAT(void* aPtr)
+ {
+ var xPos = (Native)((byte*)aPtr - mRamStart) / RAT.PageSize;
+ // See note about when mRAT = 0 in Alloc.
+ for (byte* p = mRAT + xPos; p >= mRAT; p--)
+ {
+ if (*p != PageType.Extension)
+ {
+ return (Native)(p - mRAT);
+ }
+ }
+ throw new Exception("Page type not found. Likely RAT is rotten.");
+ }
+
+ ///
+ /// Get the page type pointed by a pointer.
+ ///
+ /// A pointer to the page to get the type of.
+ /// byte value.
+ /// Thrown if page type is not found.
+ static public byte GetPageType(void* aPtr)
+ {
+ return mRAT[GetFirstRAT(aPtr)];
+ }
+
+ ///
+ /// Free page.
+ ///
+ /// A index to the page to be freed.
+ static public void Free(Native aPageIdx)
+ {
+ byte* p = mRAT + aPageIdx;
+ *p = PageType.Empty;
+ for (; p < mRAT + mPageCount; p++)
+ {
+ if (*p != PageType.Extension)
+ {
+ break;
+ }
+ *p = PageType.Empty;
+ }
}
- *p = PageType.Empty;
- }
}
- }
}