//#define COSMOSDEBUG using System; using System.Collections.Generic; using System.Runtime.InteropServices; using IL2CPU.API.Attribs; namespace Cosmos.Core { // Non hardware class, only used by core and hardware drivers for ports etc. /// /// CPU class. Non hardware class, only used by core and hardware drivers for ports etc. /// public class CPU { // Amount of RAM in MB's. // needs to be static, as Heap needs it before we can instantiate objects /// /// Get amount of RAM in MB's. Plugged. /// [PlugMethod(PlugRequired = true)] public static uint GetAmountOfRAM() => throw null; // needs to be static, as Heap needs it before we can instantiate objects /// /// Get end of the kernel. Plugged. /// [PlugMethod(PlugRequired = true)] public static uint GetEndOfKernel() => throw null; /// /// Update IDT. Plugged. /// [PlugMethod(PlugRequired = true)] public void UpdateIDT(bool aEnableInterruptsImmediately) => throw null; /// /// Init float. Plugged. /// [PlugMethod(PlugRequired = true)] public void InitFloat() => throw null; /// /// Init SSE. Plugged. /// [PlugMethod(PlugRequired = true)] public void InitSSE() => throw null; /// /// Zero fill. Plugged. /// [PlugMethod(PlugRequired = true)] public static void ZeroFill(uint aStartAddress, uint aLength) => throw null; /// /// Halt the CPU. Plugged. /// [PlugMethod(PlugRequired = true)] public void Halt() => throw null; /// /// Reboot the CPU. /// public void Reboot() { // Disable all interrupts DisableInterrupts(); var myPort = new IOPort(0x64); while ((myPort.Byte & 0x02) != 0) { } myPort.Byte = 0xFE; Halt(); // If it didn't work, Halt the CPU } /// /// Enable interrupts. Plugged. /// [PlugMethod(PlugRequired = true)] private static void DoEnableInterrupts() => throw null; /// /// Disable interrupts. Plugged. /// [PlugMethod(PlugRequired = true)] private static void DoDisableInterrupts() => throw null; /// /// Check if interrupts enabled. /// [AsmMarker(AsmMarker.Type.Processor_IntsEnabled)] public static bool mInterruptsEnabled; /// /// Enable interrupts. /// public static void EnableInterrupts() { mInterruptsEnabled = true; DoEnableInterrupts(); } /// /// Returns if the interrupts were actually enabled. /// /// bool value. public static bool DisableInterrupts() { DoDisableInterrupts(); var xResult = mInterruptsEnabled; mInterruptsEnabled = false; return xResult; } /// /// Get CPU vendor name. /// /// string value. /// Thrown on fatal error, contact support. /// Thrown if can not read CPU vendor name. public static string GetCPUVendorName() { if (CanReadCPUID() != 0) { int eax = 0; int ebx = 0; int ecx = 0; int edx = 0; ReadCPUID(0, ref eax, ref ebx, ref ecx, ref edx); // 0 is vendor name string s = ""; s += (char)(ebx & 0xff); s += (char)((ebx >> 8) & 0xff); s += (char)((ebx >> 16) & 0xff); s += (char)(ebx >> 24); s += (char)((edx) & 0xff); s += (char)((edx >> 8) & 0xff); s += (char)((edx >> 16) & 0xff); s += (char)(edx >> 24); s += (char)((ecx) & 0xff); s += (char)((ecx >> 8) & 0xff); s += (char)((ecx >> 16) & 0xff); s += (char)(ecx >> 24); return s; } throw new NotSupportedException(); } /// /// Get CPU up time. /// /// ulong value. /// Thrown on fatal error, contact support. public static ulong GetCPUUptime() { // TODO Divide by cpu clock speed return ReadTimestampCounter(); } /// /// Get CPU cycle speed. /// /// long value. /// Thrown on fatal error, contact support. /// Thrown if can not read CPU ID. public static long GetCPUCycleSpeed() { if (CanReadCPUID() != 0) { // See https://c9x.me/x86/html/file_module_x86_id_45.html int eax = 0; int ebx = 0; int ecx = 0; int edx = 0; string s = ""; for (uint i = 0; i < 3; i++) { ReadCPUID(0x80000002 + i, ref eax, ref ebx, ref ecx, ref edx); s += (char)(ebx % 256); s += (char)((ebx >> 8) % 256); s += (char)((ebx >> 16) % 256); s += (char)((ebx >> 24) % 256); s += (char)(edx % 256); s += (char)((edx >> 8) % 256); s += (char)((edx >> 16) % 256); s += (char)((edx >> 24) % 256); s += (char)(ecx % 256); s += (char)((ecx >> 8) % 256); s += (char)((ecx >> 16) % 256); s += (char)((ecx >> 24) % 256); } var _words = new List(); string curr = ""; for (int i = 0; i < s.Length; i++) { if (s[i] == ' ' || (byte)s[i] == 0) { if (curr != "") { _words.Add(curr); } curr = ""; } else { curr += s[i]; } } _words.Add(curr); string[] words = _words.ToArray(); string[] w = new string[words.Length]; for (int i = 0; i < words.Length; i++) { w[i] = words[words.Length - i - 1]; } words = w; double multiplier = 0; double value = 0; for (int i = 0; i < words.Length; i++) { if (words[i] == "MHz") { multiplier = 10e6; break; } else if (words[i] == "GHz") { multiplier = 10e9; break; } else if (words[i] == "THz") { multiplier = 10e12; break; } else if (value == 0) { Double.TryParse(words[i], out value); } } value *= multiplier; return (long)value; } throw new NotSupportedException(); } /// /// Get CPU cycle speed. /// /// long value. /// Thrown on fatal error, contact support. /// Thrown if can not read CPU ID. public static string GetCPUBrandString() { if (CanReadCPUID() != 0) { // See https://c9x.me/x86/html/file_module_x86_id_45.html int eax = 0; int ebx = 0; int ecx = 0; int edx = 0; int[] s = new int[64]; string rs = ""; for (uint i = 0; i < 3; i++) { ReadCPUID(0x80000002 + i, ref eax, ref ebx, ref ecx, ref edx); s[(i * 16) + 0] = (eax % 256); s[(i * 16) + 1] = ((eax >> 8) % 256); s[(i * 16) + 2] = ((eax >> 16) % 256); s[(i * 16) + 3] = ((eax >> 24) % 256); s[(i * 16) + 4] = (ebx % 256); s[(i * 16) + 5] = ((ebx >> 8) % 256); s[(i * 16) + 6] = ((ebx >> 16) % 256); s[(i * 16) + 7] = ((ebx >> 24) % 256); s[(i * 16) + 8] = (ecx % 256); s[(i * 16) + 9] = ((ecx >> 8) % 256); s[(i * 16) + 10] = ((ecx >> 16) % 256); s[(i * 16) + 11] = ((ecx >> 24) % 256); s[(i * 16) + 12] = (edx % 256); s[(i * 16) + 13] = ((edx >> 8) % 256); s[(i * 16) + 14] = ((edx >> 16) % 256); s[(i * 16) + 15] = ((edx >> 24) % 256); } for (int i = 0; i < s.Length; i++) { if (s[i] == 0x00) { continue; } rs += (char)s[i]; } if (!(rs == "")) { return rs; } else { throw new NotSupportedException(); } } throw new NotSupportedException(); } /// /// Check if can read CPU ID. Plugged. /// /// non-zero if can read. /// Thrown on fatal error, contact support. public static int CanReadCPUID() => throw new NotImplementedException(); /// /// Read CPU ID. Plugged. /// /// type. /// eax. /// ebx. /// ecx. /// edx. /// Thrown on fatal error, contact support. public static void ReadCPUID(uint type, ref int eax, ref int ebx, ref int ecx, ref int edx) => throw new NotImplementedException(); /// /// Read timestamp counter. Plugged. /// /// ulong value. /// Thrown on fatal error, contact support. internal static ulong ReadTimestampCounter() => throw new NotImplementedException(); /// /// Read from mode specific register. Plugged. /// /// ulong value. /// Thrown on fatal error, contact support. internal static ulong ReadFromModelSpecificRegister() => throw new NotImplementedException(); /// /// Checks if Multiboot returned a memory map /// /// public static unsafe bool MemoryMapExists() { return (Bootstrap.MultibootHeader->Flags & 1 << 6) == 64; } /// /// Get the Memory Map Information from Multiboot /// /// Returns an array of MemoryMaps containing the Multiboot Memory Map information. The array may have empty values at the end. public static unsafe MemoryMap[] GetMemoryMap() { if (!MemoryMapExists()) { throw new Exception("No Memory Map was returned by Multiboot"); } var rawMap = new RawMemoryMap[64]; var currentMap = (RawMemoryMap*)Bootstrap.MultibootHeader->memMapAddress; int counter = 0; while ((uint)currentMap < (Bootstrap.MultibootHeader->memMapAddress + Bootstrap.MultibootHeader->memMapLength) && counter < 64) { rawMap[counter++] = *currentMap; currentMap = (RawMemoryMap*)((uint*)currentMap + ((currentMap->Size + 4 )>> 2)); //The size is in bits, not bytes if (currentMap->Size == 0) { break; } } if (counter >= 64) { throw new Exception("Memory Map returned too many segments"); } var entireMap = new MemoryMap[counter]; for (int i = 0; i < counter; i++) { var rawMemoryMap = rawMap[i]; entireMap[i] = new MemoryMap { Address = (ulong)rawMemoryMap.HighBaseAddr << 32 | rawMemoryMap.LowBaseAddr, Length = (ulong)rawMemoryMap.HighLength << 32 | rawMemoryMap.LowLength, Type = rawMemoryMap.Type }; } return entireMap; } } public class MemoryMap { /// /// Base Address of the memory region /// public ulong Address; /// /// Length in bytes of the region /// public ulong Length; /// /// Type of RAM in region. 1 is available. 3 is for ACPI. All other is unavailable /// public uint Type; } [StructLayout(LayoutKind.Explicit, Size = 24)] public struct RawMemoryMap { /// /// Size of this entry /// [FieldOffset(0)] public uint Size; /// /// Low 32 bits of the base address /// [FieldOffset(4)] public uint LowBaseAddr; /// /// High 32 bits of the base address /// [FieldOffset(8)] public uint HighBaseAddr; /// /// Low 32 bits of the length of memory block in bytes /// [FieldOffset(12)] public uint LowLength; /// /// High 32 bits of the length of memory block in bytes /// [FieldOffset(16)] public uint HighLength; /// /// Type of memory area, 1 if usable RAM, everything else unusable. /// [FieldOffset(20)] public uint Type; } }