xref: /openbmc/smbios-mdr/include/smbios_mdrv2.hpp (revision 6981b7ffb8a81bd1ea90c8deba8466accbe2693b)
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