blob: afb1662a04c7b0adf7f4102cc965d7994cb6c7b1 [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{
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800761 constexpr uint8_t undefinedImage = 0x00;
AppaRao Puli28972062019-11-11 02:04:45 +0530762 constexpr uint8_t primaryImage = 0x01;
763 constexpr uint8_t secondaryImage = 0x02;
764 constexpr const char *secondaryFitImageStartAddr = "22480000";
765
766 uint8_t bootImage = primaryImage;
767 boost::system::error_code ec;
768 std::string value = ctx->bus->yield_method_call<std::string>(
769 ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
770 "/xyz/openbmc_project/u_boot/environment/mgr",
771 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
772 if (ec)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700773 {
AppaRao Puli28972062019-11-11 02:04:45 +0530774 phosphor::logging::log<phosphor::logging::level::ERR>(
775 "Failed to read the bootcmd value");
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800776 /* don't fail, just give back undefined until it is ready */
777 bootImage = undefinedImage;
AppaRao Puli28972062019-11-11 02:04:45 +0530778 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700779
AppaRao Puli28972062019-11-11 02:04:45 +0530780 /* cheking for secondary FitImage Address 22480000 */
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800781 else if (value.find(secondaryFitImageStartAddr) != std::string::npos)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700782 {
AppaRao Puli28972062019-11-11 02:04:45 +0530783 bootImage = secondaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700784 }
785 else
786 {
AppaRao Puli28972062019-11-11 02:04:45 +0530787 bootImage = primaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700788 }
789
AppaRao Puli28972062019-11-11 02:04:45 +0530790 return bootImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700791}
792
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530793#ifdef INTEL_PFR_ENABLED
794using fwVersionInfoType = std::tuple<uint8_t, // ID Tag
795 uint8_t, // Major Version Number
796 uint8_t, // Minor Version Number
797 uint32_t, // Build Number
798 uint32_t, // Build Timestamp
799 uint32_t>; // Update Timestamp
800ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700801{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700802 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530803 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700804 // Bytes - 17:(15xN) - Repeat of 2 through 16
805
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530806 std::vector<fwVersionInfoType> fwVerInfoList;
807 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
808 for (const auto &fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700809 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530810 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700811 try
812 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530813 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700814
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530815 ipmi::Value result = ipmi::getDbusProperty(
816 *busp, service, fwDev.second, versionIntf, "Version");
817 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700818 }
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530819 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700820 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530821 phosphor::logging::log<phosphor::logging::level::INFO>(
822 "Failed to fetch Version property",
823 phosphor::logging::entry("ERROR=%s", e.what()),
824 phosphor::logging::entry("PATH=%s", fwDev.second),
825 phosphor::logging::entry("INTERFACE=%s", versionIntf));
826 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700827 }
828
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530829 if (verStr.empty())
830 {
831 phosphor::logging::log<phosphor::logging::level::INFO>(
832 "Version is empty.",
833 phosphor::logging::entry("PATH=%s", fwDev.second),
834 phosphor::logging::entry("INTERFACE=%s", versionIntf));
835 continue;
836 }
837
838 // BMC Version format: <major>.<minor>-<build bum>-<build hash>
839 std::vector<std::string> splitVer;
840 boost::split(splitVer, verStr, boost::is_any_of(".-"));
841 if (splitVer.size() < 3)
842 {
843 phosphor::logging::log<phosphor::logging::level::INFO>(
844 "Invalid Version format.",
845 phosphor::logging::entry("Version=%s", verStr.c_str()),
846 phosphor::logging::entry("PATH=%s", fwDev.second));
847 continue;
848 }
849
850 uint8_t majorNum = 0;
851 uint8_t minorNum = 0;
852 uint32_t buildNum = 0;
853 try
854 {
855 majorNum = std::stoul(splitVer[0], nullptr, 16);
856 minorNum = std::stoul(splitVer[1], nullptr, 16);
857 buildNum = std::stoul(splitVer[2], nullptr, 16);
858 }
859 catch (const std::exception &e)
860 {
861 phosphor::logging::log<phosphor::logging::level::INFO>(
862 "Failed to convert stoul.",
863 phosphor::logging::entry("ERROR=%s", e.what()));
864 continue;
865 }
866
867 // Build Timestamp - Not supported.
868 // Update Timestamp - TODO: Need to check with CPLD team.
869 fwVerInfoList.emplace_back(
870 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
871 minorNum, buildNum, 0, 0));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700872 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700873
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530874 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700875}
AppaRao Puli28972062019-11-11 02:04:45 +0530876using fwSecurityVersionInfoType = std::tuple<uint8_t, // ID Tag
877 uint8_t, // BKC Version
878 uint8_t>; // SVN Version
879ipmi::RspType<uint8_t, std::vector<fwSecurityVersionInfoType>>
880 ipmiGetFwSecurityVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700881{
AppaRao Puli28972062019-11-11 02:04:45 +0530882 // TODO: Need to add support.
883 return ipmi::responseInvalidCommand();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700884}
885
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530886ipmi::RspType<std::array<uint8_t, certKeyLen>,
887 std::optional<std::array<uint8_t, cskSignatureLen>>>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530888 ipmiGetFwRootCertData(const ipmi::Context::ptr &ctx, uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700889{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530890 bool isIPMBChannel = false;
891
892 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
893 {
894 return ipmi::responseUnspecifiedError();
895 }
896 if (isIPMBChannel)
897 {
898 phosphor::logging::log<phosphor::logging::level::INFO>(
899 "Command not supported. Failed to get root certificate data.");
900 return ipmi::responseCommandNotAvailable();
901 }
902
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530903 size_t certKeyOffset = 0;
904 size_t cskSigOffset = 0;
905 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700906
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530907 switch (static_cast<FwGetRootCertDataTag>(certId))
908 {
909 case FwGetRootCertDataTag::activeRootKey:
910 {
911 mtdDev = bmcActivePfmMTDDev;
912 certKeyOffset = rootkeyOffsetInPfm;
913 break;
914 }
915 case FwGetRootCertDataTag::recoveryRootKey:
916 {
917 mtdDev = bmcRecoveryImgMTDDev;
918 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
919 break;
920 }
921 case FwGetRootCertDataTag::activeCSK:
922 {
923 mtdDev = bmcActivePfmMTDDev;
924 certKeyOffset = cskKeyOffsetInPfm;
925 cskSigOffset = cskSignatureOffsetInPfm;
926 break;
927 }
928 case FwGetRootCertDataTag::recoveryCSK:
929 {
930 mtdDev = bmcRecoveryImgMTDDev;
931 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
932 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
933 break;
934 }
935 default:
936 {
937 return ipmi::responseInvalidFieldRequest();
938 }
939 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700940
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530941 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700942
Vernon Mauery52ce6622019-05-22 09:19:46 -0700943 try
944 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530945 SPIDev spiDev(mtdDev);
946 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
947
948 if (cskSigOffset)
949 {
950 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
951 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
952 cskSignature.data());
953 return ipmi::responseSuccess(certKey, cskSignature);
954 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700955 }
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530956 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700957 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530958 phosphor::logging::log<phosphor::logging::level::ERR>(
959 "Exception caught in ipmiGetFwRootCertData",
960 phosphor::logging::entry("MSG=%s", e.what()));
961 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700962 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700963
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530964 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700965}
AppaRao Puli28972062019-11-11 02:04:45 +0530966#endif // INTEL_PFR_ENABLED
967
968static constexpr uint8_t channelListSize = 3;
969/** @brief implements Maximum Firmware Transfer size command
970 * @parameter
971 * - none
972 * @returns IPMI completion code plus response data
973 * - count - channel count
974 * - channelList - channel list information
975 */
976ipmi::RspType<uint8_t, // channel count
977 std::array<std::tuple<uint8_t, uint32_t>,
978 channelListSize> // Channel List
979 >
980 ipmiFirmwareMaxTransferSize()
981{
982 constexpr size_t kcsMaxBufSize = 128;
983 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
AppaRao Puli28972062019-11-11 02:04:45 +0530984 // Byte 1 - Count (N) Number of devices data is being returned for.
985 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
986 // Byte 3-6 - transfer size (little endian)
987 // Bytes - 7:(5xN) - Repeat of 2 through 6
988 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
989 channelList = {
990 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
AppaRao Puli28972062019-11-11 02:04:45 +0530991 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
992 rmcpPlusMaxBufSize}}};
993
994 return ipmi::responseSuccess(channelListSize, channelList);
995}
996
997ipmi::RspType<uint8_t, uint8_t>
998 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
999{
1000 // Byte 1 - Current execution context
1001 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
1002 // Byte 2 - Partition pointer
1003 // 0x01 - primary, 0x02 - secondary
1004 uint8_t partitionPtr = getActiveBootImage(ctx);
1005
1006 return ipmi::responseSuccess(
1007 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
1008}
AppaRao Puli28972062019-11-11 02:04:45 +05301009/** @brief Get Firmware Update Random Number
1010 *
1011 * This function generate the random number used for
1012 * setting the firmware update mode as authentication key.
1013 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301014 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301015 * @returns IPMI completion code along with
1016 * - random number
1017 **/
1018ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301019 ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr &ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301020{
1021 phosphor::logging::log<phosphor::logging::level::INFO>(
1022 "Generate FW update random number");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301023 bool isIPMBChannel = false;
1024
1025 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1026 {
1027 return ipmi::responseUnspecifiedError();
1028 }
1029 if (isIPMBChannel)
1030 {
1031 phosphor::logging::log<phosphor::logging::level::INFO>(
1032 "Channel not supported. Failed to fetch FW update random number");
1033 return ipmi::responseCommandNotAvailable();
1034 }
AppaRao Puli28972062019-11-11 02:04:45 +05301035 std::random_device rd;
1036 std::default_random_engine gen(rd());
1037 std::uniform_int_distribution<> dist{0, 255};
1038
1039 fwRandomNumGenTs = std::chrono::steady_clock::now();
1040
1041 for (int i = 0; i < fwRandomNumLength; i++)
1042 {
1043 fwRandomNum[i] = dist(gen);
1044 }
1045
1046 return ipmi::responseSuccess(fwRandomNum);
1047}
1048
1049/** @brief Set Firmware Update Mode
1050 *
1051 * This function sets BMC into firmware update mode
1052 * after validating Random number obtained from the Get
1053 * Firmware Update Random Number command
1054 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301055 * @param[in] ctx - context of current session
1056 * @parameter randNum - Random number(token)
1057 * @returns IPMI completion code
AppaRao Puli28972062019-11-11 02:04:45 +05301058 **/
1059ipmi::RspType<>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301060 ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr &ctx,
1061 std::array<uint8_t, fwRandomNumLength> &randNum)
AppaRao Puli28972062019-11-11 02:04:45 +05301062{
1063 phosphor::logging::log<phosphor::logging::level::INFO>(
1064 "Start FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301065
1066 bool isIPMBChannel = false;
1067
1068 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1069 {
1070 return ipmi::responseUnspecifiedError();
1071 }
1072 if (isIPMBChannel)
1073 {
1074 phosphor::logging::log<phosphor::logging::level::INFO>(
1075 "Channel not supported. Failed to set FW update mode");
1076 return ipmi::responseCommandNotAvailable();
1077 }
AppaRao Puli28972062019-11-11 02:04:45 +05301078 /* Firmware Update Random number is valid for 30 seconds only */
1079 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1080 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1081 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1082 fwRandomNumExpirySeconds)
1083 .count())
1084 {
1085 phosphor::logging::log<phosphor::logging::level::INFO>(
1086 "Firmware update random number expired.");
1087 return ipmi::responseInvalidFieldRequest();
1088 }
1089
1090 /* Validate random number */
1091 for (int i = 0; i < fwRandomNumLength; i++)
1092 {
1093 if (fwRandomNum[i] != randNum[i])
1094 {
1095 phosphor::logging::log<phosphor::logging::level::INFO>(
1096 "Invalid random number specified.");
1097 return ipmi::responseInvalidFieldRequest();
1098 }
1099 }
1100
1101 try
1102 {
1103 if (getFirmwareUpdateMode())
1104 {
1105 phosphor::logging::log<phosphor::logging::level::INFO>(
1106 "Already firmware update is in progress.");
1107 return ipmi::responseBusy();
1108 }
1109 }
1110 catch (const std::exception &e)
1111 {
1112 return ipmi::responseUnspecifiedError();
1113 }
1114
1115 // FIXME? c++ doesn't off an option for exclusive file creation
1116 FILE *fp = fopen(firmwareBufferFile, "wx");
1117 if (!fp)
1118 {
1119 phosphor::logging::log<phosphor::logging::level::INFO>(
1120 "Unable to open file.");
1121 return ipmi::responseUnspecifiedError();
1122 }
1123 fclose(fp);
1124
1125 try
1126 {
1127 setFirmwareUpdateMode(true);
1128 }
1129 catch (const std::exception &e)
1130 {
1131 unlink(firmwareBufferFile);
1132 return ipmi::responseUnspecifiedError();
1133 }
1134
1135 return ipmi::responseSuccess();
1136}
1137
1138/** @brief implements exit firmware update mode command
1139 * @param None
1140 *
1141 * @returns IPMI completion code
1142 */
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301143ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr &ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301144{
1145 phosphor::logging::log<phosphor::logging::level::INFO>(
1146 "Exit FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301147 bool isIPMBChannel = false;
1148
1149 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1150 {
1151 return ipmi::responseUnspecifiedError();
1152 }
1153 if (isIPMBChannel)
1154 {
1155 phosphor::logging::log<phosphor::logging::level::INFO>(
1156 "Command not supported. Failed to exit firmware update mode");
1157 return ipmi::responseCommandNotAvailable();
1158 }
1159
AppaRao Puli28972062019-11-11 02:04:45 +05301160 switch (fwUpdateStatus.getState())
1161 {
1162 case FwUpdateStatusCache::fwStateInit:
1163 case FwUpdateStatusCache::fwStateIdle:
1164 return ipmi::responseInvalidFieldRequest();
1165 break;
1166 case FwUpdateStatusCache::fwStateDownload:
1167 case FwUpdateStatusCache::fwStateVerify:
1168 break;
1169 case FwUpdateStatusCache::fwStateProgram:
1170 break;
1171 case FwUpdateStatusCache::fwStateUpdateSuccess:
1172 case FwUpdateStatusCache::fwStateError:
1173 break;
1174 case FwUpdateStatusCache::fwStateAcCycleRequired:
1175 return ipmi::responseInvalidFieldRequest();
1176 break;
1177 }
1178 fwUpdateStatus.firmwareUpdateAbortState();
1179
1180 try
1181 {
1182 setFirmwareUpdateMode(false);
1183 }
1184 catch (const std::exception &e)
1185 {
1186 return ipmi::responseUnspecifiedError();
1187 }
1188
1189 return ipmi::responseSuccess();
1190}
1191
1192/** @brief implements Get/Set Firmware Update Control
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301193 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301194 * @parameter
1195 * - Byte 1: Control Byte
1196 * - Byte 2: Firmware filename length (Optional)
1197 * - Byte 3:N: Firmware filename data (Optional)
1198 * @returns IPMI completion code plus response data
1199 * - Byte 2: Current control status
1200 **/
1201ipmi::RspType<bool, bool, bool, bool, uint4_t>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301202 ipmiGetSetFirmwareUpdateControl(const ipmi::Context::ptr &ctx,
1203 const uint8_t controlReq,
AppaRao Puli28972062019-11-11 02:04:45 +05301204 const std::optional<std::string> &fileName)
1205{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301206 bool isIPMBChannel = false;
1207
1208 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1209 {
1210 return ipmi::responseUnspecifiedError();
1211 }
1212 if (isIPMBChannel)
1213 {
1214 phosphor::logging::log<phosphor::logging::level::INFO>(
1215 "Channel not supported. Failed to get or set FW update control");
1216 return ipmi::responseCommandNotAvailable();
1217 }
1218
AppaRao Puli28972062019-11-11 02:04:45 +05301219 static std::string fwXferUriPath;
1220 static bool imageTransferStarted = false;
1221 static bool imageTransferCompleted = false;
1222 static bool imageTransferAborted = false;
1223
1224 if ((controlReq !=
1225 static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
1226 (fileName))
1227 {
1228 phosphor::logging::log<phosphor::logging::level::ERR>(
1229 "Invalid request field (Filename).");
1230 return ipmi::responseInvalidFieldRequest();
1231 }
1232
1233 static bool usbAttached = getUsbStatus();
1234
1235 switch (static_cast<FwUpdateCtrlReq>(controlReq))
1236 {
1237 case FwUpdateCtrlReq::getCurrentControlStatus:
1238 phosphor::logging::log<phosphor::logging::level::INFO>(
1239 "ipmiGetSetFirmwareUpdateControl: Get status");
1240 break;
1241 case FwUpdateCtrlReq::imageTransferStart:
1242 {
1243 phosphor::logging::log<phosphor::logging::level::INFO>(
1244 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
1245 imageTransferStarted = true;
1246 // reset buffer to empty (truncate file)
1247 std::ofstream out(firmwareBufferFile,
1248 std::ofstream::binary | std::ofstream::trunc);
1249 fwXferUriPath = std::string("file://") + firmwareBufferFile;
1250 if (xferHashCheck)
1251 {
1252 xferHashCheck->clear();
1253 }
1254 // Setting state to download
1255 fwUpdateStatus.setState(
1256 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
1257#ifdef INTEL_PFR_ENABLED
1258 imgLength = 0;
1259 imgType = 0;
1260 block0Mapped = false;
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301261#endif
AppaRao Puli28972062019-11-11 02:04:45 +05301262 }
1263 break;
1264 case FwUpdateCtrlReq::imageTransferComplete:
1265 {
1266 phosphor::logging::log<phosphor::logging::level::INFO>(
1267 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
1268 if (usbAttached)
1269 {
1270 phosphor::logging::log<phosphor::logging::level::ERR>(
1271 "USB should be detached to perform this operation.");
1272 return ipmi::responseNotSupportedInPresentState();
1273 }
1274 // finish transfer based on URI
1275 if (!transferFirmwareFromUri(fwXferUriPath))
1276 {
1277 phosphor::logging::log<phosphor::logging::level::ERR>(
1278 "transferFirmwareFromUri failed.");
1279 return ipmi::responseUnspecifiedError();
1280 }
1281 // transfer complete
1282 if (xferHashCheck)
1283 {
1284 if (TransferHashCheck::HashCheck::sha2Success !=
1285 xferHashCheck->verify())
1286 {
1287 phosphor::logging::log<phosphor::logging::level::ERR>(
1288 "xferHashCheck failed.");
1289 return ipmi::responseUnspecifiedError();
1290 }
1291 }
1292 // Set state to verify and start the update
1293 fwUpdateStatus.setState(
1294 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
1295 // start the request
1296 if (!startFirmwareUpdate(firmwareBufferFile))
1297 {
1298 phosphor::logging::log<phosphor::logging::level::ERR>(
1299 "startFirmwareUpdate failed.");
1300 return ipmi::responseUnspecifiedError();
1301 }
1302 imageTransferCompleted = true;
1303 }
1304 break;
1305 case FwUpdateCtrlReq::imageTransferAbort:
1306 phosphor::logging::log<phosphor::logging::level::INFO>(
1307 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
1308 if (usbAttached)
1309 {
1310 if (detachUsbDevice())
1311 {
1312 phosphor::logging::log<phosphor::logging::level::ERR>(
1313 "Detach USB device failed.");
1314 return ipmi::responseUsbAttachOrDetachFailed();
1315 }
1316 usbAttached = false;
1317 }
1318 // During abort request reset the state to Init by cleaning update
1319 // file.
1320 fwUpdateStatus.firmwareUpdateAbortState();
1321 imageTransferAborted = true;
1322 break;
1323 case FwUpdateCtrlReq::setFirmwareFilename:
1324 phosphor::logging::log<phosphor::logging::level::INFO>(
1325 "ipmiGetSetFirmwareUpdateControl: Set filename.");
1326 if (!fileName || ((*fileName).length() == 0))
1327 {
1328 phosphor::logging::log<phosphor::logging::level::ERR>(
1329 "Invalid Filename specified.");
1330 return ipmi::responseInvalidFieldRequest();
1331 }
1332
1333 fwXferUriPath = *fileName;
1334 break;
1335 case FwUpdateCtrlReq::attachUsbDevice:
1336 phosphor::logging::log<phosphor::logging::level::INFO>(
1337 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
1338 if (usbAttached)
1339 {
1340 phosphor::logging::log<phosphor::logging::level::ERR>(
1341 "USB device is already attached.");
1342 return ipmi::responseInvalidFieldRequest();
1343 }
1344 if (attachUsbDevice())
1345 {
1346 phosphor::logging::log<phosphor::logging::level::ERR>(
1347 "Attach USB device failed.");
1348 return ipmi::responseUsbAttachOrDetachFailed();
1349 }
1350 usbAttached = true;
1351 break;
1352 case FwUpdateCtrlReq::detachUsbDevice:
1353 phosphor::logging::log<phosphor::logging::level::INFO>(
1354 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
1355 if (!usbAttached)
1356 {
1357 phosphor::logging::log<phosphor::logging::level::ERR>(
1358 "USB device is not attached.");
1359 return ipmi::responseInvalidFieldRequest();
1360 }
1361 if (detachUsbDevice())
1362 {
1363 phosphor::logging::log<phosphor::logging::level::ERR>(
1364 "Detach USB device failed.");
1365 return ipmi::responseUsbAttachOrDetachFailed();
1366 }
1367 usbAttached = false;
1368 break;
1369 default:
1370 phosphor::logging::log<phosphor::logging::level::ERR>(
1371 "Invalid control option specified.");
1372 return ipmi::responseInvalidFieldRequest();
1373 }
1374
1375 return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
1376 imageTransferAborted, usbAttached, uint4_t(0));
1377}
1378
1379/** @brief implements firmware get status command
1380 * @parameter
1381 * - none
1382 * @returns IPMI completion code plus response data
1383 * - status - processing status
1384 * - percentage - percentage completion
1385 * - check - channel integrity check status
1386 **/
1387ipmi::RspType<uint8_t, // status
1388 uint8_t, // percentage
1389 uint8_t // check
1390 >
1391 ipmiGetFirmwareUpdateStatus()
1392
1393{
1394 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1395 // 5=ready, f=error, 83=ac cycle required)
1396 // Byte 2 - percent
1397 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
1398 uint8_t status = fwUpdateStatus.getState();
1399 uint8_t percent = fwUpdateStatus.percent();
1400 uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
1401
1402 // Status code.
1403 return ipmi::responseSuccess(status, percent, check);
1404}
1405
1406ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301407 const ipmi::Context::ptr &ctx, bool noDowngradeMask, bool deferRestartMask,
1408 bool sha2CheckMask, uint5_t reserved1, bool noDowngrade, bool deferRestart,
1409 bool sha2Check, uint5_t reserved2,
1410 std::optional<std::vector<uint8_t>> integrityCheckVal)
AppaRao Puli28972062019-11-11 02:04:45 +05301411{
1412 phosphor::logging::log<phosphor::logging::level::INFO>(
1413 "Set firmware update options.");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301414 bool isIPMBChannel = false;
1415
1416 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1417 {
1418 return ipmi::responseUnspecifiedError();
1419 }
1420 if (isIPMBChannel)
1421 {
1422 phosphor::logging::log<phosphor::logging::level::INFO>(
1423 "Channel not supported. Failed to set firmware update options");
1424 return ipmi::responseCommandNotAvailable();
1425 }
AppaRao Puli28972062019-11-11 02:04:45 +05301426 bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
1427 bool deferRestartState = fwUpdateStatus.getDeferRestart();
1428 bool sha2CheckState = xferHashCheck ? true : false;
1429
1430 if (noDowngradeMask && (noDowngradeState != noDowngrade))
1431 {
1432 fwUpdateStatus.setInhibitDowngrade(noDowngrade);
1433 noDowngradeState = noDowngrade;
1434 }
1435 if (deferRestartMask && (deferRestartState != deferRestart))
1436 {
1437 fwUpdateStatus.setDeferRestart(deferRestart);
1438 deferRestartState = deferRestart;
1439 }
1440 if (sha2CheckMask)
1441 {
1442 if (sha2Check)
1443 {
1444 auto hashSize = EVP_MD_size(EVP_sha256());
1445 if ((*integrityCheckVal).size() != hashSize)
1446 {
1447 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1448 "Invalid size of Hash specified.");
1449 return ipmi::responseInvalidFieldRequest();
1450 }
1451 xferHashCheck = std::make_shared<TransferHashCheck>();
1452 xferHashCheck->init(*integrityCheckVal);
1453 }
1454 else
1455 {
1456 // delete the xferHashCheck object
1457 xferHashCheck.reset();
1458 }
1459 sha2CheckState = sha2CheckMask;
1460 }
1461 return ipmi::responseSuccess(noDowngradeState, deferRestartState,
1462 sha2CheckState, reserved1);
1463}
Vernon Mauery52ce6622019-05-22 09:19:46 -07001464
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301465ipmi::RspType<uint32_t>
1466 ipmiFwImageWriteData(const std::vector<uint8_t> &writeData)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001467{
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301468 const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
1469 size_t writeDataLen = writeData.size();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001470
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301471 if (!writeDataLen)
1472 {
1473 return ipmi::responseReqDataLenInvalid();
1474 }
1475
AppaRao Puli28972062019-11-11 02:04:45 +05301476 if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301477 {
AppaRao Puli28972062019-11-11 02:04:45 +05301478 phosphor::logging::log<phosphor::logging::level::ERR>(
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301479 "Invalid firmware update state.");
1480 return ipmi::response(ccCmdNotSupportedInPresentState);
1481 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001482
AppaRao Puli28972062019-11-11 02:04:45 +05301483 std::ofstream out(firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001484 std::ofstream::binary | std::ofstream::app);
1485 if (!out)
1486 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301487 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1488 "Error while opening file.");
1489 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001490 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301491
1492 uint64_t fileDataLen = out.tellp();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301493
AppaRao Puli28972062019-11-11 02:04:45 +05301494 if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001495 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301496 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1497 "Firmware image size exceeds the limit");
1498 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001499 }
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301500
1501 const char *data = reinterpret_cast<const char *>(writeData.data());
1502 out.write(data, writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001503 out.close();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301504
AppaRao Puli28972062019-11-11 02:04:45 +05301505 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001506 {
AppaRao Puli28972062019-11-11 02:04:45 +05301507 xferHashCheck->hash(writeData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001508 }
1509
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301510#ifdef INTEL_PFR_ENABLED
1511 /* PFR image block 0 - As defined in HAS */
1512 struct PFRImageBlock0
1513 {
1514 uint32_t tag;
1515 uint32_t pcLength;
1516 uint32_t pcType;
1517 uint32_t reserved1;
1518 uint8_t hash256[32];
1519 uint8_t hash384[48];
1520 uint8_t reserved2[32];
1521 } __attribute__((packed));
1522
1523 /* Get the PFR block 0 data and read the uploaded image
1524 * information( Image type, length etc) */
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301525 if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
1526 (!block0Mapped))
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301527 {
1528 struct PFRImageBlock0 block0Data = {0};
1529
AppaRao Puli28972062019-11-11 02:04:45 +05301530 std::ifstream inFile(firmwareBufferFile,
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301531 std::ios::binary | std::ios::in);
1532 inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
1533 inFile.close();
1534
1535 uint32_t magicNum = block0Data.tag;
1536
1537 /* Validate the magic number */
1538 if (magicNum != perBlock0MagicNum)
1539 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301540 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1541 "PFR image magic number not matched");
1542 return ipmi::responseInvalidFieldRequest();
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301543 }
1544 // Note:imgLength, imgType and block0Mapped are in global scope, as
1545 // these are used in cascaded updates.
1546 imgLength = block0Data.pcLength;
1547 imgType = block0Data.pcType;
1548 block0Mapped = true;
1549 }
1550#endif // end of INTEL_PFR_ENABLED
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301551 return ipmi::responseSuccess(writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001552}
1553
AppaRao Puli28972062019-11-11 02:04:45 +05301554static void registerFirmwareFunctions()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001555{
1556 // guarantee that we start with an already timed out timestamp
AppaRao Puli28972062019-11-11 02:04:45 +05301557 fwRandomNumGenTs =
1558 std::chrono::steady_clock::now() - fwRandomNumExpirySeconds;
1559 fwUpdateStatus.setState(
1560 static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001561
AppaRao Puli28972062019-11-11 02:04:45 +05301562 unlink(firmwareBufferFile);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001563
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301564#ifdef INTEL_PFR_ENABLED
1565 // Following commands are supported only for PFR enabled platforms
1566 // CMD:0x20 - Get Firmware Version Information
AppaRao Puli28972062019-11-11 02:04:45 +05301567 // CMD:0x21 - Get Firmware Security Version Information
1568 // CMD:0x25 - Get Root Certificate Data
Vernon Mauery52ce6622019-05-22 09:19:46 -07001569
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301570 // get firmware version information
1571 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1572 ipmi::firmware::cmdGetFwVersionInfo,
1573 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
AppaRao Puli28972062019-11-11 02:04:45 +05301574
Vernon Mauery52ce6622019-05-22 09:19:46 -07001575 // get firmware security version information
AppaRao Puli28972062019-11-11 02:04:45 +05301576 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1577 ipmi::firmware::cmdGetFwSecurityVersionInfo,
1578 ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001579
Vernon Mauery52ce6622019-05-22 09:19:46 -07001580 // get root certificate data
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301581 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1582 ipmi::firmware::cmdFwGetRootCertData,
1583 ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1584#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001585
AppaRao Puli28972062019-11-11 02:04:45 +05301586 // get firmware update channel information (max transfer sizes)
1587 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1588 ipmi::firmware::cmdGetFwUpdateChannelInfo,
1589 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001590
AppaRao Puli28972062019-11-11 02:04:45 +05301591 // get bmc execution context
1592 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1593 ipmi::firmware::cmdGetBmcExecutionContext,
1594 ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
1595
1596 // Get Firmware Update Random number
1597 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1598 ipmi::firmware::cmdGetFwUpdateRandomNumber,
1599 ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
1600
1601 // Set Firmware Update Mode
1602 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1603 ipmi::firmware::cmdSetFirmwareUpdateMode,
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301604 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001605
AppaRao Puli28972062019-11-11 02:04:45 +05301606 // Exit Firmware Update Mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001607 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
AppaRao Puli28972062019-11-11 02:04:45 +05301608 ipmi::firmware::cmdExitFirmwareUpdateMode,
1609 ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001610
AppaRao Puli28972062019-11-11 02:04:45 +05301611 // Get/Set Firmware Update Control
1612 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1613 ipmi::firmware::cmdGetSetFwUpdateControl,
1614 ipmi::Privilege::Admin,
1615 ipmiGetSetFirmwareUpdateControl);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001616
AppaRao Puli28972062019-11-11 02:04:45 +05301617 // Get Firmware Update Status
1618 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1619 ipmi::firmware::cmdGetFirmwareUpdateStatus,
1620 ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001621
AppaRao Puli28972062019-11-11 02:04:45 +05301622 // Set Firmware Update Options
1623 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1624 ipmi::firmware::cmdSetFirmwareUpdateOptions,
1625 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001626 // write image data
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301627 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1628 ipmi::firmware::cmdFwImageWriteData,
1629 ipmi::Privilege::Admin, ipmiFwImageWriteData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001630 return;
1631}