blob: d3236d53155bca96849b3aafc745541e8a19fe0f [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;
395 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 Puli28972062019-11-11 02:04:45 +0530516static void postTransferCompleteHandler(
517 std::unique_ptr<sdbusplus::bus::match::match> &fwUpdateMatchSignal)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700518{
519 // Setup timer for watching signal
520 static phosphor::Timer timer(
AppaRao Puli28972062019-11-11 02:04:45 +0530521 [&fwUpdateMatchSignal]() { fwUpdateMatchSignal = nullptr; });
Vernon Mauery52ce6622019-05-22 09:19:46 -0700522
AppaRao Puli28972062019-11-11 02:04:45 +0530523 static phosphor::Timer activationStatusTimer([]() {
524 if (fwUpdateStatus.activationTimerTimeout() >= 95)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700525 {
AppaRao Puli28972062019-11-11 02:04:45 +0530526 activationStatusTimer.stop();
527 fwUpdateStatus.setState(
528 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700529 }
530 });
531
532 timer.start(std::chrono::microseconds(5000000), false);
533
534 // callback function for capturing signal
AppaRao Puli28972062019-11-11 02:04:45 +0530535 auto callback = [&](sdbusplus::message::message &m) {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700536 bool flag = false;
537
538 std::vector<std::pair<
539 std::string,
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700540 std::vector<std::pair<std::string, std::variant<std::string>>>>>
AppaRao Puli28972062019-11-11 02:04:45 +0530541 intfPropsPair;
542 sdbusplus::message::object_path objPath;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700543
544 try
545 {
AppaRao Puli28972062019-11-11 02:04:45 +0530546 m.read(objPath, intfPropsPair); // Read in the object path
547 // that was just created
Vernon Mauery52ce6622019-05-22 09:19:46 -0700548 }
AppaRao Puli28972062019-11-11 02:04:45 +0530549 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700550 {
AppaRao Puli28972062019-11-11 02:04:45 +0530551 phosphor::logging::log<phosphor::logging::level::ERR>(
552 "Exception caught in reading created object path.");
553 return;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700554 }
555 // constructing response message
AppaRao Puli28972062019-11-11 02:04:45 +0530556 phosphor::logging::log<phosphor::logging::level::INFO>(
557 "New Interface Added.",
558 phosphor::logging::entry("OBJPATH=%s", objPath.str.c_str()));
559 for (auto &interface : intfPropsPair)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700560 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700561 if (interface.first == "xyz.openbmc_project.Software.Activation")
562 {
AppaRao Puli28972062019-11-11 02:04:45 +0530563 // There are chances of getting two signals for
564 // InterfacesAdded. So cross check and discrad second instance.
565 if (fwUpdateMatchSignal == nullptr)
566 {
567 return;
568 }
569 // Found our interface, disable callbacks
570 fwUpdateMatchSignal = nullptr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700571
AppaRao Puli28972062019-11-11 02:04:45 +0530572 phosphor::logging::log<phosphor::logging::level::INFO>(
573 "Start activationStatusTimer for status.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700574 try
575 {
576 timer.stop();
AppaRao Puli28972062019-11-11 02:04:45 +0530577 activationStatusTimer.start(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700578 std::chrono::microseconds(3000000), true);
579 }
AppaRao Puli28972062019-11-11 02:04:45 +0530580 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700581 {
AppaRao Puli28972062019-11-11 02:04:45 +0530582 phosphor::logging::log<phosphor::logging::level::ERR>(
583 "Exception caught in start activationStatusTimer.",
584 phosphor::logging::entry("ERROR=%s", e.what()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700585 }
586
AppaRao Puli28972062019-11-11 02:04:45 +0530587 fwUpdateStatus.updateActivationPercent(objPath.str);
588 activateImage(objPath.str);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700589 }
590 }
591 };
592
593 // Adding matcher
AppaRao Puli28972062019-11-11 02:04:45 +0530594 fwUpdateMatchSignal = std::make_unique<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700595 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700596 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
597 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
598 callback);
599}
AppaRao Puli28972062019-11-11 02:04:45 +0530600static bool startFirmwareUpdate(const std::string &uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700601{
AppaRao Puli28972062019-11-11 02:04:45 +0530602 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
603 // the code gets to this point, the file should be transferred start the
604 // request (creating a new file in /tmp/images causes the update manager to
605 // check if it is ready for activation)
606 static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatchSignal;
607 postTransferCompleteHandler(fwUpdateMatchSignal);
608 std::filesystem::rename(
609 uri, "/tmp/images/" +
610 boost::uuids::to_string(boost::uuids::random_generator()()));
611 return true;
612}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700613
AppaRao Puli28972062019-11-11 02:04:45 +0530614static int transferImageFromFile(const std::string &uri, bool move = true)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700615{
616 std::error_code ec;
AppaRao Puli28972062019-11-11 02:04:45 +0530617 phosphor::logging::log<phosphor::logging::level::INFO>(
618 "Transfer Image From File.",
619 phosphor::logging::entry("URI=%s", uri.c_str()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700620 if (move)
621 {
AppaRao Puli28972062019-11-11 02:04:45 +0530622 std::filesystem::rename(uri, firmwareBufferFile, ec);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700623 }
624 else
625 {
AppaRao Puli28972062019-11-11 02:04:45 +0530626 std::filesystem::copy(uri, firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700627 std::filesystem::copy_options::overwrite_existing,
628 ec);
629 }
AppaRao Puli28972062019-11-11 02:04:45 +0530630 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700631 {
632 MappedFile mappedfw(uri);
AppaRao Puli28972062019-11-11 02:04:45 +0530633 xferHashCheck->hash(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700634 {mappedfw.data(), mappedfw.data() + mappedfw.size()});
635 }
636 if (ec.value())
637 {
AppaRao Puli28972062019-11-11 02:04:45 +0530638 phosphor::logging::log<phosphor::logging::level::ERR>(
639 "Image copy failed.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700640 }
641 return ec.value();
642}
643
644template <typename... ArgTypes>
645static int executeCmd(const char *path, ArgTypes &&... tArgs)
646{
647 boost::process::child execProg(path, const_cast<char *>(tArgs)...);
648 execProg.wait();
649 return execProg.exit_code();
650}
651
AppaRao Puli28972062019-11-11 02:04:45 +0530652static int transferImageFromUsb(const std::string &uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700653{
654 int ret, sysret;
655 char fwpath[fwPathMaxLength];
AppaRao Puli28972062019-11-11 02:04:45 +0530656 phosphor::logging::log<phosphor::logging::level::INFO>(
657 "Transfer Image From USB.",
658 phosphor::logging::entry("URI=%s", uri.c_str()));
659 ret = executeCmd(usbCtrlPath, "mount", fwUpdateUsbVolImage,
660 fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700661 if (ret)
662 {
663 return ret;
664 }
665
AppaRao Puli28972062019-11-11 02:04:45 +0530666 std::string usb_path = std::string(fwUpdateMountPoint) + "/" + uri;
667 ret = transferImageFromFile(usb_path, false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700668
AppaRao Puli28972062019-11-11 02:04:45 +0530669 executeCmd(usbCtrlPath, "cleanup", fwUpdateUsbVolImage, fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700670 return ret;
671}
672
AppaRao Puli28972062019-11-11 02:04:45 +0530673static bool transferFirmwareFromUri(const std::string &uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700674{
AppaRao Puli28972062019-11-11 02:04:45 +0530675 static constexpr char fwUriFile[] = "file://";
676 static constexpr char fwUriUsb[] = "usb://";
677 phosphor::logging::log<phosphor::logging::level::INFO>(
678 "Transfer Image From URI.",
679 phosphor::logging::entry("URI=%s", uri.c_str()));
680 if (boost::algorithm::starts_with(uri, fwUriFile))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700681 {
AppaRao Puli28972062019-11-11 02:04:45 +0530682 std::string fname = uri.substr(sizeof(fwUriFile) - 1);
683 if (fname != firmwareBufferFile)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700684 {
AppaRao Puli28972062019-11-11 02:04:45 +0530685 return 0 == transferImageFromFile(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700686 }
687 return true;
688 }
AppaRao Puli28972062019-11-11 02:04:45 +0530689 if (boost::algorithm::starts_with(uri, fwUriUsb))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700690 {
AppaRao Puli28972062019-11-11 02:04:45 +0530691 std::string fname = uri.substr(sizeof(fwUriUsb) - 1);
692 return 0 == transferImageFromUsb(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700693 }
694 return false;
695}
696
697/* Get USB-mass-storage device status: inserted => true, ejected => false */
AppaRao Puli28972062019-11-11 02:04:45 +0530698static bool getUsbStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700699{
AppaRao Puli28972062019-11-11 02:04:45 +0530700 std::filesystem::path usbDevPath =
701 std::filesystem::path("/sys/kernel/config/usb_gadget") /
702 fwUpdateUSBDevName;
703 return (std::filesystem::exists(usbDevPath) ? true : false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700704}
705
706/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530707static int attachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700708{
AppaRao Puli28972062019-11-11 02:04:45 +0530709 if (getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700710 {
711 return 1;
712 }
AppaRao Puli28972062019-11-11 02:04:45 +0530713 int ret = executeCmd(usbCtrlPath, "setup", fwUpdateUsbVolImage,
714 std::to_string(maxFirmwareImageSize / 1_MB).c_str());
Vernon Mauery52ce6622019-05-22 09:19:46 -0700715 if (!ret)
716 {
AppaRao Puli28972062019-11-11 02:04:45 +0530717 ret = executeCmd(usbCtrlPath, "insert", fwUpdateUSBDevName,
718 fwUpdateUsbVolImage);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700719 }
720 return ret;
721}
722
723/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530724static int detachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700725{
AppaRao Puli28972062019-11-11 02:04:45 +0530726 if (!getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700727 {
728 return 1;
729 }
AppaRao Puli28972062019-11-11 02:04:45 +0530730 return executeCmd(usbCtrlPath, "eject", fwUpdateUSBDevName);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700731}
AppaRao Puli28972062019-11-11 02:04:45 +0530732static uint8_t getActiveBootImage(ipmi::Context::ptr ctx)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700733{
AppaRao Puli28972062019-11-11 02:04:45 +0530734 constexpr uint8_t primaryImage = 0x01;
735 constexpr uint8_t secondaryImage = 0x02;
736 constexpr const char *secondaryFitImageStartAddr = "22480000";
737
738 uint8_t bootImage = primaryImage;
739 boost::system::error_code ec;
740 std::string value = ctx->bus->yield_method_call<std::string>(
741 ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
742 "/xyz/openbmc_project/u_boot/environment/mgr",
743 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
744 if (ec)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700745 {
AppaRao Puli28972062019-11-11 02:04:45 +0530746 phosphor::logging::log<phosphor::logging::level::ERR>(
747 "Failed to read the bootcmd value");
748 return ipmi::ccUnspecifiedError;
749 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700750
AppaRao Puli28972062019-11-11 02:04:45 +0530751 /* cheking for secondary FitImage Address 22480000 */
752 if (value.find(secondaryFitImageStartAddr) != std::string::npos)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700753 {
AppaRao Puli28972062019-11-11 02:04:45 +0530754 bootImage = secondaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700755 }
756 else
757 {
AppaRao Puli28972062019-11-11 02:04:45 +0530758 bootImage = primaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700759 }
760
AppaRao Puli28972062019-11-11 02:04:45 +0530761 return bootImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700762}
763
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530764#ifdef INTEL_PFR_ENABLED
765using fwVersionInfoType = std::tuple<uint8_t, // ID Tag
766 uint8_t, // Major Version Number
767 uint8_t, // Minor Version Number
768 uint32_t, // Build Number
769 uint32_t, // Build Timestamp
770 uint32_t>; // Update Timestamp
771ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700772{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700773 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530774 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700775 // Bytes - 17:(15xN) - Repeat of 2 through 16
776
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530777 std::vector<fwVersionInfoType> fwVerInfoList;
778 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
779 for (const auto &fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700780 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530781 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700782 try
783 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530784 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700785
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530786 ipmi::Value result = ipmi::getDbusProperty(
787 *busp, service, fwDev.second, versionIntf, "Version");
788 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700789 }
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530790 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700791 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530792 phosphor::logging::log<phosphor::logging::level::INFO>(
793 "Failed to fetch Version property",
794 phosphor::logging::entry("ERROR=%s", e.what()),
795 phosphor::logging::entry("PATH=%s", fwDev.second),
796 phosphor::logging::entry("INTERFACE=%s", versionIntf));
797 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700798 }
799
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530800 if (verStr.empty())
801 {
802 phosphor::logging::log<phosphor::logging::level::INFO>(
803 "Version is empty.",
804 phosphor::logging::entry("PATH=%s", fwDev.second),
805 phosphor::logging::entry("INTERFACE=%s", versionIntf));
806 continue;
807 }
808
809 // BMC Version format: <major>.<minor>-<build bum>-<build hash>
810 std::vector<std::string> splitVer;
811 boost::split(splitVer, verStr, boost::is_any_of(".-"));
812 if (splitVer.size() < 3)
813 {
814 phosphor::logging::log<phosphor::logging::level::INFO>(
815 "Invalid Version format.",
816 phosphor::logging::entry("Version=%s", verStr.c_str()),
817 phosphor::logging::entry("PATH=%s", fwDev.second));
818 continue;
819 }
820
821 uint8_t majorNum = 0;
822 uint8_t minorNum = 0;
823 uint32_t buildNum = 0;
824 try
825 {
826 majorNum = std::stoul(splitVer[0], nullptr, 16);
827 minorNum = std::stoul(splitVer[1], nullptr, 16);
828 buildNum = std::stoul(splitVer[2], nullptr, 16);
829 }
830 catch (const std::exception &e)
831 {
832 phosphor::logging::log<phosphor::logging::level::INFO>(
833 "Failed to convert stoul.",
834 phosphor::logging::entry("ERROR=%s", e.what()));
835 continue;
836 }
837
838 // Build Timestamp - Not supported.
839 // Update Timestamp - TODO: Need to check with CPLD team.
840 fwVerInfoList.emplace_back(
841 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
842 minorNum, buildNum, 0, 0));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700843 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700844
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530845 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700846}
AppaRao Puli28972062019-11-11 02:04:45 +0530847using fwSecurityVersionInfoType = std::tuple<uint8_t, // ID Tag
848 uint8_t, // BKC Version
849 uint8_t>; // SVN Version
850ipmi::RspType<uint8_t, std::vector<fwSecurityVersionInfoType>>
851 ipmiGetFwSecurityVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700852{
AppaRao Puli28972062019-11-11 02:04:45 +0530853 // TODO: Need to add support.
854 return ipmi::responseInvalidCommand();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700855}
856
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530857ipmi::RspType<std::array<uint8_t, certKeyLen>,
858 std::optional<std::array<uint8_t, cskSignatureLen>>>
859 ipmiGetFwRootCertData(uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700860{
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530861 size_t certKeyOffset = 0;
862 size_t cskSigOffset = 0;
863 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700864
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530865 switch (static_cast<FwGetRootCertDataTag>(certId))
866 {
867 case FwGetRootCertDataTag::activeRootKey:
868 {
869 mtdDev = bmcActivePfmMTDDev;
870 certKeyOffset = rootkeyOffsetInPfm;
871 break;
872 }
873 case FwGetRootCertDataTag::recoveryRootKey:
874 {
875 mtdDev = bmcRecoveryImgMTDDev;
876 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
877 break;
878 }
879 case FwGetRootCertDataTag::activeCSK:
880 {
881 mtdDev = bmcActivePfmMTDDev;
882 certKeyOffset = cskKeyOffsetInPfm;
883 cskSigOffset = cskSignatureOffsetInPfm;
884 break;
885 }
886 case FwGetRootCertDataTag::recoveryCSK:
887 {
888 mtdDev = bmcRecoveryImgMTDDev;
889 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
890 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
891 break;
892 }
893 default:
894 {
895 return ipmi::responseInvalidFieldRequest();
896 }
897 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700898
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530899 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700900
Vernon Mauery52ce6622019-05-22 09:19:46 -0700901 try
902 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530903 SPIDev spiDev(mtdDev);
904 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
905
906 if (cskSigOffset)
907 {
908 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
909 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
910 cskSignature.data());
911 return ipmi::responseSuccess(certKey, cskSignature);
912 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700913 }
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530914 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700915 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530916 phosphor::logging::log<phosphor::logging::level::ERR>(
917 "Exception caught in ipmiGetFwRootCertData",
918 phosphor::logging::entry("MSG=%s", e.what()));
919 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700920 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700921
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530922 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700923}
AppaRao Puli28972062019-11-11 02:04:45 +0530924#endif // INTEL_PFR_ENABLED
925
926static constexpr uint8_t channelListSize = 3;
927/** @brief implements Maximum Firmware Transfer size command
928 * @parameter
929 * - none
930 * @returns IPMI completion code plus response data
931 * - count - channel count
932 * - channelList - channel list information
933 */
934ipmi::RspType<uint8_t, // channel count
935 std::array<std::tuple<uint8_t, uint32_t>,
936 channelListSize> // Channel List
937 >
938 ipmiFirmwareMaxTransferSize()
939{
940 constexpr size_t kcsMaxBufSize = 128;
941 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
942 constexpr size_t ipmbMaxBufSize = 4 * 1024;
943 // Byte 1 - Count (N) Number of devices data is being returned for.
944 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
945 // Byte 3-6 - transfer size (little endian)
946 // Bytes - 7:(5xN) - Repeat of 2 through 6
947 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
948 channelList = {
949 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
950 {static_cast<uint8_t>(ChannelIdTag::ipmb), ipmbMaxBufSize},
951 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
952 rmcpPlusMaxBufSize}}};
953
954 return ipmi::responseSuccess(channelListSize, channelList);
955}
956
957ipmi::RspType<uint8_t, uint8_t>
958 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
959{
960 // Byte 1 - Current execution context
961 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
962 // Byte 2 - Partition pointer
963 // 0x01 - primary, 0x02 - secondary
964 uint8_t partitionPtr = getActiveBootImage(ctx);
965
966 return ipmi::responseSuccess(
967 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
968}
969
970/** @brief Get Firmware Update Random Number
971 *
972 * This function generate the random number used for
973 * setting the firmware update mode as authentication key.
974 *
975 * @parameter : None
976 * @returns IPMI completion code along with
977 * - random number
978 **/
979ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
980 ipmiGetFwUpdateRandomNumber()
981{
982 phosphor::logging::log<phosphor::logging::level::INFO>(
983 "Generate FW update random number");
984 std::random_device rd;
985 std::default_random_engine gen(rd());
986 std::uniform_int_distribution<> dist{0, 255};
987
988 fwRandomNumGenTs = std::chrono::steady_clock::now();
989
990 for (int i = 0; i < fwRandomNumLength; i++)
991 {
992 fwRandomNum[i] = dist(gen);
993 }
994
995 return ipmi::responseSuccess(fwRandomNum);
996}
997
998/** @brief Set Firmware Update Mode
999 *
1000 * This function sets BMC into firmware update mode
1001 * after validating Random number obtained from the Get
1002 * Firmware Update Random Number command
1003 *
1004 * @parameter
1005 * - randNum - Random number(token)
1006 * @returns IPMI completion code
1007 **/
1008ipmi::RspType<>
1009 ipmiSetFirmwareUpdateMode(std::array<uint8_t, fwRandomNumLength> &randNum)
1010{
1011 phosphor::logging::log<phosphor::logging::level::INFO>(
1012 "Start FW update mode");
1013 /* Firmware Update Random number is valid for 30 seconds only */
1014 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1015 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1016 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1017 fwRandomNumExpirySeconds)
1018 .count())
1019 {
1020 phosphor::logging::log<phosphor::logging::level::INFO>(
1021 "Firmware update random number expired.");
1022 return ipmi::responseInvalidFieldRequest();
1023 }
1024
1025 /* Validate random number */
1026 for (int i = 0; i < fwRandomNumLength; i++)
1027 {
1028 if (fwRandomNum[i] != randNum[i])
1029 {
1030 phosphor::logging::log<phosphor::logging::level::INFO>(
1031 "Invalid random number specified.");
1032 return ipmi::responseInvalidFieldRequest();
1033 }
1034 }
1035
1036 try
1037 {
1038 if (getFirmwareUpdateMode())
1039 {
1040 phosphor::logging::log<phosphor::logging::level::INFO>(
1041 "Already firmware update is in progress.");
1042 return ipmi::responseBusy();
1043 }
1044 }
1045 catch (const std::exception &e)
1046 {
1047 return ipmi::responseUnspecifiedError();
1048 }
1049
1050 // FIXME? c++ doesn't off an option for exclusive file creation
1051 FILE *fp = fopen(firmwareBufferFile, "wx");
1052 if (!fp)
1053 {
1054 phosphor::logging::log<phosphor::logging::level::INFO>(
1055 "Unable to open file.");
1056 return ipmi::responseUnspecifiedError();
1057 }
1058 fclose(fp);
1059
1060 try
1061 {
1062 setFirmwareUpdateMode(true);
1063 }
1064 catch (const std::exception &e)
1065 {
1066 unlink(firmwareBufferFile);
1067 return ipmi::responseUnspecifiedError();
1068 }
1069
1070 return ipmi::responseSuccess();
1071}
1072
1073/** @brief implements exit firmware update mode command
1074 * @param None
1075 *
1076 * @returns IPMI completion code
1077 */
1078ipmi::RspType<> ipmiExitFirmwareUpdateMode()
1079{
1080 phosphor::logging::log<phosphor::logging::level::INFO>(
1081 "Exit FW update mode");
1082 switch (fwUpdateStatus.getState())
1083 {
1084 case FwUpdateStatusCache::fwStateInit:
1085 case FwUpdateStatusCache::fwStateIdle:
1086 return ipmi::responseInvalidFieldRequest();
1087 break;
1088 case FwUpdateStatusCache::fwStateDownload:
1089 case FwUpdateStatusCache::fwStateVerify:
1090 break;
1091 case FwUpdateStatusCache::fwStateProgram:
1092 break;
1093 case FwUpdateStatusCache::fwStateUpdateSuccess:
1094 case FwUpdateStatusCache::fwStateError:
1095 break;
1096 case FwUpdateStatusCache::fwStateAcCycleRequired:
1097 return ipmi::responseInvalidFieldRequest();
1098 break;
1099 }
1100 fwUpdateStatus.firmwareUpdateAbortState();
1101
1102 try
1103 {
1104 setFirmwareUpdateMode(false);
1105 }
1106 catch (const std::exception &e)
1107 {
1108 return ipmi::responseUnspecifiedError();
1109 }
1110
1111 return ipmi::responseSuccess();
1112}
1113
1114/** @brief implements Get/Set Firmware Update Control
1115 * @parameter
1116 * - Byte 1: Control Byte
1117 * - Byte 2: Firmware filename length (Optional)
1118 * - Byte 3:N: Firmware filename data (Optional)
1119 * @returns IPMI completion code plus response data
1120 * - Byte 2: Current control status
1121 **/
1122ipmi::RspType<bool, bool, bool, bool, uint4_t>
1123 ipmiGetSetFirmwareUpdateControl(const uint8_t controlReq,
1124 const std::optional<std::string> &fileName)
1125{
1126 static std::string fwXferUriPath;
1127 static bool imageTransferStarted = false;
1128 static bool imageTransferCompleted = false;
1129 static bool imageTransferAborted = false;
1130
1131 if ((controlReq !=
1132 static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
1133 (fileName))
1134 {
1135 phosphor::logging::log<phosphor::logging::level::ERR>(
1136 "Invalid request field (Filename).");
1137 return ipmi::responseInvalidFieldRequest();
1138 }
1139
1140 static bool usbAttached = getUsbStatus();
1141
1142 switch (static_cast<FwUpdateCtrlReq>(controlReq))
1143 {
1144 case FwUpdateCtrlReq::getCurrentControlStatus:
1145 phosphor::logging::log<phosphor::logging::level::INFO>(
1146 "ipmiGetSetFirmwareUpdateControl: Get status");
1147 break;
1148 case FwUpdateCtrlReq::imageTransferStart:
1149 {
1150 phosphor::logging::log<phosphor::logging::level::INFO>(
1151 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
1152 imageTransferStarted = true;
1153 // reset buffer to empty (truncate file)
1154 std::ofstream out(firmwareBufferFile,
1155 std::ofstream::binary | std::ofstream::trunc);
1156 fwXferUriPath = std::string("file://") + firmwareBufferFile;
1157 if (xferHashCheck)
1158 {
1159 xferHashCheck->clear();
1160 }
1161 // Setting state to download
1162 fwUpdateStatus.setState(
1163 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
1164#ifdef INTEL_PFR_ENABLED
1165 imgLength = 0;
1166 imgType = 0;
1167 block0Mapped = false;
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301168#endif
AppaRao Puli28972062019-11-11 02:04:45 +05301169 }
1170 break;
1171 case FwUpdateCtrlReq::imageTransferComplete:
1172 {
1173 phosphor::logging::log<phosphor::logging::level::INFO>(
1174 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
1175 if (usbAttached)
1176 {
1177 phosphor::logging::log<phosphor::logging::level::ERR>(
1178 "USB should be detached to perform this operation.");
1179 return ipmi::responseNotSupportedInPresentState();
1180 }
1181 // finish transfer based on URI
1182 if (!transferFirmwareFromUri(fwXferUriPath))
1183 {
1184 phosphor::logging::log<phosphor::logging::level::ERR>(
1185 "transferFirmwareFromUri failed.");
1186 return ipmi::responseUnspecifiedError();
1187 }
1188 // transfer complete
1189 if (xferHashCheck)
1190 {
1191 if (TransferHashCheck::HashCheck::sha2Success !=
1192 xferHashCheck->verify())
1193 {
1194 phosphor::logging::log<phosphor::logging::level::ERR>(
1195 "xferHashCheck failed.");
1196 return ipmi::responseUnspecifiedError();
1197 }
1198 }
1199 // Set state to verify and start the update
1200 fwUpdateStatus.setState(
1201 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
1202 // start the request
1203 if (!startFirmwareUpdate(firmwareBufferFile))
1204 {
1205 phosphor::logging::log<phosphor::logging::level::ERR>(
1206 "startFirmwareUpdate failed.");
1207 return ipmi::responseUnspecifiedError();
1208 }
1209 imageTransferCompleted = true;
1210 }
1211 break;
1212 case FwUpdateCtrlReq::imageTransferAbort:
1213 phosphor::logging::log<phosphor::logging::level::INFO>(
1214 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
1215 if (usbAttached)
1216 {
1217 if (detachUsbDevice())
1218 {
1219 phosphor::logging::log<phosphor::logging::level::ERR>(
1220 "Detach USB device failed.");
1221 return ipmi::responseUsbAttachOrDetachFailed();
1222 }
1223 usbAttached = false;
1224 }
1225 // During abort request reset the state to Init by cleaning update
1226 // file.
1227 fwUpdateStatus.firmwareUpdateAbortState();
1228 imageTransferAborted = true;
1229 break;
1230 case FwUpdateCtrlReq::setFirmwareFilename:
1231 phosphor::logging::log<phosphor::logging::level::INFO>(
1232 "ipmiGetSetFirmwareUpdateControl: Set filename.");
1233 if (!fileName || ((*fileName).length() == 0))
1234 {
1235 phosphor::logging::log<phosphor::logging::level::ERR>(
1236 "Invalid Filename specified.");
1237 return ipmi::responseInvalidFieldRequest();
1238 }
1239
1240 fwXferUriPath = *fileName;
1241 break;
1242 case FwUpdateCtrlReq::attachUsbDevice:
1243 phosphor::logging::log<phosphor::logging::level::INFO>(
1244 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
1245 if (usbAttached)
1246 {
1247 phosphor::logging::log<phosphor::logging::level::ERR>(
1248 "USB device is already attached.");
1249 return ipmi::responseInvalidFieldRequest();
1250 }
1251 if (attachUsbDevice())
1252 {
1253 phosphor::logging::log<phosphor::logging::level::ERR>(
1254 "Attach USB device failed.");
1255 return ipmi::responseUsbAttachOrDetachFailed();
1256 }
1257 usbAttached = true;
1258 break;
1259 case FwUpdateCtrlReq::detachUsbDevice:
1260 phosphor::logging::log<phosphor::logging::level::INFO>(
1261 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
1262 if (!usbAttached)
1263 {
1264 phosphor::logging::log<phosphor::logging::level::ERR>(
1265 "USB device is not attached.");
1266 return ipmi::responseInvalidFieldRequest();
1267 }
1268 if (detachUsbDevice())
1269 {
1270 phosphor::logging::log<phosphor::logging::level::ERR>(
1271 "Detach USB device failed.");
1272 return ipmi::responseUsbAttachOrDetachFailed();
1273 }
1274 usbAttached = false;
1275 break;
1276 default:
1277 phosphor::logging::log<phosphor::logging::level::ERR>(
1278 "Invalid control option specified.");
1279 return ipmi::responseInvalidFieldRequest();
1280 }
1281
1282 return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
1283 imageTransferAborted, usbAttached, uint4_t(0));
1284}
1285
1286/** @brief implements firmware get status command
1287 * @parameter
1288 * - none
1289 * @returns IPMI completion code plus response data
1290 * - status - processing status
1291 * - percentage - percentage completion
1292 * - check - channel integrity check status
1293 **/
1294ipmi::RspType<uint8_t, // status
1295 uint8_t, // percentage
1296 uint8_t // check
1297 >
1298 ipmiGetFirmwareUpdateStatus()
1299
1300{
1301 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1302 // 5=ready, f=error, 83=ac cycle required)
1303 // Byte 2 - percent
1304 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
1305 uint8_t status = fwUpdateStatus.getState();
1306 uint8_t percent = fwUpdateStatus.percent();
1307 uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
1308
1309 // Status code.
1310 return ipmi::responseSuccess(status, percent, check);
1311}
1312
1313ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
1314 bool noDowngradeMask, bool deferRestartMask, bool sha2CheckMask,
1315 uint5_t reserved1, bool noDowngrade, bool deferRestart, bool sha2Check,
1316 uint5_t reserved2, std::optional<std::vector<uint8_t>> integrityCheckVal)
1317{
1318 phosphor::logging::log<phosphor::logging::level::INFO>(
1319 "Set firmware update options.");
1320 bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
1321 bool deferRestartState = fwUpdateStatus.getDeferRestart();
1322 bool sha2CheckState = xferHashCheck ? true : false;
1323
1324 if (noDowngradeMask && (noDowngradeState != noDowngrade))
1325 {
1326 fwUpdateStatus.setInhibitDowngrade(noDowngrade);
1327 noDowngradeState = noDowngrade;
1328 }
1329 if (deferRestartMask && (deferRestartState != deferRestart))
1330 {
1331 fwUpdateStatus.setDeferRestart(deferRestart);
1332 deferRestartState = deferRestart;
1333 }
1334 if (sha2CheckMask)
1335 {
1336 if (sha2Check)
1337 {
1338 auto hashSize = EVP_MD_size(EVP_sha256());
1339 if ((*integrityCheckVal).size() != hashSize)
1340 {
1341 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1342 "Invalid size of Hash specified.");
1343 return ipmi::responseInvalidFieldRequest();
1344 }
1345 xferHashCheck = std::make_shared<TransferHashCheck>();
1346 xferHashCheck->init(*integrityCheckVal);
1347 }
1348 else
1349 {
1350 // delete the xferHashCheck object
1351 xferHashCheck.reset();
1352 }
1353 sha2CheckState = sha2CheckMask;
1354 }
1355 return ipmi::responseSuccess(noDowngradeState, deferRestartState,
1356 sha2CheckState, reserved1);
1357}
Vernon Mauery52ce6622019-05-22 09:19:46 -07001358
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301359ipmi::RspType<uint32_t>
1360 ipmiFwImageWriteData(const std::vector<uint8_t> &writeData)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001361{
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301362 const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
1363 size_t writeDataLen = writeData.size();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001364
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301365 if (!writeDataLen)
1366 {
1367 return ipmi::responseReqDataLenInvalid();
1368 }
1369
AppaRao Puli28972062019-11-11 02:04:45 +05301370 if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301371 {
AppaRao Puli28972062019-11-11 02:04:45 +05301372 phosphor::logging::log<phosphor::logging::level::ERR>(
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301373 "Invalid firmware update state.");
1374 return ipmi::response(ccCmdNotSupportedInPresentState);
1375 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001376
AppaRao Puli28972062019-11-11 02:04:45 +05301377 std::ofstream out(firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001378 std::ofstream::binary | std::ofstream::app);
1379 if (!out)
1380 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301381 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1382 "Error while opening file.");
1383 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001384 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301385
1386 uint64_t fileDataLen = out.tellp();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301387
AppaRao Puli28972062019-11-11 02:04:45 +05301388 if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001389 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301390 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1391 "Firmware image size exceeds the limit");
1392 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001393 }
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301394
1395 const char *data = reinterpret_cast<const char *>(writeData.data());
1396 out.write(data, writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001397 out.close();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301398
AppaRao Puli28972062019-11-11 02:04:45 +05301399 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001400 {
AppaRao Puli28972062019-11-11 02:04:45 +05301401 xferHashCheck->hash(writeData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001402 }
1403
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301404#ifdef INTEL_PFR_ENABLED
1405 /* PFR image block 0 - As defined in HAS */
1406 struct PFRImageBlock0
1407 {
1408 uint32_t tag;
1409 uint32_t pcLength;
1410 uint32_t pcType;
1411 uint32_t reserved1;
1412 uint8_t hash256[32];
1413 uint8_t hash384[48];
1414 uint8_t reserved2[32];
1415 } __attribute__((packed));
1416
1417 /* Get the PFR block 0 data and read the uploaded image
1418 * information( Image type, length etc) */
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301419 if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
1420 (!block0Mapped))
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301421 {
1422 struct PFRImageBlock0 block0Data = {0};
1423
AppaRao Puli28972062019-11-11 02:04:45 +05301424 std::ifstream inFile(firmwareBufferFile,
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301425 std::ios::binary | std::ios::in);
1426 inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
1427 inFile.close();
1428
1429 uint32_t magicNum = block0Data.tag;
1430
1431 /* Validate the magic number */
1432 if (magicNum != perBlock0MagicNum)
1433 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301434 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1435 "PFR image magic number not matched");
1436 return ipmi::responseInvalidFieldRequest();
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301437 }
1438 // Note:imgLength, imgType and block0Mapped are in global scope, as
1439 // these are used in cascaded updates.
1440 imgLength = block0Data.pcLength;
1441 imgType = block0Data.pcType;
1442 block0Mapped = true;
1443 }
1444#endif // end of INTEL_PFR_ENABLED
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301445 return ipmi::responseSuccess(writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001446}
1447
AppaRao Puli28972062019-11-11 02:04:45 +05301448static void registerFirmwareFunctions()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001449{
1450 // guarantee that we start with an already timed out timestamp
AppaRao Puli28972062019-11-11 02:04:45 +05301451 fwRandomNumGenTs =
1452 std::chrono::steady_clock::now() - fwRandomNumExpirySeconds;
1453 fwUpdateStatus.setState(
1454 static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001455
AppaRao Puli28972062019-11-11 02:04:45 +05301456 unlink(firmwareBufferFile);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001457
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301458#ifdef INTEL_PFR_ENABLED
1459 // Following commands are supported only for PFR enabled platforms
1460 // CMD:0x20 - Get Firmware Version Information
AppaRao Puli28972062019-11-11 02:04:45 +05301461 // CMD:0x21 - Get Firmware Security Version Information
1462 // CMD:0x25 - Get Root Certificate Data
Vernon Mauery52ce6622019-05-22 09:19:46 -07001463
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301464 // get firmware version information
1465 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1466 ipmi::firmware::cmdGetFwVersionInfo,
1467 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
AppaRao Puli28972062019-11-11 02:04:45 +05301468
Vernon Mauery52ce6622019-05-22 09:19:46 -07001469 // get firmware security version information
AppaRao Puli28972062019-11-11 02:04:45 +05301470 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1471 ipmi::firmware::cmdGetFwSecurityVersionInfo,
1472 ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001473
Vernon Mauery52ce6622019-05-22 09:19:46 -07001474 // get root certificate data
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301475 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1476 ipmi::firmware::cmdFwGetRootCertData,
1477 ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1478#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001479
AppaRao Puli28972062019-11-11 02:04:45 +05301480 // get firmware update channel information (max transfer sizes)
1481 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1482 ipmi::firmware::cmdGetFwUpdateChannelInfo,
1483 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001484
AppaRao Puli28972062019-11-11 02:04:45 +05301485 // get bmc execution context
1486 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1487 ipmi::firmware::cmdGetBmcExecutionContext,
1488 ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
1489
1490 // Get Firmware Update Random number
1491 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1492 ipmi::firmware::cmdGetFwUpdateRandomNumber,
1493 ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
1494
1495 // Set Firmware Update Mode
1496 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1497 ipmi::firmware::cmdSetFirmwareUpdateMode,
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301498 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001499
AppaRao Puli28972062019-11-11 02:04:45 +05301500 // Exit Firmware Update Mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001501 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
AppaRao Puli28972062019-11-11 02:04:45 +05301502 ipmi::firmware::cmdExitFirmwareUpdateMode,
1503 ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001504
AppaRao Puli28972062019-11-11 02:04:45 +05301505 // Get/Set Firmware Update Control
1506 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1507 ipmi::firmware::cmdGetSetFwUpdateControl,
1508 ipmi::Privilege::Admin,
1509 ipmiGetSetFirmwareUpdateControl);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001510
AppaRao Puli28972062019-11-11 02:04:45 +05301511 // Get Firmware Update Status
1512 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1513 ipmi::firmware::cmdGetFirmwareUpdateStatus,
1514 ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001515
AppaRao Puli28972062019-11-11 02:04:45 +05301516 // Set Firmware Update Options
1517 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1518 ipmi::firmware::cmdSetFirmwareUpdateOptions,
1519 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001520 // write image data
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301521 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1522 ipmi::firmware::cmdFwImageWriteData,
1523 ipmi::Privilege::Admin, ipmiFwImageWriteData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001524 return;
1525}