1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <phosphor-logging/elog-errors.hpp> 20 21 #include <array> 22 #include <string> 23 24 static constexpr const char* mdrDefaultFile = "/var/lib/smbios/smbios2"; 25 26 static constexpr uint16_t mdrSMBIOSSize = 32 * 1024; 27 28 constexpr uint16_t smbiosAgentId = 0x0101; 29 constexpr int firstAgentIndex = 1; 30 31 constexpr uint8_t maxDirEntries = 4; 32 constexpr uint32_t mdr2SMSize = 0x00100000; 33 constexpr uint32_t mdr2SMBaseAddress = 0x9FF00000; 34 35 constexpr uint8_t mdrDirVersion = 1; 36 constexpr uint8_t mdrTypeII = 2; 37 38 constexpr uint8_t mdr2Version = 2; 39 constexpr uint8_t smbiosAgentVersion = 1; 40 constexpr uint8_t smbiosDirVersion = 1; 41 42 constexpr uint32_t pageMask = 0xf000; 43 constexpr int smbiosDirIndex = 0; 44 45 constexpr uint32_t smbiosTableVersion = 15; 46 constexpr uint32_t smbiosTableTimestamp = 0x45464748; 47 constexpr uint32_t smbiosSMMemoryOffset = 0; 48 constexpr uint32_t smbiosSMMemorySize = 1024 * 1024; 49 constexpr uint32_t smbiosTableStorageSize = 64 * 1024; 50 constexpr uint32_t defaultTimeout = 2'000'000; // 2-seconds. 51 52 enum class MDR2SMBIOSStatusEnum 53 { 54 mdr2Init = 0, 55 mdr2Loaded = 1, 56 mdr2Updated = 2, 57 mdr2Updating = 3 58 }; 59 60 enum class MDR2DirLockEnum 61 { 62 mdr2DirUnlock = 0, 63 mdr2DirLock = 1 64 }; 65 66 enum class DirDataRequestEnum 67 { 68 dirDataNotRequested = 0x00, 69 dirDataRequested = 0x01 70 }; 71 72 enum class FlagStatus 73 { 74 flagIsInvalid = 0, 75 flagIsValid = 1, 76 flagIsLocked = 2 77 }; 78 79 typedef struct 80 { 81 uint8_t dataInfo[16]; 82 } DataIdStruct; 83 84 typedef struct 85 { 86 DataIdStruct id; 87 uint32_t size; 88 uint32_t dataSetSize; 89 uint8_t dataVersion; 90 uint32_t timestamp; 91 } Mdr2DirEntry; 92 93 typedef struct 94 { 95 Mdr2DirEntry common; 96 MDR2SMBIOSStatusEnum stage; 97 MDR2DirLockEnum lock; 98 uint16_t lockHandle; 99 uint32_t xferBuff; 100 uint32_t xferSize; 101 uint32_t maxDataSize; 102 uint8_t* dataStorage; 103 } Mdr2DirLocalStruct; 104 105 typedef struct 106 { 107 uint8_t agentVersion; 108 uint8_t dirVersion; 109 uint8_t dirEntries; 110 uint8_t status; // valid / locked / etc 111 uint8_t remoteDirVersion; 112 uint16_t sessionHandle; 113 Mdr2DirLocalStruct dir[maxDirEntries]; 114 } Mdr2DirStruct; 115 116 struct MDRSMBIOSHeader 117 { 118 uint8_t dirVer; 119 uint8_t mdrType; 120 uint32_t timestamp; 121 uint32_t dataSize; 122 } __attribute__((packed)); 123 124 typedef struct 125 { 126 uint8_t majorVersion; 127 uint8_t minorVersion; 128 } SMBIOSVersion; 129 130 struct EntryPointStructure21 131 { 132 uint32_t anchorString; 133 uint8_t epChecksum; 134 uint8_t epLength; 135 SMBIOSVersion smbiosVersion; 136 uint16_t maxStructSize; 137 uint8_t epRevision; 138 uint8_t formattedArea[5]; 139 uint8_t intermediateAnchorString[5]; 140 uint8_t intermediateChecksum; 141 uint16_t structTableLength; 142 uint32_t structTableAddress; 143 uint16_t noOfSmbiosStruct; 144 uint8_t smbiosBDCRevision; 145 } __attribute__((packed)); 146 147 struct EntryPointStructure30 148 { 149 uint8_t anchorString[5]; 150 uint8_t epChecksum; 151 uint8_t epLength; 152 SMBIOSVersion smbiosVersion; 153 uint8_t smbiosDocRev; 154 uint8_t epRevision; 155 uint8_t reserved; 156 uint32_t structTableMaxSize; 157 uint64_t structTableAddr; 158 } __attribute__((packed)); 159 160 struct StructureHeader 161 { 162 uint8_t type; 163 uint8_t length; 164 uint16_t handle; 165 } __attribute__((packed)); 166 167 static constexpr const char* cpuSuffix = "/chassis/motherboard/cpu"; 168 169 static constexpr const char* dimmSuffix = "/chassis/motherboard/dimm"; 170 171 static constexpr const char* pcieSuffix = "/chassis/motherboard/pcieslot"; 172 173 static constexpr const char* systemSuffix = "/chassis/motherboard/bios"; 174 175 static constexpr const char* tpmSuffix = "/chassis/motherboard/tpm"; 176 177 static constexpr const char* firmwarePath = "/xyz/openbmc_project/software"; 178 179 constexpr std::array<SMBIOSVersion, 8> supportedSMBIOSVersions{ 180 SMBIOSVersion{3, 0}, SMBIOSVersion{3, 2}, SMBIOSVersion{3, 3}, 181 SMBIOSVersion{3, 4}, SMBIOSVersion{3, 5}, SMBIOSVersion{3, 6}, 182 SMBIOSVersion{3, 7}, SMBIOSVersion{3, 8}}; 183 184 typedef enum 185 { 186 biosType = 0, 187 systemType = 1, 188 baseboardType = 2, 189 chassisType = 3, 190 processorsType = 4, 191 memoryControllerType = 5, 192 memoryModuleInformationType = 6, 193 cacheType = 7, 194 portConnectorType = 8, 195 systemSlots = 9, 196 onBoardDevicesType = 10, 197 oemStringsType = 11, 198 systemCconfigurationOptionsType = 12, 199 biosLanguageType = 13, 200 groupAssociatonsType = 14, 201 systemEventLogType = 15, 202 physicalMemoryArrayType = 16, 203 memoryDeviceType = 17, 204 systemPowerSupply = 39, 205 onboardDevicesExtended = 41, 206 tpmDeviceType = 43, 207 firmwareInventoryInformationType = 45, 208 } SmbiosType; 209 210 static constexpr uint8_t separateLen = 2; 211 212 static inline uint8_t* smbiosNextPtr(uint8_t* smbiosDataIn) 213 { 214 if (smbiosDataIn == nullptr) 215 { 216 return nullptr; 217 } 218 uint8_t* smbiosData = smbiosDataIn + *(smbiosDataIn + 1); 219 int len = 0; 220 while ((*smbiosData | *(smbiosData + 1)) != 0) 221 { 222 smbiosData++; 223 len++; 224 if (len >= mdrSMBIOSSize) // To avoid endless loop 225 { 226 return nullptr; 227 } 228 } 229 return smbiosData + separateLen; 230 } 231 232 // When first time run getSMBIOSTypePtr, need to send the RegionS[].regionData 233 // to smbiosDataIn 234 static inline uint8_t* getSMBIOSTypePtr(uint8_t* smbiosDataIn, uint8_t typeId, 235 size_t size = 0) 236 { 237 if (smbiosDataIn == nullptr) 238 { 239 return nullptr; 240 } 241 char* smbiosData = reinterpret_cast<char*>(smbiosDataIn); 242 while ((*smbiosData != '\0') || (*(smbiosData + 1) != '\0')) 243 { 244 uint32_t len = *(smbiosData + 1); 245 if (*smbiosData != typeId) 246 { 247 smbiosData += len; 248 while ((*smbiosData != '\0') || (*(smbiosData + 1) != '\0')) 249 { 250 smbiosData++; 251 len++; 252 if (len >= mdrSMBIOSSize) // To avoid endless loop 253 { 254 return nullptr; 255 } 256 } 257 smbiosData += separateLen; 258 continue; 259 } 260 if (len < size) 261 { 262 phosphor::logging::log<phosphor::logging::level::ERR>( 263 "Record size mismatch!"); 264 return nullptr; 265 } 266 return reinterpret_cast<uint8_t*>(smbiosData); 267 } 268 return nullptr; 269 } 270 271 static inline uint8_t* smbiosSkipEntryPoint(uint8_t* smbiosDataIn) 272 { 273 const std::string anchorString30 = "_SM3_"; 274 if (smbiosDataIn == nullptr) 275 { 276 return nullptr; 277 } 278 279 // Jump to starting address of the SMBIOS Structure Table from Entry Point 280 auto anchor = reinterpret_cast<const char*>(smbiosDataIn); 281 if (std::string_view(anchor, anchorString30.length()) 282 .compare(anchorString30) == 0) 283 { 284 auto epStructure = 285 reinterpret_cast<const EntryPointStructure30*>(smbiosDataIn); 286 if (epStructure->structTableAddr < mdrSMBIOSSize) 287 { 288 smbiosDataIn += epStructure->structTableAddr; 289 } 290 } 291 292 return smbiosDataIn; 293 } 294 295 static inline uint8_t* smbiosHandlePtr(uint8_t* smbiosDataIn, uint16_t handle) 296 { 297 auto ptr = smbiosSkipEntryPoint(smbiosDataIn); 298 struct StructureHeader* header; 299 while (ptr != nullptr) 300 { 301 header = reinterpret_cast<struct StructureHeader*>(ptr); 302 if (header->length < sizeof(StructureHeader)) 303 { 304 return nullptr; 305 } 306 307 if (header->handle == handle) 308 { 309 return ptr; 310 } 311 ptr = smbiosNextPtr(ptr); 312 } 313 return nullptr; 314 } 315 316 static inline std::string positionToString(uint8_t positionNum, 317 uint8_t structLen, uint8_t* dataIn) 318 { 319 if (dataIn == nullptr || positionNum == 0) 320 { 321 return ""; 322 } 323 uint16_t limit = mdrSMBIOSSize; // set a limit to avoid endless loop 324 325 char* target = reinterpret_cast<char*>(dataIn + structLen); 326 if (target == nullptr) 327 { 328 return ""; 329 } 330 for (uint8_t index = 1; index < positionNum; index++) 331 { 332 for (; *target != '\0'; target++) 333 { 334 limit--; 335 // When target = dataIn + structLen + limit, 336 // following target++ will be nullptr 337 if (limit < 1 || target == nullptr) 338 { 339 return ""; 340 } 341 } 342 target++; 343 if (target == nullptr || *target == '\0') 344 { 345 return ""; // 0x00 0x00 means end of the entry. 346 } 347 } 348 349 std::string result = target; 350 return result; 351 } 352