blob: 56ad7778f8b98a9de98e5126b734b3e962c4b84a [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>>>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530859 ipmiGetFwRootCertData(const ipmi::Context::ptr &ctx, uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700860{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530861 bool isIPMBChannel = false;
862
863 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
864 {
865 return ipmi::responseUnspecifiedError();
866 }
867 if (isIPMBChannel)
868 {
869 phosphor::logging::log<phosphor::logging::level::INFO>(
870 "Command not supported. Failed to get root certificate data.");
871 return ipmi::responseCommandNotAvailable();
872 }
873
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530874 size_t certKeyOffset = 0;
875 size_t cskSigOffset = 0;
876 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700877
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530878 switch (static_cast<FwGetRootCertDataTag>(certId))
879 {
880 case FwGetRootCertDataTag::activeRootKey:
881 {
882 mtdDev = bmcActivePfmMTDDev;
883 certKeyOffset = rootkeyOffsetInPfm;
884 break;
885 }
886 case FwGetRootCertDataTag::recoveryRootKey:
887 {
888 mtdDev = bmcRecoveryImgMTDDev;
889 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
890 break;
891 }
892 case FwGetRootCertDataTag::activeCSK:
893 {
894 mtdDev = bmcActivePfmMTDDev;
895 certKeyOffset = cskKeyOffsetInPfm;
896 cskSigOffset = cskSignatureOffsetInPfm;
897 break;
898 }
899 case FwGetRootCertDataTag::recoveryCSK:
900 {
901 mtdDev = bmcRecoveryImgMTDDev;
902 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
903 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
904 break;
905 }
906 default:
907 {
908 return ipmi::responseInvalidFieldRequest();
909 }
910 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700911
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530912 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700913
Vernon Mauery52ce6622019-05-22 09:19:46 -0700914 try
915 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530916 SPIDev spiDev(mtdDev);
917 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
918
919 if (cskSigOffset)
920 {
921 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
922 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
923 cskSignature.data());
924 return ipmi::responseSuccess(certKey, cskSignature);
925 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700926 }
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530927 catch (const std::exception &e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700928 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530929 phosphor::logging::log<phosphor::logging::level::ERR>(
930 "Exception caught in ipmiGetFwRootCertData",
931 phosphor::logging::entry("MSG=%s", e.what()));
932 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700933 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700934
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530935 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700936}
AppaRao Puli28972062019-11-11 02:04:45 +0530937#endif // INTEL_PFR_ENABLED
938
939static constexpr uint8_t channelListSize = 3;
940/** @brief implements Maximum Firmware Transfer size command
941 * @parameter
942 * - none
943 * @returns IPMI completion code plus response data
944 * - count - channel count
945 * - channelList - channel list information
946 */
947ipmi::RspType<uint8_t, // channel count
948 std::array<std::tuple<uint8_t, uint32_t>,
949 channelListSize> // Channel List
950 >
951 ipmiFirmwareMaxTransferSize()
952{
953 constexpr size_t kcsMaxBufSize = 128;
954 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
AppaRao Puli28972062019-11-11 02:04:45 +0530955 // Byte 1 - Count (N) Number of devices data is being returned for.
956 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
957 // Byte 3-6 - transfer size (little endian)
958 // Bytes - 7:(5xN) - Repeat of 2 through 6
959 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
960 channelList = {
961 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
AppaRao Puli28972062019-11-11 02:04:45 +0530962 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
963 rmcpPlusMaxBufSize}}};
964
965 return ipmi::responseSuccess(channelListSize, channelList);
966}
967
968ipmi::RspType<uint8_t, uint8_t>
969 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
970{
971 // Byte 1 - Current execution context
972 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
973 // Byte 2 - Partition pointer
974 // 0x01 - primary, 0x02 - secondary
975 uint8_t partitionPtr = getActiveBootImage(ctx);
976
977 return ipmi::responseSuccess(
978 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
979}
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530980/** @brief check if channel IPMB
981 *
982 * This function checks if the command is from IPMB
983 *
984 * @param[in] ctx - context of current session.
985 * @returns true if the medium is IPMB else return true.
986 **/
987ipmi::Cc checkIPMBChannel(const ipmi::Context::ptr &ctx, bool &isIPMBChannel)
988{
989 ipmi::ChannelInfo chInfo;
AppaRao Puli28972062019-11-11 02:04:45 +0530990
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530991 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
992 {
993 phosphor::logging::log<phosphor::logging::level::ERR>(
994 "Failed to get Channel Info",
995 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
996 return ipmi::ccUnspecifiedError;
997 }
998
999 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
1000 ipmi::EChannelMediumType::ipmb)
1001 {
1002 isIPMBChannel = true;
1003 }
1004 return ipmi::ccSuccess;
1005}
AppaRao Puli28972062019-11-11 02:04:45 +05301006/** @brief Get Firmware Update Random Number
1007 *
1008 * This function generate the random number used for
1009 * setting the firmware update mode as authentication key.
1010 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301011 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301012 * @returns IPMI completion code along with
1013 * - random number
1014 **/
1015ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301016 ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr &ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301017{
1018 phosphor::logging::log<phosphor::logging::level::INFO>(
1019 "Generate FW update random number");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301020 bool isIPMBChannel = false;
1021
1022 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1023 {
1024 return ipmi::responseUnspecifiedError();
1025 }
1026 if (isIPMBChannel)
1027 {
1028 phosphor::logging::log<phosphor::logging::level::INFO>(
1029 "Channel not supported. Failed to fetch FW update random number");
1030 return ipmi::responseCommandNotAvailable();
1031 }
AppaRao Puli28972062019-11-11 02:04:45 +05301032 std::random_device rd;
1033 std::default_random_engine gen(rd());
1034 std::uniform_int_distribution<> dist{0, 255};
1035
1036 fwRandomNumGenTs = std::chrono::steady_clock::now();
1037
1038 for (int i = 0; i < fwRandomNumLength; i++)
1039 {
1040 fwRandomNum[i] = dist(gen);
1041 }
1042
1043 return ipmi::responseSuccess(fwRandomNum);
1044}
1045
1046/** @brief Set Firmware Update Mode
1047 *
1048 * This function sets BMC into firmware update mode
1049 * after validating Random number obtained from the Get
1050 * Firmware Update Random Number command
1051 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301052 * @param[in] ctx - context of current session
1053 * @parameter randNum - Random number(token)
1054 * @returns IPMI completion code
AppaRao Puli28972062019-11-11 02:04:45 +05301055 **/
1056ipmi::RspType<>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301057 ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr &ctx,
1058 std::array<uint8_t, fwRandomNumLength> &randNum)
AppaRao Puli28972062019-11-11 02:04:45 +05301059{
1060 phosphor::logging::log<phosphor::logging::level::INFO>(
1061 "Start FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301062
1063 bool isIPMBChannel = false;
1064
1065 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1066 {
1067 return ipmi::responseUnspecifiedError();
1068 }
1069 if (isIPMBChannel)
1070 {
1071 phosphor::logging::log<phosphor::logging::level::INFO>(
1072 "Channel not supported. Failed to set FW update mode");
1073 return ipmi::responseCommandNotAvailable();
1074 }
AppaRao Puli28972062019-11-11 02:04:45 +05301075 /* Firmware Update Random number is valid for 30 seconds only */
1076 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1077 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1078 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1079 fwRandomNumExpirySeconds)
1080 .count())
1081 {
1082 phosphor::logging::log<phosphor::logging::level::INFO>(
1083 "Firmware update random number expired.");
1084 return ipmi::responseInvalidFieldRequest();
1085 }
1086
1087 /* Validate random number */
1088 for (int i = 0; i < fwRandomNumLength; i++)
1089 {
1090 if (fwRandomNum[i] != randNum[i])
1091 {
1092 phosphor::logging::log<phosphor::logging::level::INFO>(
1093 "Invalid random number specified.");
1094 return ipmi::responseInvalidFieldRequest();
1095 }
1096 }
1097
1098 try
1099 {
1100 if (getFirmwareUpdateMode())
1101 {
1102 phosphor::logging::log<phosphor::logging::level::INFO>(
1103 "Already firmware update is in progress.");
1104 return ipmi::responseBusy();
1105 }
1106 }
1107 catch (const std::exception &e)
1108 {
1109 return ipmi::responseUnspecifiedError();
1110 }
1111
1112 // FIXME? c++ doesn't off an option for exclusive file creation
1113 FILE *fp = fopen(firmwareBufferFile, "wx");
1114 if (!fp)
1115 {
1116 phosphor::logging::log<phosphor::logging::level::INFO>(
1117 "Unable to open file.");
1118 return ipmi::responseUnspecifiedError();
1119 }
1120 fclose(fp);
1121
1122 try
1123 {
1124 setFirmwareUpdateMode(true);
1125 }
1126 catch (const std::exception &e)
1127 {
1128 unlink(firmwareBufferFile);
1129 return ipmi::responseUnspecifiedError();
1130 }
1131
1132 return ipmi::responseSuccess();
1133}
1134
1135/** @brief implements exit firmware update mode command
1136 * @param None
1137 *
1138 * @returns IPMI completion code
1139 */
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301140ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr &ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301141{
1142 phosphor::logging::log<phosphor::logging::level::INFO>(
1143 "Exit FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301144 bool isIPMBChannel = false;
1145
1146 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1147 {
1148 return ipmi::responseUnspecifiedError();
1149 }
1150 if (isIPMBChannel)
1151 {
1152 phosphor::logging::log<phosphor::logging::level::INFO>(
1153 "Command not supported. Failed to exit firmware update mode");
1154 return ipmi::responseCommandNotAvailable();
1155 }
1156
AppaRao Puli28972062019-11-11 02:04:45 +05301157 switch (fwUpdateStatus.getState())
1158 {
1159 case FwUpdateStatusCache::fwStateInit:
1160 case FwUpdateStatusCache::fwStateIdle:
1161 return ipmi::responseInvalidFieldRequest();
1162 break;
1163 case FwUpdateStatusCache::fwStateDownload:
1164 case FwUpdateStatusCache::fwStateVerify:
1165 break;
1166 case FwUpdateStatusCache::fwStateProgram:
1167 break;
1168 case FwUpdateStatusCache::fwStateUpdateSuccess:
1169 case FwUpdateStatusCache::fwStateError:
1170 break;
1171 case FwUpdateStatusCache::fwStateAcCycleRequired:
1172 return ipmi::responseInvalidFieldRequest();
1173 break;
1174 }
1175 fwUpdateStatus.firmwareUpdateAbortState();
1176
1177 try
1178 {
1179 setFirmwareUpdateMode(false);
1180 }
1181 catch (const std::exception &e)
1182 {
1183 return ipmi::responseUnspecifiedError();
1184 }
1185
1186 return ipmi::responseSuccess();
1187}
1188
1189/** @brief implements Get/Set Firmware Update Control
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301190 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301191 * @parameter
1192 * - Byte 1: Control Byte
1193 * - Byte 2: Firmware filename length (Optional)
1194 * - Byte 3:N: Firmware filename data (Optional)
1195 * @returns IPMI completion code plus response data
1196 * - Byte 2: Current control status
1197 **/
1198ipmi::RspType<bool, bool, bool, bool, uint4_t>
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301199 ipmiGetSetFirmwareUpdateControl(const ipmi::Context::ptr &ctx,
1200 const uint8_t controlReq,
AppaRao Puli28972062019-11-11 02:04:45 +05301201 const std::optional<std::string> &fileName)
1202{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301203 bool isIPMBChannel = false;
1204
1205 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1206 {
1207 return ipmi::responseUnspecifiedError();
1208 }
1209 if (isIPMBChannel)
1210 {
1211 phosphor::logging::log<phosphor::logging::level::INFO>(
1212 "Channel not supported. Failed to get or set FW update control");
1213 return ipmi::responseCommandNotAvailable();
1214 }
1215
AppaRao Puli28972062019-11-11 02:04:45 +05301216 static std::string fwXferUriPath;
1217 static bool imageTransferStarted = false;
1218 static bool imageTransferCompleted = false;
1219 static bool imageTransferAborted = false;
1220
1221 if ((controlReq !=
1222 static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
1223 (fileName))
1224 {
1225 phosphor::logging::log<phosphor::logging::level::ERR>(
1226 "Invalid request field (Filename).");
1227 return ipmi::responseInvalidFieldRequest();
1228 }
1229
1230 static bool usbAttached = getUsbStatus();
1231
1232 switch (static_cast<FwUpdateCtrlReq>(controlReq))
1233 {
1234 case FwUpdateCtrlReq::getCurrentControlStatus:
1235 phosphor::logging::log<phosphor::logging::level::INFO>(
1236 "ipmiGetSetFirmwareUpdateControl: Get status");
1237 break;
1238 case FwUpdateCtrlReq::imageTransferStart:
1239 {
1240 phosphor::logging::log<phosphor::logging::level::INFO>(
1241 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
1242 imageTransferStarted = true;
1243 // reset buffer to empty (truncate file)
1244 std::ofstream out(firmwareBufferFile,
1245 std::ofstream::binary | std::ofstream::trunc);
1246 fwXferUriPath = std::string("file://") + firmwareBufferFile;
1247 if (xferHashCheck)
1248 {
1249 xferHashCheck->clear();
1250 }
1251 // Setting state to download
1252 fwUpdateStatus.setState(
1253 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
1254#ifdef INTEL_PFR_ENABLED
1255 imgLength = 0;
1256 imgType = 0;
1257 block0Mapped = false;
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301258#endif
AppaRao Puli28972062019-11-11 02:04:45 +05301259 }
1260 break;
1261 case FwUpdateCtrlReq::imageTransferComplete:
1262 {
1263 phosphor::logging::log<phosphor::logging::level::INFO>(
1264 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
1265 if (usbAttached)
1266 {
1267 phosphor::logging::log<phosphor::logging::level::ERR>(
1268 "USB should be detached to perform this operation.");
1269 return ipmi::responseNotSupportedInPresentState();
1270 }
1271 // finish transfer based on URI
1272 if (!transferFirmwareFromUri(fwXferUriPath))
1273 {
1274 phosphor::logging::log<phosphor::logging::level::ERR>(
1275 "transferFirmwareFromUri failed.");
1276 return ipmi::responseUnspecifiedError();
1277 }
1278 // transfer complete
1279 if (xferHashCheck)
1280 {
1281 if (TransferHashCheck::HashCheck::sha2Success !=
1282 xferHashCheck->verify())
1283 {
1284 phosphor::logging::log<phosphor::logging::level::ERR>(
1285 "xferHashCheck failed.");
1286 return ipmi::responseUnspecifiedError();
1287 }
1288 }
1289 // Set state to verify and start the update
1290 fwUpdateStatus.setState(
1291 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
1292 // start the request
1293 if (!startFirmwareUpdate(firmwareBufferFile))
1294 {
1295 phosphor::logging::log<phosphor::logging::level::ERR>(
1296 "startFirmwareUpdate failed.");
1297 return ipmi::responseUnspecifiedError();
1298 }
1299 imageTransferCompleted = true;
1300 }
1301 break;
1302 case FwUpdateCtrlReq::imageTransferAbort:
1303 phosphor::logging::log<phosphor::logging::level::INFO>(
1304 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
1305 if (usbAttached)
1306 {
1307 if (detachUsbDevice())
1308 {
1309 phosphor::logging::log<phosphor::logging::level::ERR>(
1310 "Detach USB device failed.");
1311 return ipmi::responseUsbAttachOrDetachFailed();
1312 }
1313 usbAttached = false;
1314 }
1315 // During abort request reset the state to Init by cleaning update
1316 // file.
1317 fwUpdateStatus.firmwareUpdateAbortState();
1318 imageTransferAborted = true;
1319 break;
1320 case FwUpdateCtrlReq::setFirmwareFilename:
1321 phosphor::logging::log<phosphor::logging::level::INFO>(
1322 "ipmiGetSetFirmwareUpdateControl: Set filename.");
1323 if (!fileName || ((*fileName).length() == 0))
1324 {
1325 phosphor::logging::log<phosphor::logging::level::ERR>(
1326 "Invalid Filename specified.");
1327 return ipmi::responseInvalidFieldRequest();
1328 }
1329
1330 fwXferUriPath = *fileName;
1331 break;
1332 case FwUpdateCtrlReq::attachUsbDevice:
1333 phosphor::logging::log<phosphor::logging::level::INFO>(
1334 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
1335 if (usbAttached)
1336 {
1337 phosphor::logging::log<phosphor::logging::level::ERR>(
1338 "USB device is already attached.");
1339 return ipmi::responseInvalidFieldRequest();
1340 }
1341 if (attachUsbDevice())
1342 {
1343 phosphor::logging::log<phosphor::logging::level::ERR>(
1344 "Attach USB device failed.");
1345 return ipmi::responseUsbAttachOrDetachFailed();
1346 }
1347 usbAttached = true;
1348 break;
1349 case FwUpdateCtrlReq::detachUsbDevice:
1350 phosphor::logging::log<phosphor::logging::level::INFO>(
1351 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
1352 if (!usbAttached)
1353 {
1354 phosphor::logging::log<phosphor::logging::level::ERR>(
1355 "USB device is not attached.");
1356 return ipmi::responseInvalidFieldRequest();
1357 }
1358 if (detachUsbDevice())
1359 {
1360 phosphor::logging::log<phosphor::logging::level::ERR>(
1361 "Detach USB device failed.");
1362 return ipmi::responseUsbAttachOrDetachFailed();
1363 }
1364 usbAttached = false;
1365 break;
1366 default:
1367 phosphor::logging::log<phosphor::logging::level::ERR>(
1368 "Invalid control option specified.");
1369 return ipmi::responseInvalidFieldRequest();
1370 }
1371
1372 return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
1373 imageTransferAborted, usbAttached, uint4_t(0));
1374}
1375
1376/** @brief implements firmware get status command
1377 * @parameter
1378 * - none
1379 * @returns IPMI completion code plus response data
1380 * - status - processing status
1381 * - percentage - percentage completion
1382 * - check - channel integrity check status
1383 **/
1384ipmi::RspType<uint8_t, // status
1385 uint8_t, // percentage
1386 uint8_t // check
1387 >
1388 ipmiGetFirmwareUpdateStatus()
1389
1390{
1391 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1392 // 5=ready, f=error, 83=ac cycle required)
1393 // Byte 2 - percent
1394 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
1395 uint8_t status = fwUpdateStatus.getState();
1396 uint8_t percent = fwUpdateStatus.percent();
1397 uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
1398
1399 // Status code.
1400 return ipmi::responseSuccess(status, percent, check);
1401}
1402
1403ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301404 const ipmi::Context::ptr &ctx, bool noDowngradeMask, bool deferRestartMask,
1405 bool sha2CheckMask, uint5_t reserved1, bool noDowngrade, bool deferRestart,
1406 bool sha2Check, uint5_t reserved2,
1407 std::optional<std::vector<uint8_t>> integrityCheckVal)
AppaRao Puli28972062019-11-11 02:04:45 +05301408{
1409 phosphor::logging::log<phosphor::logging::level::INFO>(
1410 "Set firmware update options.");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301411 bool isIPMBChannel = false;
1412
1413 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1414 {
1415 return ipmi::responseUnspecifiedError();
1416 }
1417 if (isIPMBChannel)
1418 {
1419 phosphor::logging::log<phosphor::logging::level::INFO>(
1420 "Channel not supported. Failed to set firmware update options");
1421 return ipmi::responseCommandNotAvailable();
1422 }
AppaRao Puli28972062019-11-11 02:04:45 +05301423 bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
1424 bool deferRestartState = fwUpdateStatus.getDeferRestart();
1425 bool sha2CheckState = xferHashCheck ? true : false;
1426
1427 if (noDowngradeMask && (noDowngradeState != noDowngrade))
1428 {
1429 fwUpdateStatus.setInhibitDowngrade(noDowngrade);
1430 noDowngradeState = noDowngrade;
1431 }
1432 if (deferRestartMask && (deferRestartState != deferRestart))
1433 {
1434 fwUpdateStatus.setDeferRestart(deferRestart);
1435 deferRestartState = deferRestart;
1436 }
1437 if (sha2CheckMask)
1438 {
1439 if (sha2Check)
1440 {
1441 auto hashSize = EVP_MD_size(EVP_sha256());
1442 if ((*integrityCheckVal).size() != hashSize)
1443 {
1444 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1445 "Invalid size of Hash specified.");
1446 return ipmi::responseInvalidFieldRequest();
1447 }
1448 xferHashCheck = std::make_shared<TransferHashCheck>();
1449 xferHashCheck->init(*integrityCheckVal);
1450 }
1451 else
1452 {
1453 // delete the xferHashCheck object
1454 xferHashCheck.reset();
1455 }
1456 sha2CheckState = sha2CheckMask;
1457 }
1458 return ipmi::responseSuccess(noDowngradeState, deferRestartState,
1459 sha2CheckState, reserved1);
1460}
Vernon Mauery52ce6622019-05-22 09:19:46 -07001461
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301462ipmi::RspType<uint32_t>
1463 ipmiFwImageWriteData(const std::vector<uint8_t> &writeData)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001464{
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301465 const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
1466 size_t writeDataLen = writeData.size();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001467
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301468 if (!writeDataLen)
1469 {
1470 return ipmi::responseReqDataLenInvalid();
1471 }
1472
AppaRao Puli28972062019-11-11 02:04:45 +05301473 if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301474 {
AppaRao Puli28972062019-11-11 02:04:45 +05301475 phosphor::logging::log<phosphor::logging::level::ERR>(
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301476 "Invalid firmware update state.");
1477 return ipmi::response(ccCmdNotSupportedInPresentState);
1478 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001479
AppaRao Puli28972062019-11-11 02:04:45 +05301480 std::ofstream out(firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001481 std::ofstream::binary | std::ofstream::app);
1482 if (!out)
1483 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301484 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1485 "Error while opening file.");
1486 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001487 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301488
1489 uint64_t fileDataLen = out.tellp();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301490
AppaRao Puli28972062019-11-11 02:04:45 +05301491 if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001492 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301493 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1494 "Firmware image size exceeds the limit");
1495 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001496 }
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301497
1498 const char *data = reinterpret_cast<const char *>(writeData.data());
1499 out.write(data, writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001500 out.close();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301501
AppaRao Puli28972062019-11-11 02:04:45 +05301502 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001503 {
AppaRao Puli28972062019-11-11 02:04:45 +05301504 xferHashCheck->hash(writeData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001505 }
1506
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301507#ifdef INTEL_PFR_ENABLED
1508 /* PFR image block 0 - As defined in HAS */
1509 struct PFRImageBlock0
1510 {
1511 uint32_t tag;
1512 uint32_t pcLength;
1513 uint32_t pcType;
1514 uint32_t reserved1;
1515 uint8_t hash256[32];
1516 uint8_t hash384[48];
1517 uint8_t reserved2[32];
1518 } __attribute__((packed));
1519
1520 /* Get the PFR block 0 data and read the uploaded image
1521 * information( Image type, length etc) */
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301522 if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
1523 (!block0Mapped))
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301524 {
1525 struct PFRImageBlock0 block0Data = {0};
1526
AppaRao Puli28972062019-11-11 02:04:45 +05301527 std::ifstream inFile(firmwareBufferFile,
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301528 std::ios::binary | std::ios::in);
1529 inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
1530 inFile.close();
1531
1532 uint32_t magicNum = block0Data.tag;
1533
1534 /* Validate the magic number */
1535 if (magicNum != perBlock0MagicNum)
1536 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301537 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1538 "PFR image magic number not matched");
1539 return ipmi::responseInvalidFieldRequest();
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301540 }
1541 // Note:imgLength, imgType and block0Mapped are in global scope, as
1542 // these are used in cascaded updates.
1543 imgLength = block0Data.pcLength;
1544 imgType = block0Data.pcType;
1545 block0Mapped = true;
1546 }
1547#endif // end of INTEL_PFR_ENABLED
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301548 return ipmi::responseSuccess(writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001549}
1550
AppaRao Puli28972062019-11-11 02:04:45 +05301551static void registerFirmwareFunctions()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001552{
1553 // guarantee that we start with an already timed out timestamp
AppaRao Puli28972062019-11-11 02:04:45 +05301554 fwRandomNumGenTs =
1555 std::chrono::steady_clock::now() - fwRandomNumExpirySeconds;
1556 fwUpdateStatus.setState(
1557 static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001558
AppaRao Puli28972062019-11-11 02:04:45 +05301559 unlink(firmwareBufferFile);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001560
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301561#ifdef INTEL_PFR_ENABLED
1562 // Following commands are supported only for PFR enabled platforms
1563 // CMD:0x20 - Get Firmware Version Information
AppaRao Puli28972062019-11-11 02:04:45 +05301564 // CMD:0x21 - Get Firmware Security Version Information
1565 // CMD:0x25 - Get Root Certificate Data
Vernon Mauery52ce6622019-05-22 09:19:46 -07001566
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301567 // get firmware version information
1568 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1569 ipmi::firmware::cmdGetFwVersionInfo,
1570 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
AppaRao Puli28972062019-11-11 02:04:45 +05301571
Vernon Mauery52ce6622019-05-22 09:19:46 -07001572 // get firmware security version information
AppaRao Puli28972062019-11-11 02:04:45 +05301573 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1574 ipmi::firmware::cmdGetFwSecurityVersionInfo,
1575 ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001576
Vernon Mauery52ce6622019-05-22 09:19:46 -07001577 // get root certificate data
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301578 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1579 ipmi::firmware::cmdFwGetRootCertData,
1580 ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1581#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001582
AppaRao Puli28972062019-11-11 02:04:45 +05301583 // get firmware update channel information (max transfer sizes)
1584 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1585 ipmi::firmware::cmdGetFwUpdateChannelInfo,
1586 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001587
AppaRao Puli28972062019-11-11 02:04:45 +05301588 // get bmc execution context
1589 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1590 ipmi::firmware::cmdGetBmcExecutionContext,
1591 ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
1592
1593 // Get Firmware Update Random number
1594 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1595 ipmi::firmware::cmdGetFwUpdateRandomNumber,
1596 ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
1597
1598 // Set Firmware Update Mode
1599 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1600 ipmi::firmware::cmdSetFirmwareUpdateMode,
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301601 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001602
AppaRao Puli28972062019-11-11 02:04:45 +05301603 // Exit Firmware Update Mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001604 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
AppaRao Puli28972062019-11-11 02:04:45 +05301605 ipmi::firmware::cmdExitFirmwareUpdateMode,
1606 ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001607
AppaRao Puli28972062019-11-11 02:04:45 +05301608 // Get/Set Firmware Update Control
1609 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1610 ipmi::firmware::cmdGetSetFwUpdateControl,
1611 ipmi::Privilege::Admin,
1612 ipmiGetSetFirmwareUpdateControl);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001613
AppaRao Puli28972062019-11-11 02:04:45 +05301614 // Get Firmware Update Status
1615 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1616 ipmi::firmware::cmdGetFirmwareUpdateStatus,
1617 ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001618
AppaRao Puli28972062019-11-11 02:04:45 +05301619 // Set Firmware Update Options
1620 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1621 ipmi::firmware::cmdSetFirmwareUpdateOptions,
1622 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001623 // write image data
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301624 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1625 ipmi::firmware::cmdFwImageWriteData,
1626 ipmi::Privilege::Admin, ipmiFwImageWriteData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001627 return;
1628}