blob: d940285d6b003939c6e89ce4c06160a5f827056b [file] [log] [blame]
Cheng C Yangeecaf822019-12-19 00:34:23 +08001/*
2// Copyright (c) 2019 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#include "mdrv2.hpp"
18
19#include <sys/mman.h>
20
21#include <fstream>
22#include <phosphor-logging/elog-errors.hpp>
23#include <sdbusplus/exception.hpp>
24#include <xyz/openbmc_project/Smbios/MDR_V2/error.hpp>
25
26namespace phosphor
27{
28namespace smbios
29{
30
31std::vector<uint8_t> MDR_V2::getDirectoryInformation(uint8_t dirIndex)
32{
Cheng C Yang608e52d2019-12-19 00:39:50 +080033 std::vector<uint8_t> responseDir;
34 if (dirIndex > smbiosDir.dirEntries)
35 {
36 responseDir.push_back(0);
37 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::
38 InvalidParameter();
39 }
40 responseDir.push_back(mdr2Version);
41 responseDir.push_back(smbiosDir.dirVersion);
42 uint8_t returnedEntries = smbiosDir.dirEntries - dirIndex;
43 responseDir.push_back(returnedEntries);
44 if ((dirIndex + returnedEntries) >= smbiosDir.dirEntries)
45 {
46 responseDir.push_back(0);
47 }
48 else
49 {
50 responseDir.push_back(smbiosDir.dirEntries - dirIndex -
51 returnedEntries);
52 }
53 for (uint8_t index = dirIndex; index < smbiosDir.dirEntries; index++)
54 {
55 for (uint8_t indexId = 0; indexId < sizeof(DataIdStruct); indexId++)
56 {
57 responseDir.push_back(
58 smbiosDir.dir[index].common.id.dataInfo[indexId]);
59 }
60 }
61
62 return responseDir;
Cheng C Yangeecaf822019-12-19 00:34:23 +080063}
64
65bool MDR_V2::smbiosIsAvailForUpdate(uint8_t index)
66{
67 bool ret = false;
68 if (index > maxDirEntries)
69 {
70 return ret;
71 }
72
73 switch (smbiosDir.dir[index].stage)
74 {
75 case MDR2SMBIOSStatusEnum::mdr2Updating:
76 ret = false;
77 break;
78
79 case MDR2SMBIOSStatusEnum::mdr2Init:
80 // This *looks* like there should be a break statement here,
81 // as the effects of the previous statement are a noop given
82 // the following code that this falls through to.
83 // We've elected not to change it, though, since it's been
84 // this way since the old generation, and it would affect
85 // the way the code functions.
86 // If it ain't broke, don't fix it.
87
88 case MDR2SMBIOSStatusEnum::mdr2Loaded:
89 case MDR2SMBIOSStatusEnum::mdr2Updated:
90 if (smbiosDir.dir[index].lock == MDR2DirLockEnum::mdr2DirLock)
91 {
92 ret = false;
93 }
94 else
95 {
96 ret = true;
97 }
98 break;
99
100 default:
101 break;
102 }
103
104 return ret;
105}
106
107std::vector<uint8_t> MDR_V2::getDataOffer()
108{
109 std::vector<uint8_t> offer(sizeof(DataIdStruct));
110 if (smbiosIsAvailForUpdate(0))
111 {
112 std::copy(smbiosDir.dir[0].common.id.dataInfo,
113 &smbiosDir.dir[0].common.id.dataInfo[16], offer.data());
114 }
115 else
116 {
117 phosphor::logging::log<phosphor::logging::level::ERR>(
118 "smbios is not ready for update");
119 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::
120 UpdateInProgress();
121 }
122 return offer;
123}
124
125inline uint8_t MDR_V2::smbiosValidFlag(uint8_t index)
126{
127 FlagStatus ret = FlagStatus::flagIsInvalid;
128 MDR2SMBIOSStatusEnum stage = smbiosDir.dir[index].stage;
129 MDR2DirLockEnum lock = smbiosDir.dir[index].lock;
130
131 switch (stage)
132 {
133 case MDR2SMBIOSStatusEnum::mdr2Loaded:
134 case MDR2SMBIOSStatusEnum::mdr2Updated:
135 if (lock == MDR2DirLockEnum::mdr2DirLock)
136 {
137 ret = FlagStatus::flagIsLocked; // locked
138 }
139 else
140 {
141 ret = FlagStatus::flagIsValid; // valid
142 }
143 break;
144
145 case MDR2SMBIOSStatusEnum::mdr2Updating:
146 case MDR2SMBIOSStatusEnum::mdr2Init:
147 ret = FlagStatus::flagIsInvalid; // invalid
148 break;
149
150 default:
151 break;
152 }
153
154 return static_cast<uint8_t>(ret);
155}
156
157std::vector<uint8_t> MDR_V2::getDataInformation(uint8_t idIndex)
158{
159 std::vector<uint8_t> responseInfo;
160 responseInfo.push_back(mdr2Version);
161
162 if (idIndex >= maxDirEntries)
163 {
164 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::
165 InvalidParameter();
166 }
167
168 for (uint8_t index = 0; index < sizeof(DataIdStruct); index++)
169 {
170 responseInfo.push_back(
171 smbiosDir.dir[idIndex].common.id.dataInfo[index]);
172 }
173 responseInfo.push_back(smbiosValidFlag(idIndex));
174 responseInfo.push_back(smbiosDir.dir[idIndex].common.size);
175 responseInfo.push_back(smbiosDir.dir[idIndex].common.dataVersion);
176 responseInfo.push_back(smbiosDir.dir[idIndex].common.timestamp);
177
178 return responseInfo;
179}
180
181bool MDR_V2::sendDirectoryInformation(uint8_t dirVersion, uint8_t dirIndex,
182 uint8_t returnedEntries,
183 uint8_t remainingEntries,
184 std::vector<uint8_t> dirEntry)
185{
Cheng C Yang608e52d2019-12-19 00:39:50 +0800186 bool teminate = false;
187 if ((dirIndex >= maxDirEntries) || (returnedEntries < 1))
188 {
189 phosphor::logging::log<phosphor::logging::level::ERR>(
190 "Send Dir info failed - input parameter invalid");
191 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::
192 InvalidParameter();
193 }
194 if (dirEntry.size() < sizeof(Mdr2DirEntry))
195 {
196 phosphor::logging::log<phosphor::logging::level::ERR>(
197 "Directory size invalid");
198 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::
199 InvalidParameter();
200 }
201 if (dirVersion == smbiosDir.dirVersion)
202 {
203 teminate = true;
204 }
205 else
206 {
207 if (remainingEntries > 0)
208 {
209 teminate = false;
210 }
211 else
212 {
213 teminate = true;
214 smbiosDir.dirVersion = dirVersion;
215 }
216 uint8_t idIndex = dirIndex;
217
218 uint8_t* pData = dirEntry.data();
219 if (pData == nullptr)
220 {
221 return false;
222 }
223 for (uint8_t index = 0; index < returnedEntries; index++)
224 {
225 auto data = reinterpret_cast<const Mdr2DirEntry*>(pData);
226 smbiosDir.dir[idIndex + index].common.dataVersion =
227 data->dataVersion;
228 std::copy(data->id.dataInfo,
229 data->id.dataInfo + sizeof(DataIdStruct),
230 smbiosDir.dir[idIndex + index].common.id.dataInfo);
231 smbiosDir.dir[idIndex + index].common.dataSetSize = data->size;
232 smbiosDir.dir[idIndex + index].common.timestamp = data->timestamp;
233 pData += sizeof(returnedEntries);
234 }
235 }
236 return teminate;
Cheng C Yangeecaf822019-12-19 00:34:23 +0800237}
238
Cheng C Yangec634252019-12-19 00:42:36 +0800239bool MDR_V2::readDataFromFlash(MDRSMBIOSHeader* mdrHdr, uint8_t* data)
240{
241 if (mdrHdr == nullptr)
242 {
243 phosphor::logging::log<phosphor::logging::level::ERR>(
244 "Read data from flash error - Invalid mdr header");
245 return false;
246 }
247 if (data == nullptr)
248 {
249 phosphor::logging::log<phosphor::logging::level::ERR>(
250 "Read data from flash error - Invalid data point");
251 return false;
252 }
253 std::ifstream smbiosFile(mdrType2File, std::ios_base::binary);
254 if (!smbiosFile.good())
255 {
256 phosphor::logging::log<phosphor::logging::level::ERR>(
257 "Read data from flash error - Open MDRV2 table file failure");
258 return false;
259 }
260 smbiosFile.clear();
261 smbiosFile.seekg(0, std::ios_base::end);
262 int fileLength = smbiosFile.tellg();
263 smbiosFile.seekg(0, std::ios_base::beg);
264 if (fileLength < sizeof(MDRSMBIOSHeader))
265 {
266 phosphor::logging::log<phosphor::logging::level::ERR>(
267 "MDR V2 file size is smaller than mdr header");
268 return false;
269 }
270 smbiosFile.read(reinterpret_cast<char*>(mdrHdr), sizeof(MDRSMBIOSHeader));
271 if (mdrHdr->dataSize > smbiosTableStorageSize)
272 {
273 phosphor::logging::log<phosphor::logging::level::ERR>(
274 "Data size out of limitation");
275 smbiosFile.close();
276 return false;
277 }
278 fileLength -= sizeof(MDRSMBIOSHeader);
279 if (fileLength < mdrHdr->dataSize)
280 {
281 smbiosFile.read(reinterpret_cast<char*>(data), fileLength);
282 }
283 else
284 {
285 smbiosFile.read(reinterpret_cast<char*>(data), mdrHdr->dataSize);
286 }
287 smbiosFile.close();
288 return true;
289}
290
Cheng C Yangeecaf822019-12-19 00:34:23 +0800291bool MDR_V2::sendDataInformation(uint8_t idIndex, uint8_t flag,
292 uint32_t dataLen, uint32_t dataVer,
293 uint32_t timeStamp)
294{
295 if (idIndex >= maxDirEntries)
296 {
297 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::
298 InvalidParameter();
299 }
300 int entryChanged = 0;
301 if (smbiosDir.dir[idIndex].common.dataSetSize != dataLen)
302 {
303 entryChanged++;
304 smbiosDir.dir[idIndex].common.dataSetSize = dataLen;
305 }
306
307 if (smbiosDir.dir[idIndex].common.dataVersion != dataVer)
308 {
309 entryChanged++;
310 smbiosDir.dir[idIndex].common.dataVersion = dataVer;
311 }
312
313 if (smbiosDir.dir[idIndex].common.timestamp != timeStamp)
314 {
315 entryChanged++;
316 smbiosDir.dir[idIndex].common.timestamp = timeStamp;
317 }
318 if (entryChanged == 0)
319 {
320 return false;
321 }
322 return true;
323}
324
325int MDR_V2::findIdIndex(std::vector<uint8_t> dataInfo)
326{
327 if (dataInfo.size() != sizeof(DataIdStruct))
328 {
329 phosphor::logging::log<phosphor::logging::level::ERR>(
330 "Length of dataInfo invalid");
331 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::
332 InvalidParameter();
333 }
334 std::array<uint8_t, 16> arrayDataInfo;
335
336 std::copy(dataInfo.begin(), dataInfo.end(), arrayDataInfo.begin());
337
338 for (int index = 0; index < smbiosDir.dirEntries; index++)
339 {
340 int info = 0;
341 for (; info < arrayDataInfo.size(); info++)
342 {
343 if (arrayDataInfo[info] !=
344 smbiosDir.dir[index].common.id.dataInfo[info])
345 {
346 break;
347 }
348 }
349 if (info == arrayDataInfo.size())
350 {
351 return index;
352 }
353 }
354 throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::InvalidId();
355}
356
357uint8_t MDR_V2::directoryEntries(uint8_t value)
358{
359 value = smbiosDir.dirEntries;
360 return sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V2::
361 directoryEntries(value);
362}
363
364bool MDR_V2::agentSynchronizeData()
365{
Cheng C Yangec634252019-12-19 00:42:36 +0800366 struct MDRSMBIOSHeader mdr2SMBIOS;
367 bool status = readDataFromFlash(&mdr2SMBIOS,
368 smbiosDir.dir[smbiosDirIndex].dataStorage);
369 if (!status)
370 {
371 phosphor::logging::log<phosphor::logging::level::ERR>(
372 "agent data sync failed - read data from flash failed");
373 return false;
374 }
375 else
376 {
377 smbiosDir.dir[smbiosDirIndex].common.dataVersion = mdr2SMBIOS.dirVer;
378 smbiosDir.dir[smbiosDirIndex].common.timestamp = mdr2SMBIOS.timestamp;
379 smbiosDir.dir[smbiosDirIndex].common.size = mdr2SMBIOS.dataSize;
380 smbiosDir.dir[smbiosDirIndex].stage = MDR2SMBIOSStatusEnum::mdr2Loaded;
381 smbiosDir.dir[smbiosDirIndex].lock = MDR2DirLockEnum::mdr2DirUnlock;
382 }
383 timer.stop();
384 return true;
Cheng C Yangeecaf822019-12-19 00:34:23 +0800385}
386
387std::vector<uint32_t> MDR_V2::synchronizeDirectoryCommonData(uint8_t idIndex,
388 uint32_t size)
389{
Cheng C Yangec634252019-12-19 00:42:36 +0800390 std::chrono::microseconds usec(
391 defaultTimeout); // default lock time out is 2s
392 std::vector<uint32_t> result;
393 smbiosDir.dir[idIndex].common.size = size;
394 result.push_back(smbiosDir.dir[idIndex].common.dataSetSize);
395 result.push_back(smbiosDir.dir[idIndex].common.dataVersion);
396 result.push_back(smbiosDir.dir[idIndex].common.timestamp);
397
398 timer.start(usec);
399 return result;
Cheng C Yangeecaf822019-12-19 00:34:23 +0800400}
401
402} // namespace smbios
403} // namespace phosphor