blob: 548cd61bf425d45fcfb7650758e6100a90c3308a [file] [log] [blame]
Vernon Mauery52ce6622019-05-22 09:19:46 -07001#include <ipmid/api.h>
2#include <openssl/evp.h>
3#include <openssl/sha.h>
4#include <sys/mman.h>
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8
9#include <boost/algorithm/string.hpp>
AppaRao Puli28972062019-11-11 02:04:45 +053010#include <boost/container/flat_map.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070011#include <boost/process/child.hpp>
12#include <boost/uuid/random_generator.hpp>
13#include <boost/uuid/uuid_io.hpp>
14#include <chrono>
15#include <commandutils.hpp>
16#include <cstdint>
17#include <filesystem>
18#include <fstream>
19#include <iostream>
anil kumar appana6c7d9382019-05-31 14:33:13 +000020#include <ipmid/api.hpp>
AppaRao Puli37fde6b2019-10-25 16:37:50 +053021#include <ipmid/utils.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070022#include <map>
AppaRao Puli28972062019-11-11 02:04:45 +053023#include <phosphor-logging/log.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070024#include <random>
25#include <sdbusplus/bus.hpp>
26#include <sdbusplus/bus/match.hpp>
27#include <sdbusplus/server/object.hpp>
28#include <sdbusplus/timer.hpp>
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +053029#ifdef INTEL_PFR_ENABLED
30#include <spiDev.hpp>
31#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -070032
AppaRao Puli28972062019-11-11 02:04:45 +053033static constexpr bool DEBUG = true;
34static void registerFirmwareFunctions() __attribute__((constructor));
35
AppaRao Puli37fde6b2019-10-25 16:37:50 +053036namespace ipmi
37{
38namespace firmware
39{
40constexpr Cmd cmdGetFwVersionInfo = 0x20;
AppaRao Puli28972062019-11-11 02:04:45 +053041constexpr Cmd cmdGetFwSecurityVersionInfo = 0x21;
42constexpr Cmd cmdGetFwUpdateChannelInfo = 0x22;
43constexpr Cmd cmdGetBmcExecutionContext = 0x23;
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +053044constexpr Cmd cmdFwGetRootCertData = 0x25;
AppaRao Puli28972062019-11-11 02:04:45 +053045constexpr Cmd cmdGetFwUpdateRandomNumber = 0x26;
46constexpr Cmd cmdSetFirmwareUpdateMode = 0x27;
47constexpr Cmd cmdExitFirmwareUpdateMode = 0x28;
48constexpr Cmd cmdGetSetFwUpdateControl = 0x29;
49constexpr Cmd cmdGetFirmwareUpdateStatus = 0x2A;
50constexpr Cmd cmdSetFirmwareUpdateOptions = 0x2B;
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +053051constexpr Cmd cmdFwImageWriteData = 0x2c;
AppaRao Puli37fde6b2019-10-25 16:37:50 +053052} // namespace firmware
53} // namespace ipmi
54
AppaRao Puli28972062019-11-11 02:04:45 +053055namespace ipmi
56{
57// Custom completion codes
58constexpr Cc ccUsbAttachOrDetachFailed = 0x80;
59constexpr Cc ccNotSupportedInPresentState = 0xD5;
60
61static inline auto responseUsbAttachOrDetachFailed()
62{
63 return response(ccUsbAttachOrDetachFailed);
64}
65static inline auto responseNotSupportedInPresentState()
66{
67 return response(ccNotSupportedInPresentState);
68}
69} // namespace ipmi
70
71static constexpr const char *bmcStateIntf = "xyz.openbmc_project.State.BMC";
72static constexpr const char *bmcStatePath = "/xyz/openbmc_project/state/bmc0";
73static constexpr const char *bmcStateReady =
74 "xyz.openbmc_project.State.BMC.BMCState.Ready";
75static constexpr const char *bmcStateUpdateInProgress =
76 "xyz.openbmc_project.State.BMC.BMCState.UpdateInProgress";
77
78static constexpr char firmwareBufferFile[] = "/tmp/fw-download.bin";
79static std::chrono::steady_clock::time_point fwRandomNumGenTs;
80static constexpr auto fwRandomNumExpirySeconds = std::chrono::seconds(30);
81static constexpr size_t fwRandomNumLength = 8;
82static std::array<uint8_t, fwRandomNumLength> fwRandomNum;
83constexpr char usbCtrlPath[] = "/usr/bin/usb-ctrl";
84constexpr char fwUpdateMountPoint[] = "/tmp/usb-fwupd.mnt";
85constexpr char fwUpdateUsbVolImage[] = "/tmp/usb-fwupd.img";
86constexpr char fwUpdateUSBDevName[] = "fw-usb-mass-storage-dev";
87constexpr size_t fwPathMaxLength = 255;
88
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +053089#ifdef INTEL_PFR_ENABLED
90uint32_t imgLength = 0;
91uint32_t imgType = 0;
92bool block0Mapped = false;
93static constexpr uint32_t perBlock0MagicNum = 0xB6EAFD19;
AppaRao Puli37fde6b2019-10-25 16:37:50 +053094
AppaRao Puli28972062019-11-11 02:04:45 +053095static constexpr const char *bmcActivePfmMTDDev = "/dev/mtd/pfm";
96static constexpr const char *bmcRecoveryImgMTDDev = "/dev/mtd/rc-image";
97static constexpr size_t pfmBaseOffsetInImage = 0x400;
98static constexpr size_t rootkeyOffsetInPfm = 0xA0;
99static constexpr size_t cskKeyOffsetInPfm = 0x124;
100static constexpr size_t cskSignatureOffsetInPfm = 0x19c;
101static constexpr size_t certKeyLen = 96;
102static constexpr size_t cskSignatureLen = 96;
103
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530104static constexpr const char *versionIntf =
105 "xyz.openbmc_project.Software.Version";
106
AppaRao Puli28972062019-11-11 02:04:45 +0530107enum class FwGetRootCertDataTag : uint8_t
108{
109 activeRootKey = 1,
110 recoveryRootKey,
111 activeCSK,
112 recoveryCSK,
113};
114
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530115enum class FWDeviceIDTag : uint8_t
116{
117 bmcActiveImage = 1,
118 bmcRecoveryImage,
119};
120
121const static boost::container::flat_map<FWDeviceIDTag, const char *>
122 fwVersionIdMap{{FWDeviceIDTag::bmcActiveImage,
123 "/xyz/openbmc_project/software/bmc_active"},
124 {FWDeviceIDTag::bmcRecoveryImage,
125 "/xyz/openbmc_project/software/bmc_recovery"}};
AppaRao Puli28972062019-11-11 02:04:45 +0530126#endif // INTEL_PFR_ENABLED
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530127
AppaRao Puli28972062019-11-11 02:04:45 +0530128enum class ChannelIdTag : uint8_t
129{
130 reserved = 0,
131 kcs = 1,
132 ipmb = 2,
133 rmcpPlus = 3
134};
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +0530135
AppaRao Puli28972062019-11-11 02:04:45 +0530136enum class BmcExecutionContext : uint8_t
137{
138 reserved = 0,
139 linuxOs = 0x10,
140 bootLoader = 0x11,
141};
AppaRao Puli09a83142019-11-23 02:46:06 +0530142
AppaRao Puli28972062019-11-11 02:04:45 +0530143enum class FwUpdateCtrlReq : uint8_t
144{
145 getCurrentControlStatus = 0x00,
146 imageTransferStart = 0x01,
147 imageTransferComplete = 0x02,
148 imageTransferAbort = 0x03,
149 setFirmwareFilename = 0x04,
150 attachUsbDevice = 0x05,
151 detachUsbDevice = 0x06
152};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700153
154constexpr std::size_t operator""_MB(unsigned long long v)
155{
156 return 1024u * 1024u * v;
157}
AppaRao Puli28972062019-11-11 02:04:45 +0530158static constexpr size_t maxFirmwareImageSize = 32_MB;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700159
AppaRao Puli28972062019-11-11 02:04:45 +0530160static bool localDownloadInProgress(void)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700161{
162 struct stat sb;
AppaRao Puli28972062019-11-11 02:04:45 +0530163 if (stat(firmwareBufferFile, &sb) < 0)
164 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700165 return false;
AppaRao Puli28972062019-11-11 02:04:45 +0530166 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700167 return true;
168}
169
AppaRao Puli28972062019-11-11 02:04:45 +0530170class TransferHashCheck
171{
172 public:
173 enum class HashCheck : uint8_t
174 {
175 notRequested = 0,
176 requested,
177 sha2Success,
178 sha2Failed = 0xe2,
179 };
180
181 protected:
182 EVP_MD_CTX *ctx;
183 std::vector<uint8_t> expectedHash;
184 enum HashCheck check;
185 bool started;
186
187 public:
188 TransferHashCheck() : check(HashCheck::notRequested), started(false)
189 {
190 }
191 ~TransferHashCheck()
192 {
193 if (ctx)
194 {
195 EVP_MD_CTX_destroy(ctx);
196 ctx = NULL;
197 }
198 }
199 void init(const std::vector<uint8_t> &expected)
200 {
201 expectedHash = expected;
202 check = HashCheck::requested;
203 ctx = EVP_MD_CTX_create();
204 EVP_DigestInit(ctx, EVP_sha256());
205 }
206 void hash(const std::vector<uint8_t> &data)
207 {
208 if (!started)
209 {
210 started = true;
211 }
212 EVP_DigestUpdate(ctx, data.data(), data.size());
213 }
214 void clear()
215 {
216 // if not started, nothing to clear
217 if (started)
218 {
219 if (ctx)
220 {
221 EVP_MD_CTX_destroy(ctx);
222 }
223 if (check != HashCheck::notRequested)
224 {
225 check = HashCheck::requested;
226 }
227 ctx = EVP_MD_CTX_create();
228 EVP_DigestInit(ctx, EVP_sha256());
229 }
230 }
231 enum HashCheck verify()
232 {
233 if (check == HashCheck::requested)
234 {
235 unsigned int len = 0;
236 std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
237 EVP_DigestFinal(ctx, digest.data(), &len);
238 if (digest == expectedHash)
239 {
240 phosphor::logging::log<phosphor::logging::level::INFO>(
241 "Transfer sha2 verify passed.");
242 check = HashCheck::sha2Success;
243 }
244 else
245 {
246 phosphor::logging::log<phosphor::logging::level::ERR>(
247 "Transfer sha2 verify failed.");
248 check = HashCheck::sha2Failed;
249 }
250 }
251 return check;
252 }
253 uint8_t status() const
254 {
255 return static_cast<uint8_t>(check);
256 }
257};
258
259class MappedFile
260{
261 public:
262 MappedFile(const std::string &fname) : addr(nullptr), fsize(0)
263 {
264 std::error_code ec;
265 size_t sz = std::filesystem::file_size(fname, ec);
266 int fd = open(fname.c_str(), O_RDONLY);
267 if (!ec || fd < 0)
268 {
269 return;
270 }
271 void *tmp = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
272 close(fd);
273 if (tmp == MAP_FAILED)
274 {
275 return;
276 }
277 addr = tmp;
278 fsize = sz;
279 }
280
281 ~MappedFile()
282 {
283 if (addr)
284 {
285 munmap(addr, fsize);
286 }
287 }
288 const uint8_t *data() const
289 {
290 return static_cast<const uint8_t *>(addr);
291 }
292 size_t size() const
293 {
294 return fsize;
295 }
296
297 private:
298 size_t fsize;
299 void *addr;
300};
301
302class FwUpdateStatusCache
Vernon Mauery52ce6622019-05-22 09:19:46 -0700303{
304 public:
305 enum
306 {
AppaRao Puli28972062019-11-11 02:04:45 +0530307 fwStateInit = 0,
308 fwStateIdle,
309 fwStateDownload,
310 fwStateVerify,
311 fwStateProgram,
312 fwStateUpdateSuccess,
313 fwStateError = 0x0f,
314 fwStateAcCycleRequired = 0x83,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700315 };
AppaRao Puli28972062019-11-11 02:04:45 +0530316 uint8_t getState()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700317 {
AppaRao Puli28972062019-11-11 02:04:45 +0530318 if ((fwUpdateState == fwStateIdle || fwUpdateState == fwStateInit) &&
319 localDownloadInProgress())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700320 {
AppaRao Puli28972062019-11-11 02:04:45 +0530321 fwUpdateState = fwStateDownload;
322 progressPercent = 0;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700323 }
AppaRao Puli28972062019-11-11 02:04:45 +0530324 return fwUpdateState;
325 }
326 void resetStatusCache()
327 {
328 unlink(firmwareBufferFile);
329 }
330 void setState(const uint8_t state)
331 {
332 switch (state)
333 {
334 case fwStateInit:
335 case fwStateIdle:
336 case fwStateError:
337 resetStatusCache();
338 break;
339 case fwStateDownload:
340 case fwStateVerify:
341 case fwStateProgram:
342 case fwStateUpdateSuccess:
343 break;
344 default:
345 // Error
346 break;
347 }
348 fwUpdateState = state;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700349 }
350 uint8_t percent()
351 {
AppaRao Puli28972062019-11-11 02:04:45 +0530352 return progressPercent;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700353 }
AppaRao Puli28972062019-11-11 02:04:45 +0530354 void updateActivationPercent(const std::string &objPath)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700355 {
AppaRao Puli28972062019-11-11 02:04:45 +0530356 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
357 fwUpdateState = fwStateProgram;
358 progressPercent = 0;
359 match = std::make_shared<sdbusplus::bus::match::match>(
360 *busp,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700361 sdbusplus::bus::match::rules::propertiesChanged(
AppaRao Puli28972062019-11-11 02:04:45 +0530362 objPath, "xyz.openbmc_project.Software.ActivationProgress"),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700363 [&](sdbusplus::message::message &msg) {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700364 std::map<std::string, ipmi::DbusVariant> props;
AppaRao Puli28972062019-11-11 02:04:45 +0530365 std::vector<std::string> inVal;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700366 std::string iface;
AppaRao Puli28972062019-11-11 02:04:45 +0530367 try
368 {
369 msg.read(iface, props, inVal);
370 }
371 catch (const std::exception &e)
372 {
373 phosphor::logging::log<phosphor::logging::level::ERR>(
374 "Exception caught in get ActivationProgress");
375 return;
376 }
377
378 auto it = props.find("Progress");
379 if (it != props.end())
380 {
381 progressPercent = std::get<uint8_t>(it->second);
382 if (progressPercent == 100)
383 {
384 fwUpdateState = fwStateUpdateSuccess;
385 }
386 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700387 });
388 }
AppaRao Puli28972062019-11-11 02:04:45 +0530389 uint8_t activationTimerTimeout()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700390 {
AppaRao Puli28972062019-11-11 02:04:45 +0530391 phosphor::logging::log<phosphor::logging::level::INFO>(
392 "activationTimerTimeout: Increase percentage...",
393 phosphor::logging::entry("PERCENT:%d", progressPercent));
394 progressPercent = progressPercent + 5;
jayaprakash Mutyalab8f2bf92020-01-27 23:17:39 +0000395 if (progressPercent > 95)
anil kumar appana31f88872019-08-02 15:16:27 +0000396 {
397 /*changing the state to ready to update firmware utility */
AppaRao Puli28972062019-11-11 02:04:45 +0530398 fwUpdateState = fwStateUpdateSuccess;
anil kumar appana31f88872019-08-02 15:16:27 +0000399 }
AppaRao Puli28972062019-11-11 02:04:45 +0530400 return progressPercent;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700401 }
anil kumar appana31f88872019-08-02 15:16:27 +0000402 /* API for changing state to ERROR */
403 void firmwareUpdateAbortState()
404 {
AppaRao Puli28972062019-11-11 02:04:45 +0530405 unlink(firmwareBufferFile);
anil kumar appana31f88872019-08-02 15:16:27 +0000406 // changing the state to error
AppaRao Puli28972062019-11-11 02:04:45 +0530407 fwUpdateState = fwStateError;
anil kumar appana31f88872019-08-02 15:16:27 +0000408 }
409 void setDeferRestart(bool deferRestart)
410 {
AppaRao Puli28972062019-11-11 02:04:45 +0530411 deferRestartState = deferRestart;
anil kumar appana31f88872019-08-02 15:16:27 +0000412 }
413 void setInhibitDowngrade(bool inhibitDowngrade)
414 {
AppaRao Puli28972062019-11-11 02:04:45 +0530415 inhibitDowngradeState = inhibitDowngrade;
anil kumar appana31f88872019-08-02 15:16:27 +0000416 }
417 bool getDeferRestart()
418 {
AppaRao Puli28972062019-11-11 02:04:45 +0530419 return deferRestartState;
anil kumar appana31f88872019-08-02 15:16:27 +0000420 }
421 bool getInhibitDowngrade()
422 {
AppaRao Puli28972062019-11-11 02:04:45 +0530423 return inhibitDowngradeState;
anil kumar appana31f88872019-08-02 15:16:27 +0000424 }
425
Vernon Mauery52ce6622019-05-22 09:19:46 -0700426 protected:
AppaRao Puli28972062019-11-11 02:04:45 +0530427 std::shared_ptr<sdbusplus::asio::connection> busp;
428 std::shared_ptr<sdbusplus::bus::match::match> match;
429 uint8_t fwUpdateState = 0;
430 uint8_t progressPercent = 0;
431 bool deferRestartState = false;
432 bool inhibitDowngradeState = false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700433};
434
AppaRao Puli28972062019-11-11 02:04:45 +0530435static FwUpdateStatusCache fwUpdateStatus;
436std::shared_ptr<TransferHashCheck> xferHashCheck;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700437
AppaRao Puli28972062019-11-11 02:04:45 +0530438static void activateImage(const std::string &objPath)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700439{
AppaRao Puli28972062019-11-11 02:04:45 +0530440 // If flag is false means to reboot
441 if (fwUpdateStatus.getDeferRestart() == false)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700442 {
AppaRao Puli28972062019-11-11 02:04:45 +0530443 phosphor::logging::log<phosphor::logging::level::INFO>(
444 "activating Image: ",
445 phosphor::logging::entry("OBJPATH =%s", objPath.c_str()));
446 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
447 bus->async_method_call(
448 [](const boost::system::error_code ec) {
449 if (ec)
450 {
451 phosphor::logging::log<phosphor::logging::level::ERR>(
452 "async_method_call error: activateImage failed");
453 return;
454 }
455 },
456 "xyz.openbmc_project.Software.BMC.Updater", objPath,
457 "org.freedesktop.DBus.Properties", "Set",
458 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
459 std::variant<std::string>("xyz.openbmc_project.Software.Activation."
460 "RequestedActivations.Active"));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700461 }
AppaRao Puli28972062019-11-11 02:04:45 +0530462 else
463 {
464 phosphor::logging::log<phosphor::logging::level::INFO>(
465 "Firmware image activation is deferred.");
466 }
467 fwUpdateStatus.setState(
468 static_cast<uint8_t>(FwUpdateStatusCache::fwStateUpdateSuccess));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700469}
470
AppaRao Puli09a83142019-11-23 02:46:06 +0530471static bool getFirmwareUpdateMode()
472{
473 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
474 try
475 {
476 auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
477 ipmi::Value state = ipmi::getDbusProperty(
478 *busp, service, bmcStatePath, bmcStateIntf, "CurrentBMCState");
479 std::string bmcState = std::get<std::string>(state);
480 return (bmcState == bmcStateUpdateInProgress);
481 }
482 catch (const std::exception &e)
483 {
484 phosphor::logging::log<phosphor::logging::level::ERR>(
485 "Exception caught while getting BMC state.",
486 phosphor::logging::entry("EXCEPTION=%s", e.what()));
487 throw;
488 }
489}
490
491static void setFirmwareUpdateMode(const bool mode)
492{
493
494 std::string bmcState(bmcStateReady);
495 if (mode)
496 {
497 bmcState = bmcStateUpdateInProgress;
498 }
499
500 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
501 try
502 {
503 auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
504 ipmi::setDbusProperty(*busp, service, bmcStatePath, bmcStateIntf,
505 "CurrentBMCState", bmcState);
506 }
507 catch (const std::exception &e)
508 {
509 phosphor::logging::log<phosphor::logging::level::ERR>(
510 "Exception caught while setting BMC state.",
511 phosphor::logging::entry("EXCEPTION=%s", e.what()));
512 throw;
513 }
514}
515
AppaRao Pulie2cddf62020-01-31 00:30:08 +0530516/** @brief check if channel IPMB
517 *
518 * This function checks if the command is from IPMB
519 *
520 * @param[in] ctx - context of current session.
521 * @returns true if the medium is IPMB else return true.
522 **/
523ipmi::Cc checkIPMBChannel(const ipmi::Context::ptr &ctx, bool &isIPMBChannel)
524{
525 ipmi::ChannelInfo chInfo;
526
527 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
528 {
529 phosphor::logging::log<phosphor::logging::level::ERR>(
530 "Failed to get Channel Info",
531 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
532 return ipmi::ccUnspecifiedError;
533 }
534
535 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
536 ipmi::EChannelMediumType::ipmb)
537 {
538 isIPMBChannel = true;
539 }
540 return ipmi::ccSuccess;
541}
542
AppaRao Puli28972062019-11-11 02:04:45 +0530543static void postTransferCompleteHandler(
544 std::unique_ptr<sdbusplus::bus::match::match> &fwUpdateMatchSignal)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700545{
546 // Setup timer for watching signal
547 static phosphor::Timer timer(
AppaRao Puli28972062019-11-11 02:04:45 +0530548 [&fwUpdateMatchSignal]() { fwUpdateMatchSignal = nullptr; });
Vernon Mauery52ce6622019-05-22 09:19:46 -0700549
AppaRao Puli28972062019-11-11 02:04:45 +0530550 static phosphor::Timer activationStatusTimer([]() {
jayaprakash Mutyalab8f2bf92020-01-27 23:17:39 +0000551 if (fwUpdateStatus.activationTimerTimeout() > 95)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700552 {
AppaRao Puli28972062019-11-11 02:04:45 +0530553 activationStatusTimer.stop();
554 fwUpdateStatus.setState(
555 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700556 }
557 });
558
559 timer.start(std::chrono::microseconds(5000000), false);
560
561 // callback function for capturing signal
AppaRao Puli28972062019-11-11 02:04:45 +0530562 auto callback = [&](sdbusplus::message::message &m) {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700563 bool flag = false;
564
565 std::vector<std::pair<
566 std::string,
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700567 std::vector<std::pair<std::string, std::variant<std::string>>>>>
AppaRao Puli28972062019-11-11 02:04:45 +0530568 intfPropsPair;
569 sdbusplus::message::object_path objPath;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700570
571 try
572 {
AppaRao Puli28972062019-11-11 02:04:45 +0530573 m.read(objPath, intfPropsPair); // Read in the object path
574 // that was just created
Vernon Mauery52ce6622019-05-22 09:19:46 -0700575 }
AppaRao Puli28972062019-11-11 02:04:45 +0530576 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700577 {
AppaRao Puli28972062019-11-11 02:04:45 +0530578 phosphor::logging::log<phosphor::logging::level::ERR>(
579 "Exception caught in reading created object path.");
580 return;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700581 }
582 // constructing response message
AppaRao Puli28972062019-11-11 02:04:45 +0530583 phosphor::logging::log<phosphor::logging::level::INFO>(
584 "New Interface Added.",
585 phosphor::logging::entry("OBJPATH=%s", objPath.str.c_str()));
586 for (auto &interface : intfPropsPair)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700587 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700588 if (interface.first == "xyz.openbmc_project.Software.Activation")
589 {
AppaRao Puli28972062019-11-11 02:04:45 +0530590 // There are chances of getting two signals for
591 // InterfacesAdded. So cross check and discrad second instance.
592 if (fwUpdateMatchSignal == nullptr)
593 {
594 return;
595 }
596 // Found our interface, disable callbacks
597 fwUpdateMatchSignal = nullptr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700598
AppaRao Puli28972062019-11-11 02:04:45 +0530599 phosphor::logging::log<phosphor::logging::level::INFO>(
600 "Start activationStatusTimer for status.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700601 try
602 {
603 timer.stop();
AppaRao Puli28972062019-11-11 02:04:45 +0530604 activationStatusTimer.start(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700605 std::chrono::microseconds(3000000), true);
606 }
AppaRao Puli28972062019-11-11 02:04:45 +0530607 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700608 {
AppaRao Puli28972062019-11-11 02:04:45 +0530609 phosphor::logging::log<phosphor::logging::level::ERR>(
610 "Exception caught in start activationStatusTimer.",
611 phosphor::logging::entry("ERROR=%s", e.what()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700612 }
613
AppaRao Puli28972062019-11-11 02:04:45 +0530614 fwUpdateStatus.updateActivationPercent(objPath.str);
615 activateImage(objPath.str);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700616 }
617 }
618 };
619
620 // Adding matcher
AppaRao Puli28972062019-11-11 02:04:45 +0530621 fwUpdateMatchSignal = std::make_unique<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700622 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700623 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
624 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
625 callback);
626}
AppaRao Puli28972062019-11-11 02:04:45 +0530627static bool startFirmwareUpdate(const std::string &uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700628{
AppaRao Puli28972062019-11-11 02:04:45 +0530629 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
630 // the code gets to this point, the file should be transferred start the
631 // request (creating a new file in /tmp/images causes the update manager to
632 // check if it is ready for activation)
633 static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatchSignal;
634 postTransferCompleteHandler(fwUpdateMatchSignal);
635 std::filesystem::rename(
636 uri, "/tmp/images/" +
637 boost::uuids::to_string(boost::uuids::random_generator()()));
638 return true;
639}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700640
AppaRao Puli28972062019-11-11 02:04:45 +0530641static int transferImageFromFile(const std::string &uri, bool move = true)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700642{
643 std::error_code ec;
AppaRao Puli28972062019-11-11 02:04:45 +0530644 phosphor::logging::log<phosphor::logging::level::INFO>(
645 "Transfer Image From File.",
646 phosphor::logging::entry("URI=%s", uri.c_str()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700647 if (move)
648 {
AppaRao Puli28972062019-11-11 02:04:45 +0530649 std::filesystem::rename(uri, firmwareBufferFile, ec);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700650 }
651 else
652 {
AppaRao Puli28972062019-11-11 02:04:45 +0530653 std::filesystem::copy(uri, firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700654 std::filesystem::copy_options::overwrite_existing,
655 ec);
656 }
AppaRao Puli28972062019-11-11 02:04:45 +0530657 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700658 {
659 MappedFile mappedfw(uri);
AppaRao Puli28972062019-11-11 02:04:45 +0530660 xferHashCheck->hash(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700661 {mappedfw.data(), mappedfw.data() + mappedfw.size()});
662 }
663 if (ec.value())
664 {
AppaRao Puli28972062019-11-11 02:04:45 +0530665 phosphor::logging::log<phosphor::logging::level::ERR>(
666 "Image copy failed.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700667 }
668 return ec.value();
669}
670
671template <typename... ArgTypes>
672static int executeCmd(const char *path, ArgTypes &&... tArgs)
673{
674 boost::process::child execProg(path, const_cast<char *>(tArgs)...);
675 execProg.wait();
676 return execProg.exit_code();
677}
678
AppaRao Puli28972062019-11-11 02:04:45 +0530679static int transferImageFromUsb(const std::string &uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700680{
681 int ret, sysret;
682 char fwpath[fwPathMaxLength];
AppaRao Puli28972062019-11-11 02:04:45 +0530683 phosphor::logging::log<phosphor::logging::level::INFO>(
684 "Transfer Image From USB.",
685 phosphor::logging::entry("URI=%s", uri.c_str()));
686 ret = executeCmd(usbCtrlPath, "mount", fwUpdateUsbVolImage,
687 fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700688 if (ret)
689 {
690 return ret;
691 }
692
AppaRao Puli28972062019-11-11 02:04:45 +0530693 std::string usb_path = std::string(fwUpdateMountPoint) + "/" + uri;
694 ret = transferImageFromFile(usb_path, false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700695
AppaRao Puli28972062019-11-11 02:04:45 +0530696 executeCmd(usbCtrlPath, "cleanup", fwUpdateUsbVolImage, fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700697 return ret;
698}
699
AppaRao Puli28972062019-11-11 02:04:45 +0530700static bool transferFirmwareFromUri(const std::string &uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700701{
AppaRao Puli28972062019-11-11 02:04:45 +0530702 static constexpr char fwUriFile[] = "file://";
703 static constexpr char fwUriUsb[] = "usb://";
704 phosphor::logging::log<phosphor::logging::level::INFO>(
705 "Transfer Image From URI.",
706 phosphor::logging::entry("URI=%s", uri.c_str()));
707 if (boost::algorithm::starts_with(uri, fwUriFile))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700708 {
AppaRao Puli28972062019-11-11 02:04:45 +0530709 std::string fname = uri.substr(sizeof(fwUriFile) - 1);
710 if (fname != firmwareBufferFile)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700711 {
AppaRao Puli28972062019-11-11 02:04:45 +0530712 return 0 == transferImageFromFile(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700713 }
714 return true;
715 }
AppaRao Puli28972062019-11-11 02:04:45 +0530716 if (boost::algorithm::starts_with(uri, fwUriUsb))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700717 {
AppaRao Puli28972062019-11-11 02:04:45 +0530718 std::string fname = uri.substr(sizeof(fwUriUsb) - 1);
719 return 0 == transferImageFromUsb(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700720 }
721 return false;
722}
723
724/* Get USB-mass-storage device status: inserted => true, ejected => false */
AppaRao Puli28972062019-11-11 02:04:45 +0530725static bool getUsbStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700726{
AppaRao Puli28972062019-11-11 02:04:45 +0530727 std::filesystem::path usbDevPath =
728 std::filesystem::path("/sys/kernel/config/usb_gadget") /
729 fwUpdateUSBDevName;
730 return (std::filesystem::exists(usbDevPath) ? true : false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700731}
732
733/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530734static int attachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700735{
AppaRao Puli28972062019-11-11 02:04:45 +0530736 if (getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700737 {
738 return 1;
739 }
AppaRao Puli28972062019-11-11 02:04:45 +0530740 int ret = executeCmd(usbCtrlPath, "setup", fwUpdateUsbVolImage,
741 std::to_string(maxFirmwareImageSize / 1_MB).c_str());
Vernon Mauery52ce6622019-05-22 09:19:46 -0700742 if (!ret)
743 {
AppaRao Puli28972062019-11-11 02:04:45 +0530744 ret = executeCmd(usbCtrlPath, "insert", fwUpdateUSBDevName,
745 fwUpdateUsbVolImage);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700746 }
747 return ret;
748}
749
750/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530751static int detachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700752{
AppaRao Puli28972062019-11-11 02:04:45 +0530753 if (!getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700754 {
755 return 1;
756 }
AppaRao Puli28972062019-11-11 02:04:45 +0530757 return executeCmd(usbCtrlPath, "eject", fwUpdateUSBDevName);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700758}
AppaRao Puli28972062019-11-11 02:04:45 +0530759static uint8_t getActiveBootImage(ipmi::Context::ptr ctx)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700760{
AppaRao Puli28972062019-11-11 02:04:45 +0530761 constexpr uint8_t primaryImage = 0x01;
762 constexpr uint8_t secondaryImage = 0x02;
763 constexpr const char *secondaryFitImageStartAddr = "22480000";
764
765 uint8_t bootImage = primaryImage;
766 boost::system::error_code ec;
767 std::string value = ctx->bus->yield_method_call<std::string>(
768 ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
769 "/xyz/openbmc_project/u_boot/environment/mgr",
770 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
771 if (ec)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700772 {
AppaRao Puli28972062019-11-11 02:04:45 +0530773 phosphor::logging::log<phosphor::logging::level::ERR>(
774 "Failed to read the bootcmd value");
775 return ipmi::ccUnspecifiedError;
776 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700777
AppaRao Puli28972062019-11-11 02:04:45 +0530778 /* cheking for secondary FitImage Address 22480000 */
779 if (value.find(secondaryFitImageStartAddr) != std::string::npos)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700780 {
AppaRao Puli28972062019-11-11 02:04:45 +0530781 bootImage = secondaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700782 }
783 else
784 {
AppaRao Puli28972062019-11-11 02:04:45 +0530785 bootImage = primaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700786 }
787
AppaRao Puli28972062019-11-11 02:04:45 +0530788 return bootImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700789}
790
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530791#ifdef INTEL_PFR_ENABLED
792using fwVersionInfoType = std::tuple<uint8_t, // ID Tag
793 uint8_t, // Major Version Number
794 uint8_t, // Minor Version Number
795 uint32_t, // Build Number
796 uint32_t, // Build Timestamp
797 uint32_t>; // Update Timestamp
798ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700799{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700800 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530801 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700802 // Bytes - 17:(15xN) - Repeat of 2 through 16
803
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530804 std::vector<fwVersionInfoType> fwVerInfoList;
805 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
806 for (const auto &fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700807 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530808 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700809 try
810 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530811 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700812
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530813 ipmi::Value result = ipmi::getDbusProperty(
814 *busp, service, fwDev.second, versionIntf, "Version");
815 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700816 }
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530817 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700818 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530819 phosphor::logging::log<phosphor::logging::level::INFO>(
820 "Failed to fetch Version property",
821 phosphor::logging::entry("ERROR=%s", e.what()),
822 phosphor::logging::entry("PATH=%s", fwDev.second),
823 phosphor::logging::entry("INTERFACE=%s", versionIntf));
824 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700825 }
826
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530827 if (verStr.empty())
828 {
829 phosphor::logging::log<phosphor::logging::level::INFO>(
830 "Version is empty.",
831 phosphor::logging::entry("PATH=%s", fwDev.second),
832 phosphor::logging::entry("INTERFACE=%s", versionIntf));
833 continue;
834 }
835
836 // BMC Version format: <major>.<minor>-<build bum>-<build hash>
837 std::vector<std::string> splitVer;
838 boost::split(splitVer, verStr, boost::is_any_of(".-"));
839 if (splitVer.size() < 3)
840 {
841 phosphor::logging::log<phosphor::logging::level::INFO>(
842 "Invalid Version format.",
843 phosphor::logging::entry("Version=%s", verStr.c_str()),
844 phosphor::logging::entry("PATH=%s", fwDev.second));
845 continue;
846 }
847
848 uint8_t majorNum = 0;
849 uint8_t minorNum = 0;
850 uint32_t buildNum = 0;
851 try
852 {
853 majorNum = std::stoul(splitVer[0], nullptr, 16);
854 minorNum = std::stoul(splitVer[1], nullptr, 16);
855 buildNum = std::stoul(splitVer[2], nullptr, 16);
856 }
857 catch (const std::exception &e)
858 {
859 phosphor::logging::log<phosphor::logging::level::INFO>(
860 "Failed to convert stoul.",
861 phosphor::logging::entry("ERROR=%s", e.what()));
862 continue;
863 }
864
865 // Build Timestamp - Not supported.
866 // Update Timestamp - TODO: Need to check with CPLD team.
867 fwVerInfoList.emplace_back(
868 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
869 minorNum, buildNum, 0, 0));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700870 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700871
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530872 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700873}
AppaRao Puli28972062019-11-11 02:04:45 +0530874using fwSecurityVersionInfoType = std::tuple<uint8_t, // ID Tag
875 uint8_t, // BKC Version
876 uint8_t>; // SVN Version
877ipmi::RspType<uint8_t, std::vector<fwSecurityVersionInfoType>>
878 ipmiGetFwSecurityVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700879{
AppaRao Puli28972062019-11-11 02:04:45 +0530880 // TODO: Need to add support.
881 return ipmi::responseInvalidCommand();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700882}
883
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530884ipmi::RspType<std::array<uint8_t, certKeyLen>,
885 std::optional<std::array<uint8_t, cskSignatureLen>>>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530886 ipmiGetFwRootCertData(const ipmi::Context::ptr &ctx, uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700887{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530888 bool isIPMBChannel = false;
889
890 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
891 {
892 return ipmi::responseUnspecifiedError();
893 }
894 if (isIPMBChannel)
895 {
896 phosphor::logging::log<phosphor::logging::level::INFO>(
897 "Command not supported. Failed to get root certificate data.");
898 return ipmi::responseCommandNotAvailable();
899 }
900
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530901 size_t certKeyOffset = 0;
902 size_t cskSigOffset = 0;
903 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700904
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530905 switch (static_cast<FwGetRootCertDataTag>(certId))
906 {
907 case FwGetRootCertDataTag::activeRootKey:
908 {
909 mtdDev = bmcActivePfmMTDDev;
910 certKeyOffset = rootkeyOffsetInPfm;
911 break;
912 }
913 case FwGetRootCertDataTag::recoveryRootKey:
914 {
915 mtdDev = bmcRecoveryImgMTDDev;
916 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
917 break;
918 }
919 case FwGetRootCertDataTag::activeCSK:
920 {
921 mtdDev = bmcActivePfmMTDDev;
922 certKeyOffset = cskKeyOffsetInPfm;
923 cskSigOffset = cskSignatureOffsetInPfm;
924 break;
925 }
926 case FwGetRootCertDataTag::recoveryCSK:
927 {
928 mtdDev = bmcRecoveryImgMTDDev;
929 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
930 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
931 break;
932 }
933 default:
934 {
935 return ipmi::responseInvalidFieldRequest();
936 }
937 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700938
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530939 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700940
Vernon Mauery52ce6622019-05-22 09:19:46 -0700941 try
942 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530943 SPIDev spiDev(mtdDev);
944 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
945
946 if (cskSigOffset)
947 {
948 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
949 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
950 cskSignature.data());
951 return ipmi::responseSuccess(certKey, cskSignature);
952 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700953 }
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530954 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700955 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530956 phosphor::logging::log<phosphor::logging::level::ERR>(
957 "Exception caught in ipmiGetFwRootCertData",
958 phosphor::logging::entry("MSG=%s", e.what()));
959 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700960 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700961
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530962 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700963}
AppaRao Puli28972062019-11-11 02:04:45 +0530964#endif // INTEL_PFR_ENABLED
965
966static constexpr uint8_t channelListSize = 3;
967/** @brief implements Maximum Firmware Transfer size command
968 * @parameter
969 * - none
970 * @returns IPMI completion code plus response data
971 * - count - channel count
972 * - channelList - channel list information
973 */
974ipmi::RspType<uint8_t, // channel count
975 std::array<std::tuple<uint8_t, uint32_t>,
976 channelListSize> // Channel List
977 >
978 ipmiFirmwareMaxTransferSize()
979{
980 constexpr size_t kcsMaxBufSize = 128;
981 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
AppaRao Puli28972062019-11-11 02:04:45 +0530982 // Byte 1 - Count (N) Number of devices data is being returned for.
983 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
984 // Byte 3-6 - transfer size (little endian)
985 // Bytes - 7:(5xN) - Repeat of 2 through 6
986 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
987 channelList = {
988 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
AppaRao Puli28972062019-11-11 02:04:45 +0530989 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
990 rmcpPlusMaxBufSize}}};
991
992 return ipmi::responseSuccess(channelListSize, channelList);
993}
994
995ipmi::RspType<uint8_t, uint8_t>
996 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
997{
998 // Byte 1 - Current execution context
999 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
1000 // Byte 2 - Partition pointer
1001 // 0x01 - primary, 0x02 - secondary
1002 uint8_t partitionPtr = getActiveBootImage(ctx);
1003
1004 return ipmi::responseSuccess(
1005 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
1006}
AppaRao Puli28972062019-11-11 02:04:45 +05301007/** @brief Get Firmware Update Random Number
1008 *
1009 * This function generate the random number used for
1010 * setting the firmware update mode as authentication key.
1011 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301012 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301013 * @returns IPMI completion code along with
1014 * - random number
1015 **/
1016ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301017 ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr &ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301018{
1019 phosphor::logging::log<phosphor::logging::level::INFO>(
1020 "Generate FW update random number");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301021 bool isIPMBChannel = false;
1022
1023 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1024 {
1025 return ipmi::responseUnspecifiedError();
1026 }
1027 if (isIPMBChannel)
1028 {
1029 phosphor::logging::log<phosphor::logging::level::INFO>(
1030 "Channel not supported. Failed to fetch FW update random number");
1031 return ipmi::responseCommandNotAvailable();
1032 }
AppaRao Puli28972062019-11-11 02:04:45 +05301033 std::random_device rd;
1034 std::default_random_engine gen(rd());
1035 std::uniform_int_distribution<> dist{0, 255};
1036
1037 fwRandomNumGenTs = std::chrono::steady_clock::now();
1038
1039 for (int i = 0; i < fwRandomNumLength; i++)
1040 {
1041 fwRandomNum[i] = dist(gen);
1042 }
1043
1044 return ipmi::responseSuccess(fwRandomNum);
1045}
1046
1047/** @brief Set Firmware Update Mode
1048 *
1049 * This function sets BMC into firmware update mode
1050 * after validating Random number obtained from the Get
1051 * Firmware Update Random Number command
1052 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301053 * @param[in] ctx - context of current session
1054 * @parameter randNum - Random number(token)
1055 * @returns IPMI completion code
AppaRao Puli28972062019-11-11 02:04:45 +05301056 **/
1057ipmi::RspType<>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301058 ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr &ctx,
1059 std::array<uint8_t, fwRandomNumLength> &randNum)
AppaRao Puli28972062019-11-11 02:04:45 +05301060{
1061 phosphor::logging::log<phosphor::logging::level::INFO>(
1062 "Start FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301063
1064 bool isIPMBChannel = false;
1065
1066 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1067 {
1068 return ipmi::responseUnspecifiedError();
1069 }
1070 if (isIPMBChannel)
1071 {
1072 phosphor::logging::log<phosphor::logging::level::INFO>(
1073 "Channel not supported. Failed to set FW update mode");
1074 return ipmi::responseCommandNotAvailable();
1075 }
AppaRao Puli28972062019-11-11 02:04:45 +05301076 /* Firmware Update Random number is valid for 30 seconds only */
1077 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1078 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1079 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1080 fwRandomNumExpirySeconds)
1081 .count())
1082 {
1083 phosphor::logging::log<phosphor::logging::level::INFO>(
1084 "Firmware update random number expired.");
1085 return ipmi::responseInvalidFieldRequest();
1086 }
1087
1088 /* Validate random number */
1089 for (int i = 0; i < fwRandomNumLength; i++)
1090 {
1091 if (fwRandomNum[i] != randNum[i])
1092 {
1093 phosphor::logging::log<phosphor::logging::level::INFO>(
1094 "Invalid random number specified.");
1095 return ipmi::responseInvalidFieldRequest();
1096 }
1097 }
1098
1099 try
1100 {
1101 if (getFirmwareUpdateMode())
1102 {
1103 phosphor::logging::log<phosphor::logging::level::INFO>(
1104 "Already firmware update is in progress.");
1105 return ipmi::responseBusy();
1106 }
1107 }
1108 catch (const std::exception &e)
1109 {
1110 return ipmi::responseUnspecifiedError();
1111 }
1112
1113 // FIXME? c++ doesn't off an option for exclusive file creation
1114 FILE *fp = fopen(firmwareBufferFile, "wx");
1115 if (!fp)
1116 {
1117 phosphor::logging::log<phosphor::logging::level::INFO>(
1118 "Unable to open file.");
1119 return ipmi::responseUnspecifiedError();
1120 }
1121 fclose(fp);
1122
1123 try
1124 {
1125 setFirmwareUpdateMode(true);
1126 }
1127 catch (const std::exception &e)
1128 {
1129 unlink(firmwareBufferFile);
1130 return ipmi::responseUnspecifiedError();
1131 }
1132
1133 return ipmi::responseSuccess();
1134}
1135
1136/** @brief implements exit firmware update mode command
1137 * @param None
1138 *
1139 * @returns IPMI completion code
1140 */
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301141ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr &ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301142{
1143 phosphor::logging::log<phosphor::logging::level::INFO>(
1144 "Exit FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301145 bool isIPMBChannel = false;
1146
1147 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1148 {
1149 return ipmi::responseUnspecifiedError();
1150 }
1151 if (isIPMBChannel)
1152 {
1153 phosphor::logging::log<phosphor::logging::level::INFO>(
1154 "Command not supported. Failed to exit firmware update mode");
1155 return ipmi::responseCommandNotAvailable();
1156 }
1157
AppaRao Puli28972062019-11-11 02:04:45 +05301158 switch (fwUpdateStatus.getState())
1159 {
1160 case FwUpdateStatusCache::fwStateInit:
1161 case FwUpdateStatusCache::fwStateIdle:
1162 return ipmi::responseInvalidFieldRequest();
1163 break;
1164 case FwUpdateStatusCache::fwStateDownload:
1165 case FwUpdateStatusCache::fwStateVerify:
1166 break;
1167 case FwUpdateStatusCache::fwStateProgram:
1168 break;
1169 case FwUpdateStatusCache::fwStateUpdateSuccess:
1170 case FwUpdateStatusCache::fwStateError:
1171 break;
1172 case FwUpdateStatusCache::fwStateAcCycleRequired:
1173 return ipmi::responseInvalidFieldRequest();
1174 break;
1175 }
1176 fwUpdateStatus.firmwareUpdateAbortState();
1177
1178 try
1179 {
1180 setFirmwareUpdateMode(false);
1181 }
1182 catch (const std::exception &e)
1183 {
1184 return ipmi::responseUnspecifiedError();
1185 }
1186
1187 return ipmi::responseSuccess();
1188}
1189
1190/** @brief implements Get/Set Firmware Update Control
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301191 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301192 * @parameter
1193 * - Byte 1: Control Byte
1194 * - Byte 2: Firmware filename length (Optional)
1195 * - Byte 3:N: Firmware filename data (Optional)
1196 * @returns IPMI completion code plus response data
1197 * - Byte 2: Current control status
1198 **/
1199ipmi::RspType<bool, bool, bool, bool, uint4_t>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301200 ipmiGetSetFirmwareUpdateControl(const ipmi::Context::ptr &ctx,
1201 const uint8_t controlReq,
AppaRao Puli28972062019-11-11 02:04:45 +05301202 const std::optional<std::string> &fileName)
1203{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301204 bool isIPMBChannel = false;
1205
1206 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1207 {
1208 return ipmi::responseUnspecifiedError();
1209 }
1210 if (isIPMBChannel)
1211 {
1212 phosphor::logging::log<phosphor::logging::level::INFO>(
1213 "Channel not supported. Failed to get or set FW update control");
1214 return ipmi::responseCommandNotAvailable();
1215 }
1216
AppaRao Puli28972062019-11-11 02:04:45 +05301217 static std::string fwXferUriPath;
1218 static bool imageTransferStarted = false;
1219 static bool imageTransferCompleted = false;
1220 static bool imageTransferAborted = false;
1221
1222 if ((controlReq !=
1223 static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
1224 (fileName))
1225 {
1226 phosphor::logging::log<phosphor::logging::level::ERR>(
1227 "Invalid request field (Filename).");
1228 return ipmi::responseInvalidFieldRequest();
1229 }
1230
1231 static bool usbAttached = getUsbStatus();
1232
1233 switch (static_cast<FwUpdateCtrlReq>(controlReq))
1234 {
1235 case FwUpdateCtrlReq::getCurrentControlStatus:
1236 phosphor::logging::log<phosphor::logging::level::INFO>(
1237 "ipmiGetSetFirmwareUpdateControl: Get status");
1238 break;
1239 case FwUpdateCtrlReq::imageTransferStart:
1240 {
1241 phosphor::logging::log<phosphor::logging::level::INFO>(
1242 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
1243 imageTransferStarted = true;
1244 // reset buffer to empty (truncate file)
1245 std::ofstream out(firmwareBufferFile,
1246 std::ofstream::binary | std::ofstream::trunc);
1247 fwXferUriPath = std::string("file://") + firmwareBufferFile;
1248 if (xferHashCheck)
1249 {
1250 xferHashCheck->clear();
1251 }
1252 // Setting state to download
1253 fwUpdateStatus.setState(
1254 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
1255#ifdef INTEL_PFR_ENABLED
1256 imgLength = 0;
1257 imgType = 0;
1258 block0Mapped = false;
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301259#endif
AppaRao Puli28972062019-11-11 02:04:45 +05301260 }
1261 break;
1262 case FwUpdateCtrlReq::imageTransferComplete:
1263 {
1264 phosphor::logging::log<phosphor::logging::level::INFO>(
1265 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
1266 if (usbAttached)
1267 {
1268 phosphor::logging::log<phosphor::logging::level::ERR>(
1269 "USB should be detached to perform this operation.");
1270 return ipmi::responseNotSupportedInPresentState();
1271 }
1272 // finish transfer based on URI
1273 if (!transferFirmwareFromUri(fwXferUriPath))
1274 {
1275 phosphor::logging::log<phosphor::logging::level::ERR>(
1276 "transferFirmwareFromUri failed.");
1277 return ipmi::responseUnspecifiedError();
1278 }
1279 // transfer complete
1280 if (xferHashCheck)
1281 {
1282 if (TransferHashCheck::HashCheck::sha2Success !=
1283 xferHashCheck->verify())
1284 {
1285 phosphor::logging::log<phosphor::logging::level::ERR>(
1286 "xferHashCheck failed.");
1287 return ipmi::responseUnspecifiedError();
1288 }
1289 }
1290 // Set state to verify and start the update
1291 fwUpdateStatus.setState(
1292 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
1293 // start the request
1294 if (!startFirmwareUpdate(firmwareBufferFile))
1295 {
1296 phosphor::logging::log<phosphor::logging::level::ERR>(
1297 "startFirmwareUpdate failed.");
1298 return ipmi::responseUnspecifiedError();
1299 }
1300 imageTransferCompleted = true;
1301 }
1302 break;
1303 case FwUpdateCtrlReq::imageTransferAbort:
1304 phosphor::logging::log<phosphor::logging::level::INFO>(
1305 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
1306 if (usbAttached)
1307 {
1308 if (detachUsbDevice())
1309 {
1310 phosphor::logging::log<phosphor::logging::level::ERR>(
1311 "Detach USB device failed.");
1312 return ipmi::responseUsbAttachOrDetachFailed();
1313 }
1314 usbAttached = false;
1315 }
1316 // During abort request reset the state to Init by cleaning update
1317 // file.
1318 fwUpdateStatus.firmwareUpdateAbortState();
1319 imageTransferAborted = true;
1320 break;
1321 case FwUpdateCtrlReq::setFirmwareFilename:
1322 phosphor::logging::log<phosphor::logging::level::INFO>(
1323 "ipmiGetSetFirmwareUpdateControl: Set filename.");
1324 if (!fileName || ((*fileName).length() == 0))
1325 {
1326 phosphor::logging::log<phosphor::logging::level::ERR>(
1327 "Invalid Filename specified.");
1328 return ipmi::responseInvalidFieldRequest();
1329 }
1330
1331 fwXferUriPath = *fileName;
1332 break;
1333 case FwUpdateCtrlReq::attachUsbDevice:
1334 phosphor::logging::log<phosphor::logging::level::INFO>(
1335 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
1336 if (usbAttached)
1337 {
1338 phosphor::logging::log<phosphor::logging::level::ERR>(
1339 "USB device is already attached.");
1340 return ipmi::responseInvalidFieldRequest();
1341 }
1342 if (attachUsbDevice())
1343 {
1344 phosphor::logging::log<phosphor::logging::level::ERR>(
1345 "Attach USB device failed.");
1346 return ipmi::responseUsbAttachOrDetachFailed();
1347 }
1348 usbAttached = true;
1349 break;
1350 case FwUpdateCtrlReq::detachUsbDevice:
1351 phosphor::logging::log<phosphor::logging::level::INFO>(
1352 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
1353 if (!usbAttached)
1354 {
1355 phosphor::logging::log<phosphor::logging::level::ERR>(
1356 "USB device is not attached.");
1357 return ipmi::responseInvalidFieldRequest();
1358 }
1359 if (detachUsbDevice())
1360 {
1361 phosphor::logging::log<phosphor::logging::level::ERR>(
1362 "Detach USB device failed.");
1363 return ipmi::responseUsbAttachOrDetachFailed();
1364 }
1365 usbAttached = false;
1366 break;
1367 default:
1368 phosphor::logging::log<phosphor::logging::level::ERR>(
1369 "Invalid control option specified.");
1370 return ipmi::responseInvalidFieldRequest();
1371 }
1372
1373 return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
1374 imageTransferAborted, usbAttached, uint4_t(0));
1375}
1376
1377/** @brief implements firmware get status command
1378 * @parameter
1379 * - none
1380 * @returns IPMI completion code plus response data
1381 * - status - processing status
1382 * - percentage - percentage completion
1383 * - check - channel integrity check status
1384 **/
1385ipmi::RspType<uint8_t, // status
1386 uint8_t, // percentage
1387 uint8_t // check
1388 >
1389 ipmiGetFirmwareUpdateStatus()
1390
1391{
1392 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1393 // 5=ready, f=error, 83=ac cycle required)
1394 // Byte 2 - percent
1395 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
1396 uint8_t status = fwUpdateStatus.getState();
1397 uint8_t percent = fwUpdateStatus.percent();
1398 uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
1399
1400 // Status code.
1401 return ipmi::responseSuccess(status, percent, check);
1402}
1403
1404ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301405 const ipmi::Context::ptr &ctx, bool noDowngradeMask, bool deferRestartMask,
1406 bool sha2CheckMask, uint5_t reserved1, bool noDowngrade, bool deferRestart,
1407 bool sha2Check, uint5_t reserved2,
1408 std::optional<std::vector<uint8_t>> integrityCheckVal)
AppaRao Puli28972062019-11-11 02:04:45 +05301409{
1410 phosphor::logging::log<phosphor::logging::level::INFO>(
1411 "Set firmware update options.");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301412 bool isIPMBChannel = false;
1413
1414 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1415 {
1416 return ipmi::responseUnspecifiedError();
1417 }
1418 if (isIPMBChannel)
1419 {
1420 phosphor::logging::log<phosphor::logging::level::INFO>(
1421 "Channel not supported. Failed to set firmware update options");
1422 return ipmi::responseCommandNotAvailable();
1423 }
AppaRao Puli28972062019-11-11 02:04:45 +05301424 bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
1425 bool deferRestartState = fwUpdateStatus.getDeferRestart();
1426 bool sha2CheckState = xferHashCheck ? true : false;
1427
1428 if (noDowngradeMask && (noDowngradeState != noDowngrade))
1429 {
1430 fwUpdateStatus.setInhibitDowngrade(noDowngrade);
1431 noDowngradeState = noDowngrade;
1432 }
1433 if (deferRestartMask && (deferRestartState != deferRestart))
1434 {
1435 fwUpdateStatus.setDeferRestart(deferRestart);
1436 deferRestartState = deferRestart;
1437 }
1438 if (sha2CheckMask)
1439 {
1440 if (sha2Check)
1441 {
1442 auto hashSize = EVP_MD_size(EVP_sha256());
1443 if ((*integrityCheckVal).size() != hashSize)
1444 {
1445 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1446 "Invalid size of Hash specified.");
1447 return ipmi::responseInvalidFieldRequest();
1448 }
1449 xferHashCheck = std::make_shared<TransferHashCheck>();
1450 xferHashCheck->init(*integrityCheckVal);
1451 }
1452 else
1453 {
1454 // delete the xferHashCheck object
1455 xferHashCheck.reset();
1456 }
1457 sha2CheckState = sha2CheckMask;
1458 }
1459 return ipmi::responseSuccess(noDowngradeState, deferRestartState,
1460 sha2CheckState, reserved1);
1461}
Vernon Mauery52ce6622019-05-22 09:19:46 -07001462
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301463ipmi::RspType<uint32_t>
1464 ipmiFwImageWriteData(const std::vector<uint8_t> &writeData)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001465{
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301466 const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
1467 size_t writeDataLen = writeData.size();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001468
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301469 if (!writeDataLen)
1470 {
1471 return ipmi::responseReqDataLenInvalid();
1472 }
1473
AppaRao Puli28972062019-11-11 02:04:45 +05301474 if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301475 {
AppaRao Puli28972062019-11-11 02:04:45 +05301476 phosphor::logging::log<phosphor::logging::level::ERR>(
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301477 "Invalid firmware update state.");
1478 return ipmi::response(ccCmdNotSupportedInPresentState);
1479 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001480
AppaRao Puli28972062019-11-11 02:04:45 +05301481 std::ofstream out(firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001482 std::ofstream::binary | std::ofstream::app);
1483 if (!out)
1484 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301485 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1486 "Error while opening file.");
1487 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001488 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301489
1490 uint64_t fileDataLen = out.tellp();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301491
AppaRao Puli28972062019-11-11 02:04:45 +05301492 if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001493 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301494 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1495 "Firmware image size exceeds the limit");
1496 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001497 }
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301498
1499 const char *data = reinterpret_cast<const char *>(writeData.data());
1500 out.write(data, writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001501 out.close();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301502
AppaRao Puli28972062019-11-11 02:04:45 +05301503 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001504 {
AppaRao Puli28972062019-11-11 02:04:45 +05301505 xferHashCheck->hash(writeData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001506 }
1507
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301508#ifdef INTEL_PFR_ENABLED
1509 /* PFR image block 0 - As defined in HAS */
1510 struct PFRImageBlock0
1511 {
1512 uint32_t tag;
1513 uint32_t pcLength;
1514 uint32_t pcType;
1515 uint32_t reserved1;
1516 uint8_t hash256[32];
1517 uint8_t hash384[48];
1518 uint8_t reserved2[32];
1519 } __attribute__((packed));
1520
1521 /* Get the PFR block 0 data and read the uploaded image
1522 * information( Image type, length etc) */
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301523 if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
1524 (!block0Mapped))
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301525 {
1526 struct PFRImageBlock0 block0Data = {0};
1527
AppaRao Puli28972062019-11-11 02:04:45 +05301528 std::ifstream inFile(firmwareBufferFile,
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301529 std::ios::binary | std::ios::in);
1530 inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
1531 inFile.close();
1532
1533 uint32_t magicNum = block0Data.tag;
1534
1535 /* Validate the magic number */
1536 if (magicNum != perBlock0MagicNum)
1537 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301538 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1539 "PFR image magic number not matched");
1540 return ipmi::responseInvalidFieldRequest();
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301541 }
1542 // Note:imgLength, imgType and block0Mapped are in global scope, as
1543 // these are used in cascaded updates.
1544 imgLength = block0Data.pcLength;
1545 imgType = block0Data.pcType;
1546 block0Mapped = true;
1547 }
1548#endif // end of INTEL_PFR_ENABLED
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301549 return ipmi::responseSuccess(writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001550}
1551
AppaRao Puli28972062019-11-11 02:04:45 +05301552static void registerFirmwareFunctions()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001553{
1554 // guarantee that we start with an already timed out timestamp
AppaRao Puli28972062019-11-11 02:04:45 +05301555 fwRandomNumGenTs =
1556 std::chrono::steady_clock::now() - fwRandomNumExpirySeconds;
1557 fwUpdateStatus.setState(
1558 static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001559
AppaRao Puli28972062019-11-11 02:04:45 +05301560 unlink(firmwareBufferFile);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001561
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301562#ifdef INTEL_PFR_ENABLED
1563 // Following commands are supported only for PFR enabled platforms
1564 // CMD:0x20 - Get Firmware Version Information
AppaRao Puli28972062019-11-11 02:04:45 +05301565 // CMD:0x21 - Get Firmware Security Version Information
1566 // CMD:0x25 - Get Root Certificate Data
Vernon Mauery52ce6622019-05-22 09:19:46 -07001567
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301568 // get firmware version information
1569 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1570 ipmi::firmware::cmdGetFwVersionInfo,
1571 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
AppaRao Puli28972062019-11-11 02:04:45 +05301572
Vernon Mauery52ce6622019-05-22 09:19:46 -07001573 // get firmware security version information
AppaRao Puli28972062019-11-11 02:04:45 +05301574 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1575 ipmi::firmware::cmdGetFwSecurityVersionInfo,
1576 ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001577
Vernon Mauery52ce6622019-05-22 09:19:46 -07001578 // get root certificate data
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301579 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1580 ipmi::firmware::cmdFwGetRootCertData,
1581 ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1582#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001583
AppaRao Puli28972062019-11-11 02:04:45 +05301584 // get firmware update channel information (max transfer sizes)
1585 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1586 ipmi::firmware::cmdGetFwUpdateChannelInfo,
1587 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001588
AppaRao Puli28972062019-11-11 02:04:45 +05301589 // get bmc execution context
1590 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1591 ipmi::firmware::cmdGetBmcExecutionContext,
1592 ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
1593
1594 // Get Firmware Update Random number
1595 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1596 ipmi::firmware::cmdGetFwUpdateRandomNumber,
1597 ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
1598
1599 // Set Firmware Update Mode
1600 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1601 ipmi::firmware::cmdSetFirmwareUpdateMode,
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301602 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001603
AppaRao Puli28972062019-11-11 02:04:45 +05301604 // Exit Firmware Update Mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001605 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
AppaRao Puli28972062019-11-11 02:04:45 +05301606 ipmi::firmware::cmdExitFirmwareUpdateMode,
1607 ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001608
AppaRao Puli28972062019-11-11 02:04:45 +05301609 // Get/Set Firmware Update Control
1610 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1611 ipmi::firmware::cmdGetSetFwUpdateControl,
1612 ipmi::Privilege::Admin,
1613 ipmiGetSetFirmwareUpdateControl);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001614
AppaRao Puli28972062019-11-11 02:04:45 +05301615 // Get Firmware Update Status
1616 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1617 ipmi::firmware::cmdGetFirmwareUpdateStatus,
1618 ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001619
AppaRao Puli28972062019-11-11 02:04:45 +05301620 // Set Firmware Update Options
1621 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1622 ipmi::firmware::cmdSetFirmwareUpdateOptions,
1623 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001624 // write image data
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301625 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1626 ipmi::firmware::cmdFwImageWriteData,
1627 ipmi::Privilege::Admin, ipmiFwImageWriteData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001628 return;
1629}