using System.Collections.Generic; namespace Cosmos.Core.SMBIOS { //This class contains the parser for the entry point table. //TODO: do checks for versions. public unsafe class SMBIOS { public static SMBIOSStructure BeginParseSMBIOS() { byte* memPtr = SMBIOS.SearchEntryPointTable(); EntryPointTable entry = new EntryPointTable(); //We dont return an address since we need to use a pointer that //its inside the table entry.Parse(memPtr); //entry.GetTableAddress(); SMBIOSStructure smbiosStructure = SMBIOS.ParseStructures(entry); smbiosStructure.EntryPointTable = entry; return smbiosStructure; } /// /// This fucntion parses the array of strings of the unformatted part of the structure /// Stops when found the end of the table. THE ADDRESS NEEDS TO BE RECOMPUTED. /// The start of the next table needs to be recomputed as the sum of the length of the parsed strings; /// NOTE: assumes that the start of the unformatted section will be provided /// /// Address in which we start searching /// Variable in which we will store the result /// Offset of the search (i.e, the number of position searched) public static string[] ParseStrings(byte* beginningAddress) { List stringList = new List(); var i = 0; //While we don't find the double null... while (beginningAddress[i] != '\0') { string parsedString = ""; //While we don't find the null that indicates the end of the string... while (beginningAddress[i] != '\0') { //Create new string appending chars parsedString = parsedString + ((char)beginningAddress[i]); i++; } stringList.Add(parsedString); i++; //Skip the first null or the null that indicates end of string } return stringList.ToArray(); } /// /// Recomputes the pointer after parsing the strings of the unformatted section. /// /// Address after parsing the formatted section /// Array of strings parsed from the unformatted section /// Starting address of the next table public static byte* RecomputePointer(byte* beginningAddress, string[] stringArray) { int charLength = 0; //sum of the length of the strings contained in stringArray foreach (var str in stringArray) charLength += str.Length; //The next address will be return beginningAddress + charLength + //The sum of the length of all the strings stringArray.Length + //The number of null bytes related to the strings 1; //The second null byte in the double null part } public static SMBIOSStructure ParseStructures(EntryPointTable entryPointTable) { SMBIOSStructure smbiosStructure = new SMBIOSStructure(); List cpuList = new List(); byte* currentAddress = entryPointTable.GetTableAddress(); DebugSMBIOS.DebugEntryPoint(entryPointTable); for (int i = 0; i < entryPointTable.NumberOfStructures; i++) { //We need to compare the type (which will be always the 0 fo current address) if (currentAddress[0] == SMBIOSTypes.BiosTable) { if (smbiosStructure.BiosInfo == null) { smbiosStructure.BiosInfo = new BIOSInfo(entryPointTable, currentAddress); currentAddress = smbiosStructure.BiosInfo.Parse(); DebugSMBIOS.DebugBIOSInfo(smbiosStructure.BiosInfo); } else { //If we fail skipping the table currentAddress = currentAddress + 1; Cosmos.Debug.Kernel.Debugger.DoSend("Skipping not bios table"); } continue; } if (currentAddress[0] == SMBIOSTypes.ProcessorTable) { CPUInfo cpuInfo = new CPUInfo(entryPointTable, currentAddress); currentAddress = cpuInfo.Parse(); smbiosStructure.CpuInfoList.Add(cpuInfo); DebugSMBIOS.DebugCPUInfo(cpuInfo); continue; } //In [1] we have the length of the formatted section. Cosmos.Debug.Kernel.Debugger.DoSend("Skipping table type: " + currentAddress[0] + " Length: " + currentAddress[1]); Cosmos.Debug.Kernel.Debugger.DoSend("Is 4?" + (currentAddress[0] == 4)); currentAddress = SkipTable(currentAddress[1], currentAddress); } return smbiosStructure; } /// /// Skip a table with length x /// We need the length since the table can contain double nulls inside the formatted section /// /// Length of the table to skip /// Address to search /// public static byte* SkipTable(int length, byte* beginningAddress) { int i; //Skip the formatted section for (i = 0; i < length; i++) ; //Skip the unformatted section (bunch of strings) for (; ; ) { //If we found the double null we finished the table if (beginningAddress[i] == 0 && beginningAddress[i + 1] == 0) { //The pointer will be situated under the first null //We sum 2 to skip this return beginningAddress + i + 2; } //We need to increment here. //If we increment before checking for double null it doesnt work //for tables without strings i++; } } /// /// This method searches the memory region so as to locate the /// "Entry Point Table" /// /// Pointer to the beggining of the table public static byte* SearchEntryPointTable() { string str = ""; byte* memPtr; int length, checksum; for (memPtr = (byte*)0xf0000; memPtr < (byte*)0x100000; memPtr += 16) { if (memPtr[0] == '_' && memPtr[1] == 'S' && memPtr[2] == 'M' && memPtr[3] == '_') { //TODO: do checksum /* length = memPtr[5]; checksum = 0; for (int i = 0; i < length; i++) { checksum += memPtr[i]; str += (char)memPtr[i]; } if (checksum == 0) */ return memPtr; } } return null; } } }