xref: /openbmc/intel-ipmi-oem/src/firmware-update.cpp (revision ab5c0e5763a6e25c7d44758b5522a5d4e0cb6728)
152a292b8Ssrikanta mondal #include <byteswap.h>
252ce662cSVernon Mauery #include <ipmid/api.h>
352ce662cSVernon Mauery #include <openssl/evp.h>
452ce662cSVernon Mauery #include <openssl/sha.h>
552ce662cSVernon Mauery #include <sys/mman.h>
652ce662cSVernon Mauery #include <sys/stat.h>
752ce662cSVernon Mauery #include <sys/types.h>
852ce662cSVernon Mauery #include <unistd.h>
952ce662cSVernon Mauery 
1052a292b8Ssrikanta mondal #include <appcommands.hpp>
1152ce662cSVernon Mauery #include <boost/algorithm/string.hpp>
1228972063SAppaRao Puli #include <boost/container/flat_map.hpp>
1352ce662cSVernon Mauery #include <boost/process/child.hpp>
1452ce662cSVernon Mauery #include <boost/uuid/random_generator.hpp>
1552ce662cSVernon Mauery #include <boost/uuid/uuid_io.hpp>
1652ce662cSVernon Mauery #include <commandutils.hpp>
176c7d9382Sanil kumar appana #include <ipmid/api.hpp>
1837fde6b6SAppaRao Puli #include <ipmid/utils.hpp>
1928972063SAppaRao Puli #include <phosphor-logging/log.hpp>
2052ce662cSVernon Mauery #include <sdbusplus/bus.hpp>
2152ce662cSVernon Mauery #include <sdbusplus/bus/match.hpp>
2252ce662cSVernon Mauery #include <sdbusplus/server/object.hpp>
2352ce662cSVernon Mauery #include <sdbusplus/timer.hpp>
24c2a07d4bSPatrick Venture #include <types.hpp>
25fcd2d3a9SJames Feist 
26fcd2d3a9SJames Feist #include <chrono>
27fcd2d3a9SJames Feist #include <cstdint>
28fcd2d3a9SJames Feist #include <filesystem>
29fcd2d3a9SJames Feist #include <fstream>
30fcd2d3a9SJames Feist #include <iostream>
31fcd2d3a9SJames Feist #include <map>
32fcd2d3a9SJames Feist #include <random>
33c8864062SRajashekar Gade Reddy #ifdef INTEL_PFR_ENABLED
34c8864062SRajashekar Gade Reddy #include <spiDev.hpp>
35c8864062SRajashekar Gade Reddy #endif
3652ce662cSVernon Mauery 
37153d4c14SArun Lal K M static constexpr int openSslSuccess = 1;
3828972063SAppaRao Puli static constexpr bool DEBUG = true;
3928972063SAppaRao Puli static void registerFirmwareFunctions() __attribute__((constructor));
4028972063SAppaRao Puli 
4137fde6b6SAppaRao Puli namespace ipmi
4237fde6b6SAppaRao Puli {
4337fde6b6SAppaRao Puli namespace firmware
4437fde6b6SAppaRao Puli {
4537fde6b6SAppaRao Puli constexpr Cmd cmdGetFwVersionInfo = 0x20;
4628972063SAppaRao Puli constexpr Cmd cmdGetFwSecurityVersionInfo = 0x21;
4728972063SAppaRao Puli constexpr Cmd cmdGetFwUpdateChannelInfo = 0x22;
4828972063SAppaRao Puli constexpr Cmd cmdGetBmcExecutionContext = 0x23;
493ec26204SRajashekar Gade Reddy constexpr Cmd cmdFwGetRootCertData = 0x25;
5028972063SAppaRao Puli constexpr Cmd cmdGetFwUpdateRandomNumber = 0x26;
5128972063SAppaRao Puli constexpr Cmd cmdSetFirmwareUpdateMode = 0x27;
5228972063SAppaRao Puli constexpr Cmd cmdExitFirmwareUpdateMode = 0x28;
5328972063SAppaRao Puli constexpr Cmd cmdGetSetFwUpdateControl = 0x29;
5428972063SAppaRao Puli constexpr Cmd cmdGetFirmwareUpdateStatus = 0x2A;
5528972063SAppaRao Puli constexpr Cmd cmdSetFirmwareUpdateOptions = 0x2B;
563ec26204SRajashekar Gade Reddy constexpr Cmd cmdFwImageWriteData = 0x2c;
5737fde6b6SAppaRao Puli } // namespace firmware
5837fde6b6SAppaRao Puli } // namespace ipmi
5937fde6b6SAppaRao Puli 
6028972063SAppaRao Puli namespace ipmi
6128972063SAppaRao Puli {
6228972063SAppaRao Puli // Custom completion codes
6328972063SAppaRao Puli constexpr Cc ccUsbAttachOrDetachFailed = 0x80;
6428972063SAppaRao Puli constexpr Cc ccNotSupportedInPresentState = 0xD5;
6528972063SAppaRao Puli 
responseUsbAttachOrDetachFailed()6628972063SAppaRao Puli static inline auto responseUsbAttachOrDetachFailed()
6728972063SAppaRao Puli {
6828972063SAppaRao Puli     return response(ccUsbAttachOrDetachFailed);
6928972063SAppaRao Puli }
responseNotSupportedInPresentState()7028972063SAppaRao Puli static inline auto responseNotSupportedInPresentState()
7128972063SAppaRao Puli {
7228972063SAppaRao Puli     return response(ccNotSupportedInPresentState);
7328972063SAppaRao Puli }
7428972063SAppaRao Puli } // namespace ipmi
7528972063SAppaRao Puli 
76a8dd197aSPunith Nadur Basavarajaiah static constexpr size_t imageCount = 2;
77dcff1506SVernon Mauery std::array<std::array<uint8_t, imageCount>, imageCount> imgFwSecurityVersion =
78dcff1506SVernon Mauery     {};
79a8dd197aSPunith Nadur Basavarajaiah static constexpr size_t svnActiveVerOffsetInPfm = 0x404;
80a8dd197aSPunith Nadur Basavarajaiah static constexpr size_t bkcActiveVerOffsetInPfm = 0x405;
81a8dd197aSPunith Nadur Basavarajaiah static constexpr size_t svnRecoveryVerOffsetInPfm = 0x804;
82a8dd197aSPunith Nadur Basavarajaiah static constexpr size_t bkcRecoveryVerOffsetInPfm = 0x805;
8328972063SAppaRao Puli static constexpr const char* bmcStateIntf = "xyz.openbmc_project.State.BMC";
8428972063SAppaRao Puli static constexpr const char* bmcStatePath = "/xyz/openbmc_project/state/bmc0";
8528972063SAppaRao Puli static constexpr const char* bmcStateReady =
8628972063SAppaRao Puli     "xyz.openbmc_project.State.BMC.BMCState.Ready";
8728972063SAppaRao Puli static constexpr const char* bmcStateUpdateInProgress =
8828972063SAppaRao Puli     "xyz.openbmc_project.State.BMC.BMCState.UpdateInProgress";
8928972063SAppaRao Puli 
9028972063SAppaRao Puli static constexpr char firmwareBufferFile[] = "/tmp/fw-download.bin";
9128972063SAppaRao Puli static std::chrono::steady_clock::time_point fwRandomNumGenTs;
9228972063SAppaRao Puli static constexpr auto fwRandomNumExpirySeconds = std::chrono::seconds(30);
9328972063SAppaRao Puli static constexpr size_t fwRandomNumLength = 8;
9428972063SAppaRao Puli static std::array<uint8_t, fwRandomNumLength> fwRandomNum;
9528972063SAppaRao Puli constexpr char usbCtrlPath[] = "/usr/bin/usb-ctrl";
9628972063SAppaRao Puli constexpr char fwUpdateMountPoint[] = "/tmp/usb-fwupd.mnt";
9728972063SAppaRao Puli constexpr char fwUpdateUsbVolImage[] = "/tmp/usb-fwupd.img";
9828972063SAppaRao Puli constexpr char fwUpdateUSBDevName[] = "fw-usb-mass-storage-dev";
9928972063SAppaRao Puli constexpr size_t fwPathMaxLength = 255;
10028972063SAppaRao Puli 
101df5e3271SRajashekar Gade Reddy #ifdef INTEL_PFR_ENABLED
102df5e3271SRajashekar Gade Reddy uint32_t imgLength = 0;
103df5e3271SRajashekar Gade Reddy uint32_t imgType = 0;
104df5e3271SRajashekar Gade Reddy bool block0Mapped = false;
105df5e3271SRajashekar Gade Reddy static constexpr uint32_t perBlock0MagicNum = 0xB6EAFD19;
10637fde6b6SAppaRao Puli 
10728972063SAppaRao Puli static constexpr const char* bmcActivePfmMTDDev = "/dev/mtd/pfm";
10828972063SAppaRao Puli static constexpr const char* bmcRecoveryImgMTDDev = "/dev/mtd/rc-image";
10928972063SAppaRao Puli static constexpr size_t pfmBaseOffsetInImage = 0x400;
11028972063SAppaRao Puli static constexpr size_t rootkeyOffsetInPfm = 0xA0;
11128972063SAppaRao Puli static constexpr size_t cskKeyOffsetInPfm = 0x124;
11228972063SAppaRao Puli static constexpr size_t cskSignatureOffsetInPfm = 0x19c;
11328972063SAppaRao Puli static constexpr size_t certKeyLen = 96;
11428972063SAppaRao Puli static constexpr size_t cskSignatureLen = 96;
11528972063SAppaRao Puli 
11637fde6b6SAppaRao Puli static constexpr const char* versionIntf =
11737fde6b6SAppaRao Puli     "xyz.openbmc_project.Software.Version";
11837fde6b6SAppaRao Puli 
11928972063SAppaRao Puli enum class FwGetRootCertDataTag : uint8_t
12028972063SAppaRao Puli {
12128972063SAppaRao Puli     activeRootKey = 1,
12228972063SAppaRao Puli     recoveryRootKey,
12328972063SAppaRao Puli     activeCSK,
12428972063SAppaRao Puli     recoveryCSK,
12528972063SAppaRao Puli };
12628972063SAppaRao Puli 
12737fde6b6SAppaRao Puli enum class FWDeviceIDTag : uint8_t
12837fde6b6SAppaRao Puli {
12937fde6b6SAppaRao Puli     bmcActiveImage = 1,
13037fde6b6SAppaRao Puli     bmcRecoveryImage,
13137fde6b6SAppaRao Puli };
13237fde6b6SAppaRao Puli 
13337fde6b6SAppaRao Puli const static boost::container::flat_map<FWDeviceIDTag, const char*>
13437fde6b6SAppaRao Puli     fwVersionIdMap{{FWDeviceIDTag::bmcActiveImage,
13537fde6b6SAppaRao Puli                     "/xyz/openbmc_project/software/bmc_active"},
13637fde6b6SAppaRao Puli                    {FWDeviceIDTag::bmcRecoveryImage,
13737fde6b6SAppaRao Puli                     "/xyz/openbmc_project/software/bmc_recovery"}};
13828972063SAppaRao Puli #endif // INTEL_PFR_ENABLED
13937fde6b6SAppaRao Puli 
14028972063SAppaRao Puli enum class ChannelIdTag : uint8_t
14128972063SAppaRao Puli {
14228972063SAppaRao Puli     reserved = 0,
14328972063SAppaRao Puli     kcs = 1,
14428972063SAppaRao Puli     ipmb = 2,
14528972063SAppaRao Puli     rmcpPlus = 3
14628972063SAppaRao Puli };
147df5e3271SRajashekar Gade Reddy 
14828972063SAppaRao Puli enum class BmcExecutionContext : uint8_t
14928972063SAppaRao Puli {
15028972063SAppaRao Puli     reserved = 0,
15128972063SAppaRao Puli     linuxOs = 0x10,
15228972063SAppaRao Puli     bootLoader = 0x11,
15328972063SAppaRao Puli };
15409a8314bSAppaRao Puli 
15528972063SAppaRao Puli enum class FwUpdateCtrlReq : uint8_t
15628972063SAppaRao Puli {
15728972063SAppaRao Puli     getCurrentControlStatus = 0x00,
15828972063SAppaRao Puli     imageTransferStart = 0x01,
15928972063SAppaRao Puli     imageTransferComplete = 0x02,
16028972063SAppaRao Puli     imageTransferAbort = 0x03,
16128972063SAppaRao Puli     setFirmwareFilename = 0x04,
16228972063SAppaRao Puli     attachUsbDevice = 0x05,
16328972063SAppaRao Puli     detachUsbDevice = 0x06
16428972063SAppaRao Puli };
16552ce662cSVernon Mauery 
operator ""_MB(unsigned long long v)16652ce662cSVernon Mauery constexpr std::size_t operator""_MB(unsigned long long v)
16752ce662cSVernon Mauery {
16852ce662cSVernon Mauery     return 1024u * 1024u * v;
16952ce662cSVernon Mauery }
170*ab5c0e57SJayaprakash Mutyala static constexpr size_t maxFirmwareImageSize = 37_MB;
17152ce662cSVernon Mauery 
localDownloadInProgress(void)17228972063SAppaRao Puli static bool localDownloadInProgress(void)
17352ce662cSVernon Mauery {
17452ce662cSVernon Mauery     struct stat sb;
17528972063SAppaRao Puli     if (stat(firmwareBufferFile, &sb) < 0)
17628972063SAppaRao Puli     {
17752ce662cSVernon Mauery         return false;
17828972063SAppaRao Puli     }
17952ce662cSVernon Mauery     return true;
18052ce662cSVernon Mauery }
18152ce662cSVernon Mauery 
18228972063SAppaRao Puli class TransferHashCheck
18328972063SAppaRao Puli {
18428972063SAppaRao Puli   public:
18528972063SAppaRao Puli     enum class HashCheck : uint8_t
18628972063SAppaRao Puli     {
18728972063SAppaRao Puli         notRequested = 0,
18828972063SAppaRao Puli         requested,
18928972063SAppaRao Puli         sha2Success,
19028972063SAppaRao Puli         sha2Failed = 0xe2,
19128972063SAppaRao Puli     };
19228972063SAppaRao Puli 
19328972063SAppaRao Puli   protected:
194153d4c14SArun Lal K M     std::unique_ptr<EVP_MD_CTX, std::function<void(EVP_MD_CTX*)>> ctx;
19528972063SAppaRao Puli     std::vector<uint8_t> expectedHash;
196153d4c14SArun Lal K M     HashCheck check;
19728972063SAppaRao Puli 
19828972063SAppaRao Puli   public:
TransferHashCheck(const std::vector<uint8_t> & expected)199153d4c14SArun Lal K M     TransferHashCheck(const std::vector<uint8_t>& expected) :
200153d4c14SArun Lal K M         ctx(EVP_MD_CTX_new(), &EVP_MD_CTX_free), expectedHash(expected)
201153d4c14SArun Lal K M     {
202153d4c14SArun Lal K M         if (!ctx)
203153d4c14SArun Lal K M         {
204153d4c14SArun Lal K M             throw std::runtime_error("Unable to allocate for ctx.");
205153d4c14SArun Lal K M         }
206153d4c14SArun Lal K M 
207153d4c14SArun Lal K M         if (EVP_DigestInit(ctx.get(), EVP_sha256()) != openSslSuccess)
208153d4c14SArun Lal K M         {
209153d4c14SArun Lal K M             throw std::runtime_error("Unable to allocate for ctx.");
210153d4c14SArun Lal K M         }
211153d4c14SArun Lal K M 
212153d4c14SArun Lal K M         check = HashCheck::requested;
213153d4c14SArun Lal K M     }
214153d4c14SArun Lal K M 
~TransferHashCheck()215b37abfb2SPatrick Williams     ~TransferHashCheck() {}
216153d4c14SArun Lal K M 
hash(const std::vector<uint8_t> & data)217153d4c14SArun Lal K M     bool hash(const std::vector<uint8_t>& data)
21828972063SAppaRao Puli     {
219153d4c14SArun Lal K M         if (EVP_DigestUpdate(ctx.get(), data.data(), data.size()) !=
220153d4c14SArun Lal K M             openSslSuccess)
22128972063SAppaRao Puli         {
222153d4c14SArun Lal K M             return false;
22328972063SAppaRao Puli         }
224153d4c14SArun Lal K M 
225153d4c14SArun Lal K M         return true;
22628972063SAppaRao Puli     }
227153d4c14SArun Lal K M 
clear()228153d4c14SArun Lal K M     bool clear()
22928972063SAppaRao Puli     {
230153d4c14SArun Lal K M         /*
231153d4c14SArun Lal K M          *   EVP_DigestInit() always uses the default digest implementation and
232153d4c14SArun Lal K M          * calls EVP_MD_CTX_reset().
233153d4c14SArun Lal K M          */
234153d4c14SArun Lal K M         if (EVP_DigestInit(ctx.get(), EVP_sha256()) != openSslSuccess)
23528972063SAppaRao Puli         {
236153d4c14SArun Lal K M             return false;
23728972063SAppaRao Puli         }
238153d4c14SArun Lal K M 
239153d4c14SArun Lal K M         return true;
24028972063SAppaRao Puli     }
241153d4c14SArun Lal K M 
verify()24228972063SAppaRao Puli     enum HashCheck verify()
24328972063SAppaRao Puli     {
24428972063SAppaRao Puli         unsigned int len = 0;
24528972063SAppaRao Puli         std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
246153d4c14SArun Lal K M 
247153d4c14SArun Lal K M         check = HashCheck::sha2Failed;
248153d4c14SArun Lal K M 
249153d4c14SArun Lal K M         if (EVP_DigestFinal(ctx.get(), digest.data(), &len) == openSslSuccess)
250153d4c14SArun Lal K M         {
25128972063SAppaRao Puli             if (digest == expectedHash)
25228972063SAppaRao Puli             {
25328972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::INFO>(
25428972063SAppaRao Puli                     "Transfer sha2 verify passed.");
25528972063SAppaRao Puli                 check = HashCheck::sha2Success;
25628972063SAppaRao Puli             }
25728972063SAppaRao Puli             else
25828972063SAppaRao Puli             {
25928972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
26028972063SAppaRao Puli                     "Transfer sha2 verify failed.");
26128972063SAppaRao Puli                 check = HashCheck::sha2Failed;
26228972063SAppaRao Puli             }
26328972063SAppaRao Puli         }
264153d4c14SArun Lal K M 
26528972063SAppaRao Puli         return check;
26628972063SAppaRao Puli     }
267153d4c14SArun Lal K M 
status() const26828972063SAppaRao Puli     uint8_t status() const
26928972063SAppaRao Puli     {
27028972063SAppaRao Puli         return static_cast<uint8_t>(check);
27128972063SAppaRao Puli     }
27228972063SAppaRao Puli };
27328972063SAppaRao Puli 
27428972063SAppaRao Puli class MappedFile
27528972063SAppaRao Puli {
27628972063SAppaRao Puli   public:
MappedFile(const std::string & fname)27728972063SAppaRao Puli     MappedFile(const std::string& fname) : addr(nullptr), fsize(0)
27828972063SAppaRao Puli     {
27928972063SAppaRao Puli         std::error_code ec;
28028972063SAppaRao Puli         size_t sz = std::filesystem::file_size(fname, ec);
281c08e9752SP Dheeraj Srujan Kumar         if (!ec)
282c08e9752SP Dheeraj Srujan Kumar         {
283c08e9752SP Dheeraj Srujan Kumar             return;
284c08e9752SP Dheeraj Srujan Kumar         }
28528972063SAppaRao Puli         int fd = open(fname.c_str(), O_RDONLY);
286c08e9752SP Dheeraj Srujan Kumar         if (fd < 0)
28728972063SAppaRao Puli         {
28828972063SAppaRao Puli             return;
28928972063SAppaRao Puli         }
29028972063SAppaRao Puli         void* tmp = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
29128972063SAppaRao Puli         close(fd);
29228972063SAppaRao Puli         if (tmp == MAP_FAILED)
29328972063SAppaRao Puli         {
29428972063SAppaRao Puli             return;
29528972063SAppaRao Puli         }
29628972063SAppaRao Puli         addr = tmp;
29728972063SAppaRao Puli         fsize = sz;
29828972063SAppaRao Puli     }
29928972063SAppaRao Puli 
~MappedFile()30028972063SAppaRao Puli     ~MappedFile()
30128972063SAppaRao Puli     {
30228972063SAppaRao Puli         if (addr)
30328972063SAppaRao Puli         {
30428972063SAppaRao Puli             munmap(addr, fsize);
30528972063SAppaRao Puli         }
30628972063SAppaRao Puli     }
data() const30728972063SAppaRao Puli     const uint8_t* data() const
30828972063SAppaRao Puli     {
30928972063SAppaRao Puli         return static_cast<const uint8_t*>(addr);
31028972063SAppaRao Puli     }
size() const31128972063SAppaRao Puli     size_t size() const
31228972063SAppaRao Puli     {
31328972063SAppaRao Puli         return fsize;
31428972063SAppaRao Puli     }
31528972063SAppaRao Puli 
31628972063SAppaRao Puli   private:
31728972063SAppaRao Puli     void* addr;
318dcff1506SVernon Mauery     size_t fsize;
31928972063SAppaRao Puli };
32028972063SAppaRao Puli 
32128972063SAppaRao Puli class FwUpdateStatusCache
32252ce662cSVernon Mauery {
32352ce662cSVernon Mauery   public:
32452ce662cSVernon Mauery     enum
32552ce662cSVernon Mauery     {
32628972063SAppaRao Puli         fwStateInit = 0,
32728972063SAppaRao Puli         fwStateIdle,
32828972063SAppaRao Puli         fwStateDownload,
32928972063SAppaRao Puli         fwStateVerify,
33028972063SAppaRao Puli         fwStateProgram,
33128972063SAppaRao Puli         fwStateUpdateSuccess,
33228972063SAppaRao Puli         fwStateError = 0x0f,
33328972063SAppaRao Puli         fwStateAcCycleRequired = 0x83,
33452ce662cSVernon Mauery     };
getState()33528972063SAppaRao Puli     uint8_t getState()
33652ce662cSVernon Mauery     {
33728972063SAppaRao Puli         if ((fwUpdateState == fwStateIdle || fwUpdateState == fwStateInit) &&
33828972063SAppaRao Puli             localDownloadInProgress())
33952ce662cSVernon Mauery         {
34028972063SAppaRao Puli             fwUpdateState = fwStateDownload;
34128972063SAppaRao Puli             progressPercent = 0;
34252ce662cSVernon Mauery         }
34328972063SAppaRao Puli         return fwUpdateState;
34428972063SAppaRao Puli     }
resetStatusCache()34528972063SAppaRao Puli     void resetStatusCache()
34628972063SAppaRao Puli     {
34728972063SAppaRao Puli         unlink(firmwareBufferFile);
34828972063SAppaRao Puli     }
setState(const uint8_t state)34928972063SAppaRao Puli     void setState(const uint8_t state)
35028972063SAppaRao Puli     {
35128972063SAppaRao Puli         switch (state)
35228972063SAppaRao Puli         {
35328972063SAppaRao Puli             case fwStateInit:
35428972063SAppaRao Puli             case fwStateIdle:
35528972063SAppaRao Puli             case fwStateError:
35628972063SAppaRao Puli                 resetStatusCache();
35728972063SAppaRao Puli                 break;
35828972063SAppaRao Puli             case fwStateDownload:
35928972063SAppaRao Puli             case fwStateVerify:
36028972063SAppaRao Puli             case fwStateProgram:
36128972063SAppaRao Puli             case fwStateUpdateSuccess:
36228972063SAppaRao Puli                 break;
36328972063SAppaRao Puli             default:
36428972063SAppaRao Puli                 // Error
36528972063SAppaRao Puli                 break;
36628972063SAppaRao Puli         }
36728972063SAppaRao Puli         fwUpdateState = state;
36852ce662cSVernon Mauery     }
percent()36952ce662cSVernon Mauery     uint8_t percent()
37052ce662cSVernon Mauery     {
37128972063SAppaRao Puli         return progressPercent;
37252ce662cSVernon Mauery     }
updateActivationPercent(const std::string & objPath)37328972063SAppaRao Puli     void updateActivationPercent(const std::string& objPath)
37452ce662cSVernon Mauery     {
37528972063SAppaRao Puli         std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
37628972063SAppaRao Puli         fwUpdateState = fwStateProgram;
37728972063SAppaRao Puli         progressPercent = 0;
378f944d2e5SPatrick Williams         match = std::make_shared<sdbusplus::bus::match_t>(
37928972063SAppaRao Puli             *busp,
38052ce662cSVernon Mauery             sdbusplus::bus::match::rules::propertiesChanged(
38128972063SAppaRao Puli                 objPath, "xyz.openbmc_project.Software.ActivationProgress"),
382f944d2e5SPatrick Williams             [&](sdbusplus::message_t& msg) {
38352ce662cSVernon Mauery                 std::map<std::string, ipmi::DbusVariant> props;
38428972063SAppaRao Puli                 std::vector<std::string> inVal;
38552ce662cSVernon Mauery                 std::string iface;
38628972063SAppaRao Puli                 try
38728972063SAppaRao Puli                 {
38828972063SAppaRao Puli                     msg.read(iface, props, inVal);
38928972063SAppaRao Puli                 }
39028972063SAppaRao Puli                 catch (const std::exception& e)
39128972063SAppaRao Puli                 {
39228972063SAppaRao Puli                     phosphor::logging::log<phosphor::logging::level::ERR>(
39328972063SAppaRao Puli                         "Exception caught in get ActivationProgress");
39428972063SAppaRao Puli                     return;
39528972063SAppaRao Puli                 }
39628972063SAppaRao Puli 
39728972063SAppaRao Puli                 auto it = props.find("Progress");
39828972063SAppaRao Puli                 if (it != props.end())
39928972063SAppaRao Puli                 {
40028972063SAppaRao Puli                     progressPercent = std::get<uint8_t>(it->second);
40128972063SAppaRao Puli                     if (progressPercent == 100)
40228972063SAppaRao Puli                     {
40328972063SAppaRao Puli                         fwUpdateState = fwStateUpdateSuccess;
40428972063SAppaRao Puli                     }
40528972063SAppaRao Puli                 }
40652ce662cSVernon Mauery             });
40752ce662cSVernon Mauery     }
activationTimerTimeout()40828972063SAppaRao Puli     uint8_t activationTimerTimeout()
40952ce662cSVernon Mauery     {
41028972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::INFO>(
41128972063SAppaRao Puli             "activationTimerTimeout: Increase percentage...",
41228972063SAppaRao Puli             phosphor::logging::entry("PERCENT:%d", progressPercent));
41328972063SAppaRao Puli         progressPercent = progressPercent + 5;
414b8f2bf95Sjayaprakash Mutyala         if (progressPercent > 95)
41531f88871Sanil kumar appana         {
41631f88871Sanil kumar appana             /*changing the state to ready to update firmware utility */
41728972063SAppaRao Puli             fwUpdateState = fwStateUpdateSuccess;
41831f88871Sanil kumar appana         }
41928972063SAppaRao Puli         return progressPercent;
42052ce662cSVernon Mauery     }
42131f88871Sanil kumar appana     /* API for changing state to ERROR  */
firmwareUpdateAbortState()42231f88871Sanil kumar appana     void firmwareUpdateAbortState()
42331f88871Sanil kumar appana     {
42428972063SAppaRao Puli         unlink(firmwareBufferFile);
42531f88871Sanil kumar appana         // changing the state to error
42628972063SAppaRao Puli         fwUpdateState = fwStateError;
42731f88871Sanil kumar appana     }
setDeferRestart(bool deferRestart)42831f88871Sanil kumar appana     void setDeferRestart(bool deferRestart)
42931f88871Sanil kumar appana     {
43028972063SAppaRao Puli         deferRestartState = deferRestart;
43131f88871Sanil kumar appana     }
setInhibitDowngrade(bool inhibitDowngrade)43231f88871Sanil kumar appana     void setInhibitDowngrade(bool inhibitDowngrade)
43331f88871Sanil kumar appana     {
43428972063SAppaRao Puli         inhibitDowngradeState = inhibitDowngrade;
43531f88871Sanil kumar appana     }
getDeferRestart()43631f88871Sanil kumar appana     bool getDeferRestart()
43731f88871Sanil kumar appana     {
43828972063SAppaRao Puli         return deferRestartState;
43931f88871Sanil kumar appana     }
getInhibitDowngrade()44031f88871Sanil kumar appana     bool getInhibitDowngrade()
44131f88871Sanil kumar appana     {
44228972063SAppaRao Puli         return inhibitDowngradeState;
44331f88871Sanil kumar appana     }
44431f88871Sanil kumar appana 
44552ce662cSVernon Mauery   protected:
44628972063SAppaRao Puli     std::shared_ptr<sdbusplus::asio::connection> busp;
447f944d2e5SPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> match;
44828972063SAppaRao Puli     uint8_t fwUpdateState = 0;
44928972063SAppaRao Puli     uint8_t progressPercent = 0;
45028972063SAppaRao Puli     bool deferRestartState = false;
45128972063SAppaRao Puli     bool inhibitDowngradeState = false;
45252ce662cSVernon Mauery };
45352ce662cSVernon Mauery 
45428972063SAppaRao Puli static FwUpdateStatusCache fwUpdateStatus;
455153d4c14SArun Lal K M std::unique_ptr<TransferHashCheck> xferHashCheck;
45652ce662cSVernon Mauery 
activateImage(const std::string & objPath)45728972063SAppaRao Puli static void activateImage(const std::string& objPath)
45852ce662cSVernon Mauery {
45928972063SAppaRao Puli     // If flag is false  means to reboot
46028972063SAppaRao Puli     if (fwUpdateStatus.getDeferRestart() == false)
46152ce662cSVernon Mauery     {
46228972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::INFO>(
46328972063SAppaRao Puli             "activating Image: ",
46428972063SAppaRao Puli             phosphor::logging::entry("OBJPATH =%s", objPath.c_str()));
46528972063SAppaRao Puli         std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
46628972063SAppaRao Puli         bus->async_method_call(
46728972063SAppaRao Puli             [](const boost::system::error_code ec) {
46828972063SAppaRao Puli                 if (ec)
46928972063SAppaRao Puli                 {
47028972063SAppaRao Puli                     phosphor::logging::log<phosphor::logging::level::ERR>(
47128972063SAppaRao Puli                         "async_method_call error: activateImage failed");
47228972063SAppaRao Puli                     return;
47352ce662cSVernon Mauery                 }
47428972063SAppaRao Puli             },
47528972063SAppaRao Puli             "xyz.openbmc_project.Software.BMC.Updater", objPath,
47628972063SAppaRao Puli             "org.freedesktop.DBus.Properties", "Set",
47728972063SAppaRao Puli             "xyz.openbmc_project.Software.Activation", "RequestedActivation",
4780748c69dSJason M. Bills             ipmi::DbusVariant("xyz.openbmc_project.Software.Activation."
47928972063SAppaRao Puli                               "RequestedActivations.Active"));
48028972063SAppaRao Puli     }
48128972063SAppaRao Puli     else
48228972063SAppaRao Puli     {
48328972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::INFO>(
48428972063SAppaRao Puli             "Firmware image activation is deferred.");
48528972063SAppaRao Puli     }
48628972063SAppaRao Puli     fwUpdateStatus.setState(
48728972063SAppaRao Puli         static_cast<uint8_t>(FwUpdateStatusCache::fwStateUpdateSuccess));
48852ce662cSVernon Mauery }
48952ce662cSVernon Mauery 
getFirmwareUpdateMode()49009a8314bSAppaRao Puli static bool getFirmwareUpdateMode()
49109a8314bSAppaRao Puli {
49209a8314bSAppaRao Puli     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
49309a8314bSAppaRao Puli     try
49409a8314bSAppaRao Puli     {
49509a8314bSAppaRao Puli         auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
49609a8314bSAppaRao Puli         ipmi::Value state = ipmi::getDbusProperty(
49709a8314bSAppaRao Puli             *busp, service, bmcStatePath, bmcStateIntf, "CurrentBMCState");
49809a8314bSAppaRao Puli         std::string bmcState = std::get<std::string>(state);
49909a8314bSAppaRao Puli         return (bmcState == bmcStateUpdateInProgress);
50009a8314bSAppaRao Puli     }
50109a8314bSAppaRao Puli     catch (const std::exception& e)
50209a8314bSAppaRao Puli     {
50309a8314bSAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
50409a8314bSAppaRao Puli             "Exception caught while getting BMC state.",
50509a8314bSAppaRao Puli             phosphor::logging::entry("EXCEPTION=%s", e.what()));
50609a8314bSAppaRao Puli         throw;
50709a8314bSAppaRao Puli     }
50809a8314bSAppaRao Puli }
50909a8314bSAppaRao Puli 
setFirmwareUpdateMode(const bool mode)51009a8314bSAppaRao Puli static void setFirmwareUpdateMode(const bool mode)
51109a8314bSAppaRao Puli {
51209a8314bSAppaRao Puli     std::string bmcState(bmcStateReady);
51309a8314bSAppaRao Puli     if (mode)
51409a8314bSAppaRao Puli     {
51509a8314bSAppaRao Puli         bmcState = bmcStateUpdateInProgress;
51609a8314bSAppaRao Puli     }
51709a8314bSAppaRao Puli 
51809a8314bSAppaRao Puli     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
51909a8314bSAppaRao Puli     try
52009a8314bSAppaRao Puli     {
52109a8314bSAppaRao Puli         auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
52209a8314bSAppaRao Puli         ipmi::setDbusProperty(*busp, service, bmcStatePath, bmcStateIntf,
52309a8314bSAppaRao Puli                               "CurrentBMCState", bmcState);
52409a8314bSAppaRao Puli     }
52509a8314bSAppaRao Puli     catch (const std::exception& e)
52609a8314bSAppaRao Puli     {
52709a8314bSAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
52809a8314bSAppaRao Puli             "Exception caught while setting BMC state.",
52909a8314bSAppaRao Puli             phosphor::logging::entry("EXCEPTION=%s", e.what()));
53009a8314bSAppaRao Puli         throw;
53109a8314bSAppaRao Puli     }
53209a8314bSAppaRao Puli }
53309a8314bSAppaRao Puli 
534e2cddf68SAppaRao Puli /** @brief check if channel IPMB
535e2cddf68SAppaRao Puli  *
536e2cddf68SAppaRao Puli  *  This function checks if the command is from IPMB
537e2cddf68SAppaRao Puli  *
538e2cddf68SAppaRao Puli  * @param[in] ctx - context of current session.
539e2cddf68SAppaRao Puli  *  @returns true if the medium is IPMB else return true.
540e2cddf68SAppaRao Puli  **/
checkIPMBChannel(const ipmi::Context::ptr & ctx,bool & isIPMBChannel)541e2cddf68SAppaRao Puli ipmi::Cc checkIPMBChannel(const ipmi::Context::ptr& ctx, bool& isIPMBChannel)
542e2cddf68SAppaRao Puli {
543e2cddf68SAppaRao Puli     ipmi::ChannelInfo chInfo;
544e2cddf68SAppaRao Puli 
545e2cddf68SAppaRao Puli     if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
546e2cddf68SAppaRao Puli     {
547e2cddf68SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
548e2cddf68SAppaRao Puli             "Failed to get Channel Info",
549e2cddf68SAppaRao Puli             phosphor::logging::entry("CHANNEL=%d", ctx->channel));
550e2cddf68SAppaRao Puli         return ipmi::ccUnspecifiedError;
551e2cddf68SAppaRao Puli     }
552e2cddf68SAppaRao Puli 
553e2cddf68SAppaRao Puli     if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
554e2cddf68SAppaRao Puli         ipmi::EChannelMediumType::ipmb)
555e2cddf68SAppaRao Puli     {
556e2cddf68SAppaRao Puli         isIPMBChannel = true;
557e2cddf68SAppaRao Puli     }
558e2cddf68SAppaRao Puli     return ipmi::ccSuccess;
559e2cddf68SAppaRao Puli }
560e2cddf68SAppaRao Puli 
postTransferCompleteHandler(std::unique_ptr<sdbusplus::bus::match_t> & fwUpdateMatchSignal)56128972063SAppaRao Puli static void postTransferCompleteHandler(
562f944d2e5SPatrick Williams     std::unique_ptr<sdbusplus::bus::match_t>& fwUpdateMatchSignal)
56352ce662cSVernon Mauery {
56452ce662cSVernon Mauery     // Setup timer for watching signal
5651bcced08SPatrick Williams     static sdbusplus::Timer timer([&fwUpdateMatchSignal]() {
5661bcced08SPatrick Williams         fwUpdateMatchSignal = nullptr;
5671bcced08SPatrick Williams     });
56852ce662cSVernon Mauery 
569f0feb49cSPatrick Williams     static sdbusplus::Timer activationStatusTimer([]() {
570b8f2bf95Sjayaprakash Mutyala         if (fwUpdateStatus.activationTimerTimeout() > 95)
57152ce662cSVernon Mauery         {
57228972063SAppaRao Puli             activationStatusTimer.stop();
57328972063SAppaRao Puli             fwUpdateStatus.setState(
57428972063SAppaRao Puli                 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
57552ce662cSVernon Mauery         }
57652ce662cSVernon Mauery     });
57752ce662cSVernon Mauery 
57852ce662cSVernon Mauery     timer.start(std::chrono::microseconds(5000000), false);
57952ce662cSVernon Mauery 
58052ce662cSVernon Mauery     // callback function for capturing signal
581f944d2e5SPatrick Williams     auto callback = [&](sdbusplus::message_t& m) {
5820748c69dSJason M. Bills         std::vector<
5830748c69dSJason M. Bills             std::pair<std::string,
5840748c69dSJason M. Bills                       std::vector<std::pair<std::string, ipmi::DbusVariant>>>>
58528972063SAppaRao Puli             intfPropsPair;
58628972063SAppaRao Puli         sdbusplus::message::object_path objPath;
58752ce662cSVernon Mauery 
58852ce662cSVernon Mauery         try
58952ce662cSVernon Mauery         {
59028972063SAppaRao Puli             m.read(objPath, intfPropsPair); // Read in the object path
59152ce662cSVernon Mauery                                             // that was just created
59252ce662cSVernon Mauery         }
59328972063SAppaRao Puli         catch (const std::exception& e)
59452ce662cSVernon Mauery         {
59528972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::ERR>(
59628972063SAppaRao Puli                 "Exception caught in reading created object path.");
59728972063SAppaRao Puli             return;
59852ce662cSVernon Mauery         }
59952ce662cSVernon Mauery         // constructing response message
60028972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::INFO>(
60128972063SAppaRao Puli             "New Interface Added.",
60228972063SAppaRao Puli             phosphor::logging::entry("OBJPATH=%s", objPath.str.c_str()));
60328972063SAppaRao Puli         for (auto& interface : intfPropsPair)
60452ce662cSVernon Mauery         {
60552ce662cSVernon Mauery             if (interface.first == "xyz.openbmc_project.Software.Activation")
60652ce662cSVernon Mauery             {
60728972063SAppaRao Puli                 // There are chances of getting two signals for
60828972063SAppaRao Puli                 // InterfacesAdded. So cross check and discrad second instance.
60928972063SAppaRao Puli                 if (fwUpdateMatchSignal == nullptr)
61028972063SAppaRao Puli                 {
61128972063SAppaRao Puli                     return;
61228972063SAppaRao Puli                 }
61328972063SAppaRao Puli                 // Found our interface, disable callbacks
61428972063SAppaRao Puli                 fwUpdateMatchSignal = nullptr;
61552ce662cSVernon Mauery 
61628972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::INFO>(
61728972063SAppaRao Puli                     "Start activationStatusTimer for status.");
61852ce662cSVernon Mauery                 try
61952ce662cSVernon Mauery                 {
62052ce662cSVernon Mauery                     timer.stop();
62128972063SAppaRao Puli                     activationStatusTimer.start(
62252ce662cSVernon Mauery                         std::chrono::microseconds(3000000), true);
62352ce662cSVernon Mauery                 }
62428972063SAppaRao Puli                 catch (const std::exception& e)
62552ce662cSVernon Mauery                 {
62628972063SAppaRao Puli                     phosphor::logging::log<phosphor::logging::level::ERR>(
62728972063SAppaRao Puli                         "Exception caught in start activationStatusTimer.",
62828972063SAppaRao Puli                         phosphor::logging::entry("ERROR=%s", e.what()));
62952ce662cSVernon Mauery                 }
63052ce662cSVernon Mauery 
63128972063SAppaRao Puli                 fwUpdateStatus.updateActivationPercent(objPath.str);
63228972063SAppaRao Puli                 activateImage(objPath.str);
63352ce662cSVernon Mauery             }
63452ce662cSVernon Mauery         }
63552ce662cSVernon Mauery     };
63652ce662cSVernon Mauery 
63752ce662cSVernon Mauery     // Adding matcher
638f944d2e5SPatrick Williams     fwUpdateMatchSignal = std::make_unique<sdbusplus::bus::match_t>(
63915419dd5SVernon Mauery         *getSdBus(),
64052ce662cSVernon Mauery         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
64152ce662cSVernon Mauery         "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
64252ce662cSVernon Mauery         callback);
64352ce662cSVernon Mauery }
startFirmwareUpdate(const std::string & uri)64428972063SAppaRao Puli static bool startFirmwareUpdate(const std::string& uri)
64552ce662cSVernon Mauery {
64628972063SAppaRao Puli     // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
64728972063SAppaRao Puli     // the code gets to this point, the file should be transferred start the
64828972063SAppaRao Puli     // request (creating a new file in /tmp/images causes the update manager to
64928972063SAppaRao Puli     // check if it is ready for activation)
650f944d2e5SPatrick Williams     static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatchSignal;
65128972063SAppaRao Puli     postTransferCompleteHandler(fwUpdateMatchSignal);
652152e9145SJohnathan Mantey     std::string randomFname =
653152e9145SJohnathan Mantey         "/tmp/images/" +
654152e9145SJohnathan Mantey         boost::uuids::to_string(boost::uuids::random_generator()());
655152e9145SJohnathan Mantey     std::error_code fsError{};
656152e9145SJohnathan Mantey     std::filesystem::rename(uri, randomFname, fsError);
657152e9145SJohnathan Mantey     if (fsError)
658152e9145SJohnathan Mantey     {
659152e9145SJohnathan Mantey         // The source and destination may not be in the same
660152e9145SJohnathan Mantey         // filesystem.
661152e9145SJohnathan Mantey         std::filesystem::copy(uri, randomFname, fsError);
662152e9145SJohnathan Mantey         if (fsError)
663152e9145SJohnathan Mantey         {
664152e9145SJohnathan Mantey             phosphor::logging::log<phosphor::logging::level::ERR>(
665152e9145SJohnathan Mantey                 "Unable to move/copy image to destination directory.",
666152e9145SJohnathan Mantey                 phosphor::logging::entry("ERROR=%s",
667152e9145SJohnathan Mantey                                          fsError.message().c_str()));
668152e9145SJohnathan Mantey             return false;
669152e9145SJohnathan Mantey         }
670152e9145SJohnathan Mantey         std::filesystem::remove(uri);
671152e9145SJohnathan Mantey     }
67228972063SAppaRao Puli     return true;
67328972063SAppaRao Puli }
67428972063SAppaRao Puli 
transferImageFromFile(const std::string & uri,bool move=true)675153d4c14SArun Lal K M static bool transferImageFromFile(const std::string& uri, bool move = true)
67652ce662cSVernon Mauery {
67752ce662cSVernon Mauery     std::error_code ec;
67828972063SAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
67928972063SAppaRao Puli         "Transfer Image From File.",
68028972063SAppaRao Puli         phosphor::logging::entry("URI=%s", uri.c_str()));
68152ce662cSVernon Mauery     if (move)
68252ce662cSVernon Mauery     {
68328972063SAppaRao Puli         std::filesystem::rename(uri, firmwareBufferFile, ec);
68452ce662cSVernon Mauery     }
68552ce662cSVernon Mauery     else
68652ce662cSVernon Mauery     {
68728972063SAppaRao Puli         std::filesystem::copy(uri, firmwareBufferFile,
68852ce662cSVernon Mauery                               std::filesystem::copy_options::overwrite_existing,
68952ce662cSVernon Mauery                               ec);
69052ce662cSVernon Mauery     }
69128972063SAppaRao Puli     if (xferHashCheck)
69252ce662cSVernon Mauery     {
69352ce662cSVernon Mauery         MappedFile mappedfw(uri);
694153d4c14SArun Lal K M         if (!xferHashCheck->hash(
695153d4c14SArun Lal K M                 {mappedfw.data(), mappedfw.data() + mappedfw.size()}))
696153d4c14SArun Lal K M         {
697153d4c14SArun Lal K M             phosphor::logging::log<phosphor::logging::level::ERR>(
698153d4c14SArun Lal K M                 "transferImageFromFile: xferHashCheck->hash failed.");
699153d4c14SArun Lal K M             return false;
700153d4c14SArun Lal K M         }
70152ce662cSVernon Mauery     }
70252ce662cSVernon Mauery     if (ec.value())
70352ce662cSVernon Mauery     {
70428972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
70528972063SAppaRao Puli             "Image copy failed.");
706153d4c14SArun Lal K M         return false;
70752ce662cSVernon Mauery     }
708153d4c14SArun Lal K M 
709153d4c14SArun Lal K M     return true;
71052ce662cSVernon Mauery }
71152ce662cSVernon Mauery 
71252ce662cSVernon Mauery template <typename... ArgTypes>
executeCmd(const char * path,ArgTypes &&...tArgs)71352ce662cSVernon Mauery static int executeCmd(const char* path, ArgTypes&&... tArgs)
71452ce662cSVernon Mauery {
71552ce662cSVernon Mauery     boost::process::child execProg(path, const_cast<char*>(tArgs)...);
71652ce662cSVernon Mauery     execProg.wait();
71752ce662cSVernon Mauery     return execProg.exit_code();
71852ce662cSVernon Mauery }
71952ce662cSVernon Mauery 
transferImageFromUsb(const std::string & uri)720153d4c14SArun Lal K M static bool transferImageFromUsb(const std::string& uri)
72152ce662cSVernon Mauery {
722153d4c14SArun Lal K M     bool ret = false;
723153d4c14SArun Lal K M 
72428972063SAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
72528972063SAppaRao Puli         "Transfer Image From USB.",
72628972063SAppaRao Puli         phosphor::logging::entry("URI=%s", uri.c_str()));
72752ce662cSVernon Mauery 
728153d4c14SArun Lal K M     if (executeCmd(usbCtrlPath, "mount", fwUpdateUsbVolImage,
729153d4c14SArun Lal K M                    fwUpdateMountPoint) == 0)
730153d4c14SArun Lal K M     {
73128972063SAppaRao Puli         std::string usb_path = std::string(fwUpdateMountPoint) + "/" + uri;
73228972063SAppaRao Puli         ret = transferImageFromFile(usb_path, false);
73352ce662cSVernon Mauery 
734153d4c14SArun Lal K M         executeCmd(usbCtrlPath, "cleanup", fwUpdateUsbVolImage,
735153d4c14SArun Lal K M                    fwUpdateMountPoint);
736153d4c14SArun Lal K M     }
737153d4c14SArun Lal K M 
73852ce662cSVernon Mauery     return ret;
73952ce662cSVernon Mauery }
74052ce662cSVernon Mauery 
transferFirmwareFromUri(const std::string & uri)74128972063SAppaRao Puli static bool transferFirmwareFromUri(const std::string& uri)
74252ce662cSVernon Mauery {
74328972063SAppaRao Puli     static constexpr char fwUriFile[] = "file://";
74428972063SAppaRao Puli     static constexpr char fwUriUsb[] = "usb://";
74528972063SAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
74628972063SAppaRao Puli         "Transfer Image From URI.",
74728972063SAppaRao Puli         phosphor::logging::entry("URI=%s", uri.c_str()));
74828972063SAppaRao Puli     if (boost::algorithm::starts_with(uri, fwUriFile))
74952ce662cSVernon Mauery     {
75028972063SAppaRao Puli         std::string fname = uri.substr(sizeof(fwUriFile) - 1);
75128972063SAppaRao Puli         if (fname != firmwareBufferFile)
75252ce662cSVernon Mauery         {
753153d4c14SArun Lal K M             return transferImageFromFile(fname);
75452ce662cSVernon Mauery         }
75552ce662cSVernon Mauery         return true;
75652ce662cSVernon Mauery     }
75728972063SAppaRao Puli     if (boost::algorithm::starts_with(uri, fwUriUsb))
75852ce662cSVernon Mauery     {
75928972063SAppaRao Puli         std::string fname = uri.substr(sizeof(fwUriUsb) - 1);
760153d4c14SArun Lal K M         return transferImageFromUsb(fname);
76152ce662cSVernon Mauery     }
76252ce662cSVernon Mauery     return false;
76352ce662cSVernon Mauery }
76452ce662cSVernon Mauery 
76552ce662cSVernon Mauery /* Get USB-mass-storage device status: inserted => true, ejected => false */
getUsbStatus()76628972063SAppaRao Puli static bool getUsbStatus()
76752ce662cSVernon Mauery {
76828972063SAppaRao Puli     std::filesystem::path usbDevPath =
76928972063SAppaRao Puli         std::filesystem::path("/sys/kernel/config/usb_gadget") /
77028972063SAppaRao Puli         fwUpdateUSBDevName;
77128972063SAppaRao Puli     return (std::filesystem::exists(usbDevPath) ? true : false);
77252ce662cSVernon Mauery }
77352ce662cSVernon Mauery 
77452ce662cSVernon Mauery /* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
attachUsbDevice()77528972063SAppaRao Puli static int attachUsbDevice()
77652ce662cSVernon Mauery {
77728972063SAppaRao Puli     if (getUsbStatus())
77852ce662cSVernon Mauery     {
77952ce662cSVernon Mauery         return 1;
78052ce662cSVernon Mauery     }
78128972063SAppaRao Puli     int ret = executeCmd(usbCtrlPath, "setup", fwUpdateUsbVolImage,
78228972063SAppaRao Puli                          std::to_string(maxFirmwareImageSize / 1_MB).c_str());
78352ce662cSVernon Mauery     if (!ret)
78452ce662cSVernon Mauery     {
78528972063SAppaRao Puli         ret = executeCmd(usbCtrlPath, "insert", fwUpdateUSBDevName,
78628972063SAppaRao Puli                          fwUpdateUsbVolImage);
78752ce662cSVernon Mauery     }
78852ce662cSVernon Mauery     return ret;
78952ce662cSVernon Mauery }
79052ce662cSVernon Mauery 
79152ce662cSVernon Mauery /* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
detachUsbDevice()79228972063SAppaRao Puli static int detachUsbDevice()
79352ce662cSVernon Mauery {
79428972063SAppaRao Puli     if (!getUsbStatus())
79552ce662cSVernon Mauery     {
79652ce662cSVernon Mauery         return 1;
79752ce662cSVernon Mauery     }
79828972063SAppaRao Puli     return executeCmd(usbCtrlPath, "eject", fwUpdateUSBDevName);
79928972063SAppaRao Puli }
getActiveBootImage(ipmi::Context::ptr ctx)80028972063SAppaRao Puli static uint8_t getActiveBootImage(ipmi::Context::ptr ctx)
80128972063SAppaRao Puli {
802e319ecf5STerry S. Duncan     constexpr uint8_t undefinedImage = 0x00;
80328972063SAppaRao Puli     constexpr uint8_t primaryImage = 0x01;
80428972063SAppaRao Puli     constexpr uint8_t secondaryImage = 0x02;
80528972063SAppaRao Puli     constexpr const char* secondaryFitImageStartAddr = "22480000";
80628972063SAppaRao Puli 
80728972063SAppaRao Puli     uint8_t bootImage = primaryImage;
80828972063SAppaRao Puli     boost::system::error_code ec;
80928972063SAppaRao Puli     std::string value = ctx->bus->yield_method_call<std::string>(
81028972063SAppaRao Puli         ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
81128972063SAppaRao Puli         "/xyz/openbmc_project/u_boot/environment/mgr",
81228972063SAppaRao Puli         "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
81328972063SAppaRao Puli     if (ec)
81428972063SAppaRao Puli     {
81528972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
81628972063SAppaRao Puli             "Failed to read the bootcmd value");
817e319ecf5STerry S. Duncan         /* don't fail, just give back undefined until it is ready */
818e319ecf5STerry S. Duncan         bootImage = undefinedImage;
81952ce662cSVernon Mauery     }
82052ce662cSVernon Mauery 
82128972063SAppaRao Puli     /* cheking for secondary FitImage Address 22480000  */
822e319ecf5STerry S. Duncan     else if (value.find(secondaryFitImageStartAddr) != std::string::npos)
82352ce662cSVernon Mauery     {
82428972063SAppaRao Puli         bootImage = secondaryImage;
82552ce662cSVernon Mauery     }
82652ce662cSVernon Mauery     else
82752ce662cSVernon Mauery     {
82828972063SAppaRao Puli         bootImage = primaryImage;
82952ce662cSVernon Mauery     }
83052ce662cSVernon Mauery 
83128972063SAppaRao Puli     return bootImage;
83252ce662cSVernon Mauery }
83352ce662cSVernon Mauery 
83437fde6b6SAppaRao Puli #ifdef INTEL_PFR_ENABLED
8351bcced08SPatrick Williams using fwVersionInfoType =
8361bcced08SPatrick Williams     std::tuple<uint8_t,   // ID Tag
83737fde6b6SAppaRao Puli                uint8_t,   // Major Version Number
83837fde6b6SAppaRao Puli                uint8_t,   // Minor Version Number
83937fde6b6SAppaRao Puli                uint32_t,  // Build Number
84037fde6b6SAppaRao Puli                uint32_t,  // Build Timestamp
84137fde6b6SAppaRao Puli                uint32_t>; // Update Timestamp
ipmiGetFwVersionInfo()84237fde6b6SAppaRao Puli ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
84352ce662cSVernon Mauery {
84452ce662cSVernon Mauery     // Byte 1 - Count (N) Number of devices data is being returned for.
84537fde6b6SAppaRao Puli     // Bytes  2:16 - Device firmare information(fwVersionInfoType)
84652ce662cSVernon Mauery     // Bytes - 17:(15xN) - Repeat of 2 through 16
84752ce662cSVernon Mauery 
84837fde6b6SAppaRao Puli     std::vector<fwVersionInfoType> fwVerInfoList;
84937fde6b6SAppaRao Puli     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
85037fde6b6SAppaRao Puli     for (const auto& fwDev : fwVersionIdMap)
85152ce662cSVernon Mauery     {
85237fde6b6SAppaRao Puli         std::string verStr;
85352ce662cSVernon Mauery         try
85452ce662cSVernon Mauery         {
85537fde6b6SAppaRao Puli             auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
85652ce662cSVernon Mauery 
85737fde6b6SAppaRao Puli             ipmi::Value result = ipmi::getDbusProperty(
85837fde6b6SAppaRao Puli                 *busp, service, fwDev.second, versionIntf, "Version");
85937fde6b6SAppaRao Puli             verStr = std::get<std::string>(result);
86037fde6b6SAppaRao Puli         }
86137fde6b6SAppaRao Puli         catch (const std::exception& e)
86237fde6b6SAppaRao Puli         {
86337fde6b6SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
86437fde6b6SAppaRao Puli                 "Failed to fetch Version property",
86537fde6b6SAppaRao Puli                 phosphor::logging::entry("ERROR=%s", e.what()),
86637fde6b6SAppaRao Puli                 phosphor::logging::entry("PATH=%s", fwDev.second),
86737fde6b6SAppaRao Puli                 phosphor::logging::entry("INTERFACE=%s", versionIntf));
86852ce662cSVernon Mauery             continue;
86952ce662cSVernon Mauery         }
87052ce662cSVernon Mauery 
87137fde6b6SAppaRao Puli         if (verStr.empty())
87237fde6b6SAppaRao Puli         {
87337fde6b6SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
87437fde6b6SAppaRao Puli                 "Version is empty.",
87537fde6b6SAppaRao Puli                 phosphor::logging::entry("PATH=%s", fwDev.second),
87637fde6b6SAppaRao Puli                 phosphor::logging::entry("INTERFACE=%s", versionIntf));
87737fde6b6SAppaRao Puli             continue;
87852ce662cSVernon Mauery         }
87952ce662cSVernon Mauery 
88052a292b8Ssrikanta mondal         uint8_t majorNum = 0;
88152a292b8Ssrikanta mondal         uint8_t minorNum = 0;
88252a292b8Ssrikanta mondal         uint32_t buildNum = 0;
88352a292b8Ssrikanta mondal         try
88452a292b8Ssrikanta mondal         {
88552a292b8Ssrikanta mondal             std::optional<ipmi::MetaRevision> rev =
88652a292b8Ssrikanta mondal                 ipmi::convertIntelVersion(verStr);
88752a292b8Ssrikanta mondal             if (rev.has_value())
88852a292b8Ssrikanta mondal             {
88952a292b8Ssrikanta mondal                 ipmi::MetaRevision revision = rev.value();
89052a292b8Ssrikanta mondal                 majorNum = revision.major % 10 + (revision.major / 10) * 16;
89152a292b8Ssrikanta mondal                 minorNum = (revision.minor > 99 ? 99 : revision.minor);
89252a292b8Ssrikanta mondal                 minorNum = minorNum % 10 + (minorNum / 10) * 16;
89352a292b8Ssrikanta mondal                 uint32_t hash = std::stoul(revision.metaHash, 0, 16);
89452a292b8Ssrikanta mondal                 hash = bswap_32(hash);
89552a292b8Ssrikanta mondal                 buildNum = (revision.buildNo & 0xFF) + (hash & 0xFFFFFF00);
89652a292b8Ssrikanta mondal             }
89752a292b8Ssrikanta mondal             else
89852a292b8Ssrikanta mondal             {
89937fde6b6SAppaRao Puli                 std::vector<std::string> splitVer;
90037fde6b6SAppaRao Puli                 boost::split(splitVer, verStr, boost::is_any_of(".-"));
90137fde6b6SAppaRao Puli                 if (splitVer.size() < 3)
90237fde6b6SAppaRao Puli                 {
90337fde6b6SAppaRao Puli                     phosphor::logging::log<phosphor::logging::level::INFO>(
90437fde6b6SAppaRao Puli                         "Invalid Version format.",
90537fde6b6SAppaRao Puli                         phosphor::logging::entry("Version=%s", verStr.c_str()),
90637fde6b6SAppaRao Puli                         phosphor::logging::entry("PATH=%s", fwDev.second));
90737fde6b6SAppaRao Puli                     continue;
90852ce662cSVernon Mauery                 }
90937fde6b6SAppaRao Puli                 majorNum = std::stoul(splitVer[0], nullptr, 16);
91037fde6b6SAppaRao Puli                 minorNum = std::stoul(splitVer[1], nullptr, 16);
91137fde6b6SAppaRao Puli                 buildNum = std::stoul(splitVer[2], nullptr, 16);
91237fde6b6SAppaRao Puli             }
91352a292b8Ssrikanta mondal             // Build Timestamp - Not supported.
91452a292b8Ssrikanta mondal             // Update Timestamp - TODO: Need to check with CPLD team.
91552a292b8Ssrikanta mondal             fwVerInfoList.emplace_back(
91652a292b8Ssrikanta mondal                 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
91752a292b8Ssrikanta mondal                                   minorNum, buildNum, 0, 0));
91852a292b8Ssrikanta mondal         }
91937fde6b6SAppaRao Puli         catch (const std::exception& e)
92037fde6b6SAppaRao Puli         {
92137fde6b6SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
92237fde6b6SAppaRao Puli                 "Failed to convert stoul.",
92337fde6b6SAppaRao Puli                 phosphor::logging::entry("ERROR=%s", e.what()));
92437fde6b6SAppaRao Puli             continue;
92537fde6b6SAppaRao Puli         }
92637fde6b6SAppaRao Puli     }
92737fde6b6SAppaRao Puli 
92837fde6b6SAppaRao Puli     return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
92937fde6b6SAppaRao Puli }
930a8dd197aSPunith Nadur Basavarajaiah 
getSecurityVersionInfo(const char * mtdDevBuf,size_t svnVerOffsetInPfm,size_t bkcVerOffsetInPfm)9311bcced08SPatrick Williams std::array<uint8_t, imageCount> getSecurityVersionInfo(
9321bcced08SPatrick Williams     const char* mtdDevBuf, size_t svnVerOffsetInPfm, size_t bkcVerOffsetInPfm)
933a8dd197aSPunith Nadur Basavarajaiah {
934a8dd197aSPunith Nadur Basavarajaiah     constexpr size_t bufLength = 1;
935a8dd197aSPunith Nadur Basavarajaiah     std::array<uint8_t, imageCount> fwSecurityVersionBuf = {0}, temp;
936a8dd197aSPunith Nadur Basavarajaiah     constexpr uint8_t svnIndexValue = 0x00;
937a8dd197aSPunith Nadur Basavarajaiah     constexpr uint8_t bkcIndexValue = 0x01;
938a8dd197aSPunith Nadur Basavarajaiah     constexpr uint8_t tempIndexValue = 0x00;
939a8dd197aSPunith Nadur Basavarajaiah     try
940a8dd197aSPunith Nadur Basavarajaiah     {
941a8dd197aSPunith Nadur Basavarajaiah         SPIDev spiDev(mtdDevBuf);
942a8dd197aSPunith Nadur Basavarajaiah         spiDev.spiReadData(svnVerOffsetInPfm, bufLength, temp.data());
943a8dd197aSPunith Nadur Basavarajaiah         fwSecurityVersionBuf.at(svnIndexValue) = temp.at(tempIndexValue);
944a8dd197aSPunith Nadur Basavarajaiah         spiDev.spiReadData(bkcVerOffsetInPfm, bufLength, temp.data());
945a8dd197aSPunith Nadur Basavarajaiah         fwSecurityVersionBuf.at(bkcIndexValue) = temp.at(tempIndexValue);
946a8dd197aSPunith Nadur Basavarajaiah     }
947a8dd197aSPunith Nadur Basavarajaiah     catch (const std::exception& e)
948a8dd197aSPunith Nadur Basavarajaiah     {
949a8dd197aSPunith Nadur Basavarajaiah         phosphor::logging::log<phosphor::logging::level::ERR>(
950a8dd197aSPunith Nadur Basavarajaiah             "Exception caught in getSecurityVersionInfo",
951a8dd197aSPunith Nadur Basavarajaiah             phosphor::logging::entry("MSG=%s", e.what()));
952a8dd197aSPunith Nadur Basavarajaiah         fwSecurityVersionBuf = {0, 0};
953a8dd197aSPunith Nadur Basavarajaiah     }
954a8dd197aSPunith Nadur Basavarajaiah 
955a8dd197aSPunith Nadur Basavarajaiah     return fwSecurityVersionBuf;
956a8dd197aSPunith Nadur Basavarajaiah }
957a8dd197aSPunith Nadur Basavarajaiah 
958a8dd197aSPunith Nadur Basavarajaiah ipmi::RspType<
959a8dd197aSPunith Nadur Basavarajaiah     uint8_t,                         // device ID
960a8dd197aSPunith Nadur Basavarajaiah     uint8_t,                         // Active Image Value
961a8dd197aSPunith Nadur Basavarajaiah     std::array<uint8_t, imageCount>, // Security version for Active Image
962a8dd197aSPunith Nadur Basavarajaiah     uint8_t,                         // recovery Image Value
963a8dd197aSPunith Nadur Basavarajaiah     std::array<uint8_t, imageCount>> // Security version for Recovery Image
ipmiGetFwSecurityVersionInfo()96428972063SAppaRao Puli     ipmiGetFwSecurityVersionInfo()
96552ce662cSVernon Mauery {
966a8dd197aSPunith Nadur Basavarajaiah     static bool cacheFlag = false;
967a8dd197aSPunith Nadur Basavarajaiah     constexpr std::array<const char*, imageCount> mtdDevBuf = {
968a8dd197aSPunith Nadur Basavarajaiah         bmcActivePfmMTDDev, bmcRecoveryImgMTDDev};
969a8dd197aSPunith Nadur Basavarajaiah 
970a8dd197aSPunith Nadur Basavarajaiah     // To avoid multiple reading from SPI device
971a8dd197aSPunith Nadur Basavarajaiah     if (!cacheFlag)
972a8dd197aSPunith Nadur Basavarajaiah     {
973a8dd197aSPunith Nadur Basavarajaiah         imgFwSecurityVersion[0] = getSecurityVersionInfo(
974a8dd197aSPunith Nadur Basavarajaiah             mtdDevBuf[0], svnActiveVerOffsetInPfm, bkcActiveVerOffsetInPfm);
975a8dd197aSPunith Nadur Basavarajaiah         imgFwSecurityVersion[1] = getSecurityVersionInfo(
976a8dd197aSPunith Nadur Basavarajaiah             mtdDevBuf[1], svnRecoveryVerOffsetInPfm, bkcRecoveryVerOffsetInPfm);
977a8dd197aSPunith Nadur Basavarajaiah         cacheFlag = true;
978a8dd197aSPunith Nadur Basavarajaiah     }
979a8dd197aSPunith Nadur Basavarajaiah 
980a8dd197aSPunith Nadur Basavarajaiah     constexpr uint8_t ActivePfmMTDDev = 0x00;
981a8dd197aSPunith Nadur Basavarajaiah     constexpr uint8_t RecoveryImgMTDDev = 0x01;
982a8dd197aSPunith Nadur Basavarajaiah 
983a8dd197aSPunith Nadur Basavarajaiah     return ipmi::responseSuccess(
984a8dd197aSPunith Nadur Basavarajaiah         imageCount, static_cast<uint8_t>(FWDeviceIDTag::bmcActiveImage),
985a8dd197aSPunith Nadur Basavarajaiah         imgFwSecurityVersion[ActivePfmMTDDev],
986a8dd197aSPunith Nadur Basavarajaiah         static_cast<uint8_t>(FWDeviceIDTag::bmcRecoveryImage),
987a8dd197aSPunith Nadur Basavarajaiah         imgFwSecurityVersion[RecoveryImgMTDDev]);
98852ce662cSVernon Mauery }
989c8864062SRajashekar Gade Reddy 
990c8864062SRajashekar Gade Reddy ipmi::RspType<std::array<uint8_t, certKeyLen>,
991c8864062SRajashekar Gade Reddy               std::optional<std::array<uint8_t, cskSignatureLen>>>
ipmiGetFwRootCertData(const ipmi::Context::ptr & ctx,uint8_t certId)9925b1988b1SRajashekar Gade Reddy     ipmiGetFwRootCertData(const ipmi::Context::ptr& ctx, uint8_t certId)
99352ce662cSVernon Mauery {
9945b1988b1SRajashekar Gade Reddy     bool isIPMBChannel = false;
9955b1988b1SRajashekar Gade Reddy 
9965b1988b1SRajashekar Gade Reddy     if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
9975b1988b1SRajashekar Gade Reddy     {
9985b1988b1SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
9995b1988b1SRajashekar Gade Reddy     }
10005b1988b1SRajashekar Gade Reddy     if (isIPMBChannel)
10015b1988b1SRajashekar Gade Reddy     {
10025b1988b1SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::INFO>(
10035b1988b1SRajashekar Gade Reddy             "Command not supported. Failed to get root certificate data.");
10045b1988b1SRajashekar Gade Reddy         return ipmi::responseCommandNotAvailable();
10055b1988b1SRajashekar Gade Reddy     }
10065b1988b1SRajashekar Gade Reddy 
1007c8864062SRajashekar Gade Reddy     size_t certKeyOffset = 0;
1008c8864062SRajashekar Gade Reddy     size_t cskSigOffset = 0;
1009c8864062SRajashekar Gade Reddy     std::string mtdDev;
101052ce662cSVernon Mauery 
1011c8864062SRajashekar Gade Reddy     switch (static_cast<FwGetRootCertDataTag>(certId))
1012c8864062SRajashekar Gade Reddy     {
1013c8864062SRajashekar Gade Reddy         case FwGetRootCertDataTag::activeRootKey:
1014c8864062SRajashekar Gade Reddy         {
1015c8864062SRajashekar Gade Reddy             mtdDev = bmcActivePfmMTDDev;
1016c8864062SRajashekar Gade Reddy             certKeyOffset = rootkeyOffsetInPfm;
1017c8864062SRajashekar Gade Reddy             break;
1018c8864062SRajashekar Gade Reddy         }
1019c8864062SRajashekar Gade Reddy         case FwGetRootCertDataTag::recoveryRootKey:
1020c8864062SRajashekar Gade Reddy         {
1021c8864062SRajashekar Gade Reddy             mtdDev = bmcRecoveryImgMTDDev;
1022c8864062SRajashekar Gade Reddy             certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
1023c8864062SRajashekar Gade Reddy             break;
1024c8864062SRajashekar Gade Reddy         }
1025c8864062SRajashekar Gade Reddy         case FwGetRootCertDataTag::activeCSK:
1026c8864062SRajashekar Gade Reddy         {
1027c8864062SRajashekar Gade Reddy             mtdDev = bmcActivePfmMTDDev;
1028c8864062SRajashekar Gade Reddy             certKeyOffset = cskKeyOffsetInPfm;
1029c8864062SRajashekar Gade Reddy             cskSigOffset = cskSignatureOffsetInPfm;
1030c8864062SRajashekar Gade Reddy             break;
1031c8864062SRajashekar Gade Reddy         }
1032c8864062SRajashekar Gade Reddy         case FwGetRootCertDataTag::recoveryCSK:
1033c8864062SRajashekar Gade Reddy         {
1034c8864062SRajashekar Gade Reddy             mtdDev = bmcRecoveryImgMTDDev;
1035c8864062SRajashekar Gade Reddy             certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
1036c8864062SRajashekar Gade Reddy             cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
1037c8864062SRajashekar Gade Reddy             break;
1038c8864062SRajashekar Gade Reddy         }
1039c8864062SRajashekar Gade Reddy         default:
1040c8864062SRajashekar Gade Reddy         {
1041c8864062SRajashekar Gade Reddy             return ipmi::responseInvalidFieldRequest();
1042c8864062SRajashekar Gade Reddy         }
1043c8864062SRajashekar Gade Reddy     }
104452ce662cSVernon Mauery 
1045c8864062SRajashekar Gade Reddy     std::array<uint8_t, certKeyLen> certKey = {0};
104652ce662cSVernon Mauery 
104752ce662cSVernon Mauery     try
104852ce662cSVernon Mauery     {
1049c8864062SRajashekar Gade Reddy         SPIDev spiDev(mtdDev);
1050c8864062SRajashekar Gade Reddy         spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
1051c8864062SRajashekar Gade Reddy 
1052c8864062SRajashekar Gade Reddy         if (cskSigOffset)
105352ce662cSVernon Mauery         {
1054c8864062SRajashekar Gade Reddy             std::array<uint8_t, cskSignatureLen> cskSignature = {0};
1055c8864062SRajashekar Gade Reddy             spiDev.spiReadData(cskSigOffset, cskSignatureLen,
1056c8864062SRajashekar Gade Reddy                                cskSignature.data());
1057c8864062SRajashekar Gade Reddy             return ipmi::responseSuccess(certKey, cskSignature);
105852ce662cSVernon Mauery         }
1059c8864062SRajashekar Gade Reddy     }
1060c8864062SRajashekar Gade Reddy     catch (const std::exception& e)
106152ce662cSVernon Mauery     {
1062c8864062SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::ERR>(
1063c8864062SRajashekar Gade Reddy             "Exception caught in ipmiGetFwRootCertData",
1064c8864062SRajashekar Gade Reddy             phosphor::logging::entry("MSG=%s", e.what()));
1065c8864062SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
106652ce662cSVernon Mauery     }
106752ce662cSVernon Mauery 
1068c8864062SRajashekar Gade Reddy     return ipmi::responseSuccess(certKey, std::nullopt);
106952ce662cSVernon Mauery }
107028972063SAppaRao Puli #endif // INTEL_PFR_ENABLED
107128972063SAppaRao Puli 
107228972063SAppaRao Puli static constexpr uint8_t channelListSize = 3;
107328972063SAppaRao Puli /** @brief implements Maximum Firmware Transfer size command
107428972063SAppaRao Puli  *  @parameter
107528972063SAppaRao Puli  *   -  none
107628972063SAppaRao Puli  *  @returns IPMI completion code plus response data
107728972063SAppaRao Puli  *   - count - channel count
107828972063SAppaRao Puli  *   - channelList - channel list information
107928972063SAppaRao Puli  */
108028972063SAppaRao Puli ipmi::RspType<uint8_t,                    // channel count
108128972063SAppaRao Puli               std::array<std::tuple<uint8_t, uint32_t>,
108228972063SAppaRao Puli                          channelListSize> // Channel List
108328972063SAppaRao Puli               >
ipmiFirmwareMaxTransferSize()108428972063SAppaRao Puli     ipmiFirmwareMaxTransferSize()
108528972063SAppaRao Puli {
108628972063SAppaRao Puli     constexpr size_t kcsMaxBufSize = 128;
108728972063SAppaRao Puli     constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
108828972063SAppaRao Puli     // Byte 1 - Count (N) Number of devices data is being returned for.
108928972063SAppaRao Puli     // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
109028972063SAppaRao Puli     // Byte 3-6 - transfer size (little endian)
109128972063SAppaRao Puli     // Bytes - 7:(5xN) - Repeat of 2 through 6
109228972063SAppaRao Puli     constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
109328972063SAppaRao Puli         channelList = {
109428972063SAppaRao Puli             {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
109528972063SAppaRao Puli              {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
109628972063SAppaRao Puli               rmcpPlusMaxBufSize}}};
109728972063SAppaRao Puli 
109828972063SAppaRao Puli     return ipmi::responseSuccess(channelListSize, channelList);
109928972063SAppaRao Puli }
110028972063SAppaRao Puli 
110128972063SAppaRao Puli ipmi::RspType<uint8_t, uint8_t>
ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)110228972063SAppaRao Puli     ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
110328972063SAppaRao Puli {
110428972063SAppaRao Puli     // Byte 1 - Current execution context
110528972063SAppaRao Puli     //          0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
110628972063SAppaRao Puli     // Byte 2 - Partition pointer
110728972063SAppaRao Puli     //          0x01 - primary, 0x02 - secondary
110828972063SAppaRao Puli     uint8_t partitionPtr = getActiveBootImage(ctx);
110928972063SAppaRao Puli 
111028972063SAppaRao Puli     return ipmi::responseSuccess(
111128972063SAppaRao Puli         static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
111228972063SAppaRao Puli }
111328972063SAppaRao Puli /** @brief Get Firmware Update Random Number
111428972063SAppaRao Puli  *
111528972063SAppaRao Puli  *  This function generate the random number used for
111628972063SAppaRao Puli  *  setting the firmware update mode as authentication key.
111728972063SAppaRao Puli  *
11185b1988b1SRajashekar Gade Reddy  * @param[in] ctx - context of current session
111928972063SAppaRao Puli  *  @returns IPMI completion code along with
112028972063SAppaRao Puli  *   - random number
112128972063SAppaRao Puli  **/
112228972063SAppaRao Puli ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr & ctx)11235b1988b1SRajashekar Gade Reddy     ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr& ctx)
112428972063SAppaRao Puli {
112528972063SAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
112628972063SAppaRao Puli         "Generate FW update random number");
11275b1988b1SRajashekar Gade Reddy     bool isIPMBChannel = false;
11285b1988b1SRajashekar Gade Reddy 
11295b1988b1SRajashekar Gade Reddy     if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
11305b1988b1SRajashekar Gade Reddy     {
11315b1988b1SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
11325b1988b1SRajashekar Gade Reddy     }
11335b1988b1SRajashekar Gade Reddy     if (isIPMBChannel)
11345b1988b1SRajashekar Gade Reddy     {
11355b1988b1SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::INFO>(
11365b1988b1SRajashekar Gade Reddy             "Channel not supported. Failed to fetch FW update random number");
11375b1988b1SRajashekar Gade Reddy         return ipmi::responseCommandNotAvailable();
11385b1988b1SRajashekar Gade Reddy     }
113928972063SAppaRao Puli     std::random_device rd;
114028972063SAppaRao Puli     std::default_random_engine gen(rd());
114128972063SAppaRao Puli     std::uniform_int_distribution<> dist{0, 255};
114228972063SAppaRao Puli 
114328972063SAppaRao Puli     fwRandomNumGenTs = std::chrono::steady_clock::now();
114428972063SAppaRao Puli 
1145dcff1506SVernon Mauery     for (size_t i = 0; i < fwRandomNumLength; i++)
114628972063SAppaRao Puli     {
114728972063SAppaRao Puli         fwRandomNum[i] = dist(gen);
114828972063SAppaRao Puli     }
114928972063SAppaRao Puli 
115028972063SAppaRao Puli     return ipmi::responseSuccess(fwRandomNum);
115128972063SAppaRao Puli }
115228972063SAppaRao Puli 
115328972063SAppaRao Puli /** @brief Set Firmware Update Mode
115428972063SAppaRao Puli  *
115528972063SAppaRao Puli  *  This function sets BMC into firmware update mode
115628972063SAppaRao Puli  *  after validating Random number obtained from the Get
115728972063SAppaRao Puli  *  Firmware Update Random Number command
115828972063SAppaRao Puli  *
11595b1988b1SRajashekar Gade Reddy  * @param[in] ctx - context of current session
11605b1988b1SRajashekar Gade Reddy  * @parameter randNum - Random number(token)
116128972063SAppaRao Puli  * @returns IPMI completion code
116228972063SAppaRao Puli  **/
116328972063SAppaRao Puli ipmi::RspType<>
ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr & ctx,std::array<uint8_t,fwRandomNumLength> & randNum)11645b1988b1SRajashekar Gade Reddy     ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr& ctx,
11655b1988b1SRajashekar Gade Reddy                               std::array<uint8_t, fwRandomNumLength>& randNum)
116628972063SAppaRao Puli {
116728972063SAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
116828972063SAppaRao Puli         "Start FW update mode");
11695b1988b1SRajashekar Gade Reddy 
11705b1988b1SRajashekar Gade Reddy     bool isIPMBChannel = false;
11715b1988b1SRajashekar Gade Reddy 
11725b1988b1SRajashekar Gade Reddy     if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
11735b1988b1SRajashekar Gade Reddy     {
11745b1988b1SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
11755b1988b1SRajashekar Gade Reddy     }
11765b1988b1SRajashekar Gade Reddy     if (isIPMBChannel)
11775b1988b1SRajashekar Gade Reddy     {
11785b1988b1SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::INFO>(
11795b1988b1SRajashekar Gade Reddy             "Channel not supported. Failed to set FW update mode");
11805b1988b1SRajashekar Gade Reddy         return ipmi::responseCommandNotAvailable();
11815b1988b1SRajashekar Gade Reddy     }
118228972063SAppaRao Puli     /* Firmware Update Random number is valid for 30 seconds only */
118328972063SAppaRao Puli     auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
118428972063SAppaRao Puli     if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
118528972063SAppaRao Puli             .count() > std::chrono::duration_cast<std::chrono::microseconds>(
118628972063SAppaRao Puli                            fwRandomNumExpirySeconds)
118728972063SAppaRao Puli                            .count())
118828972063SAppaRao Puli     {
118928972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::INFO>(
119028972063SAppaRao Puli             "Firmware update random number expired.");
119128972063SAppaRao Puli         return ipmi::responseInvalidFieldRequest();
119228972063SAppaRao Puli     }
119328972063SAppaRao Puli 
119428972063SAppaRao Puli     /* Validate random number */
1195dcff1506SVernon Mauery     for (size_t i = 0; i < fwRandomNumLength; i++)
119628972063SAppaRao Puli     {
119728972063SAppaRao Puli         if (fwRandomNum[i] != randNum[i])
119828972063SAppaRao Puli         {
119928972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
120028972063SAppaRao Puli                 "Invalid random number specified.");
120128972063SAppaRao Puli             return ipmi::responseInvalidFieldRequest();
120228972063SAppaRao Puli         }
120328972063SAppaRao Puli     }
120428972063SAppaRao Puli 
120528972063SAppaRao Puli     try
120628972063SAppaRao Puli     {
120728972063SAppaRao Puli         if (getFirmwareUpdateMode())
120828972063SAppaRao Puli         {
120928972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
121028972063SAppaRao Puli                 "Already firmware update is in progress.");
121128972063SAppaRao Puli             return ipmi::responseBusy();
121228972063SAppaRao Puli         }
121328972063SAppaRao Puli     }
121428972063SAppaRao Puli     catch (const std::exception& e)
121528972063SAppaRao Puli     {
121628972063SAppaRao Puli         return ipmi::responseUnspecifiedError();
121728972063SAppaRao Puli     }
121828972063SAppaRao Puli 
121928972063SAppaRao Puli     // FIXME? c++ doesn't off an option for exclusive file creation
122028972063SAppaRao Puli     FILE* fp = fopen(firmwareBufferFile, "wx");
122128972063SAppaRao Puli     if (!fp)
122228972063SAppaRao Puli     {
122328972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::INFO>(
122428972063SAppaRao Puli             "Unable to open file.");
122528972063SAppaRao Puli         return ipmi::responseUnspecifiedError();
122628972063SAppaRao Puli     }
122728972063SAppaRao Puli     fclose(fp);
122828972063SAppaRao Puli 
122928972063SAppaRao Puli     try
123028972063SAppaRao Puli     {
123128972063SAppaRao Puli         setFirmwareUpdateMode(true);
123228972063SAppaRao Puli     }
123328972063SAppaRao Puli     catch (const std::exception& e)
123428972063SAppaRao Puli     {
123528972063SAppaRao Puli         unlink(firmwareBufferFile);
123628972063SAppaRao Puli         return ipmi::responseUnspecifiedError();
123728972063SAppaRao Puli     }
123828972063SAppaRao Puli 
123928972063SAppaRao Puli     return ipmi::responseSuccess();
124028972063SAppaRao Puli }
124128972063SAppaRao Puli 
124228972063SAppaRao Puli /** @brief implements exit firmware update mode command
124328972063SAppaRao Puli  *  @param None
124428972063SAppaRao Puli  *
124528972063SAppaRao Puli  *  @returns IPMI completion code
124628972063SAppaRao Puli  */
ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr & ctx)12475b1988b1SRajashekar Gade Reddy ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr& ctx)
124828972063SAppaRao Puli {
124928972063SAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
125028972063SAppaRao Puli         "Exit FW update mode");
12515b1988b1SRajashekar Gade Reddy     bool isIPMBChannel = false;
12525b1988b1SRajashekar Gade Reddy 
12535b1988b1SRajashekar Gade Reddy     if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
12545b1988b1SRajashekar Gade Reddy     {
12555b1988b1SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
12565b1988b1SRajashekar Gade Reddy     }
12575b1988b1SRajashekar Gade Reddy     if (isIPMBChannel)
12585b1988b1SRajashekar Gade Reddy     {
12595b1988b1SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::INFO>(
12605b1988b1SRajashekar Gade Reddy             "Command not supported. Failed to exit firmware update mode");
12615b1988b1SRajashekar Gade Reddy         return ipmi::responseCommandNotAvailable();
12625b1988b1SRajashekar Gade Reddy     }
12635b1988b1SRajashekar Gade Reddy 
126428972063SAppaRao Puli     switch (fwUpdateStatus.getState())
126528972063SAppaRao Puli     {
126628972063SAppaRao Puli         case FwUpdateStatusCache::fwStateInit:
126728972063SAppaRao Puli         case FwUpdateStatusCache::fwStateIdle:
126828972063SAppaRao Puli             return ipmi::responseInvalidFieldRequest();
126928972063SAppaRao Puli             break;
127028972063SAppaRao Puli         case FwUpdateStatusCache::fwStateDownload:
127128972063SAppaRao Puli         case FwUpdateStatusCache::fwStateVerify:
127228972063SAppaRao Puli             break;
127328972063SAppaRao Puli         case FwUpdateStatusCache::fwStateProgram:
127428972063SAppaRao Puli             break;
127528972063SAppaRao Puli         case FwUpdateStatusCache::fwStateUpdateSuccess:
127628972063SAppaRao Puli         case FwUpdateStatusCache::fwStateError:
127728972063SAppaRao Puli             break;
127828972063SAppaRao Puli         case FwUpdateStatusCache::fwStateAcCycleRequired:
127928972063SAppaRao Puli             return ipmi::responseInvalidFieldRequest();
128028972063SAppaRao Puli             break;
128128972063SAppaRao Puli     }
128228972063SAppaRao Puli     fwUpdateStatus.firmwareUpdateAbortState();
128328972063SAppaRao Puli 
128428972063SAppaRao Puli     try
128528972063SAppaRao Puli     {
128628972063SAppaRao Puli         setFirmwareUpdateMode(false);
128728972063SAppaRao Puli     }
128828972063SAppaRao Puli     catch (const std::exception& e)
128928972063SAppaRao Puli     {
129028972063SAppaRao Puli         return ipmi::responseUnspecifiedError();
129128972063SAppaRao Puli     }
129228972063SAppaRao Puli 
129328972063SAppaRao Puli     return ipmi::responseSuccess();
129428972063SAppaRao Puli }
129528972063SAppaRao Puli 
129628972063SAppaRao Puli /** @brief implements Get/Set Firmware Update Control
12975b1988b1SRajashekar Gade Reddy  *  @param[in] ctx - context of current session
129828972063SAppaRao Puli  *  @parameter
129928972063SAppaRao Puli  *   - Byte 1: Control Byte
130028972063SAppaRao Puli  *   - Byte 2: Firmware filename length (Optional)
130128972063SAppaRao Puli  *   - Byte 3:N: Firmware filename data (Optional)
130228972063SAppaRao Puli  *  @returns IPMI completion code plus response data
130328972063SAppaRao Puli  *   - Byte 2: Current control status
130428972063SAppaRao Puli  **/
ipmiGetSetFirmwareUpdateControl(const ipmi::Context::ptr & ctx,const uint8_t controlReq,const std::optional<std::string> & fileName)13051bcced08SPatrick Williams ipmi::RspType<bool, bool, bool, bool, uint4_t> ipmiGetSetFirmwareUpdateControl(
13061bcced08SPatrick Williams     const ipmi::Context::ptr& ctx, const uint8_t controlReq,
130728972063SAppaRao Puli     const std::optional<std::string>& fileName)
130828972063SAppaRao Puli {
13095b1988b1SRajashekar Gade Reddy     bool isIPMBChannel = false;
13105b1988b1SRajashekar Gade Reddy 
13115b1988b1SRajashekar Gade Reddy     if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
13125b1988b1SRajashekar Gade Reddy     {
13135b1988b1SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
13145b1988b1SRajashekar Gade Reddy     }
13155b1988b1SRajashekar Gade Reddy     if (isIPMBChannel)
13165b1988b1SRajashekar Gade Reddy     {
13175b1988b1SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::INFO>(
13185b1988b1SRajashekar Gade Reddy             "Channel not supported. Failed to get or set FW update control");
13195b1988b1SRajashekar Gade Reddy         return ipmi::responseCommandNotAvailable();
13205b1988b1SRajashekar Gade Reddy     }
13215b1988b1SRajashekar Gade Reddy 
132228972063SAppaRao Puli     static std::string fwXferUriPath;
132328972063SAppaRao Puli     static bool imageTransferStarted = false;
132428972063SAppaRao Puli     static bool imageTransferCompleted = false;
132528972063SAppaRao Puli     static bool imageTransferAborted = false;
132628972063SAppaRao Puli 
132728972063SAppaRao Puli     if ((controlReq !=
132828972063SAppaRao Puli          static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
132928972063SAppaRao Puli         (fileName))
133028972063SAppaRao Puli     {
133128972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
133228972063SAppaRao Puli             "Invalid request field (Filename).");
133328972063SAppaRao Puli         return ipmi::responseInvalidFieldRequest();
133428972063SAppaRao Puli     }
133528972063SAppaRao Puli 
133628972063SAppaRao Puli     static bool usbAttached = getUsbStatus();
133728972063SAppaRao Puli 
133828972063SAppaRao Puli     switch (static_cast<FwUpdateCtrlReq>(controlReq))
133928972063SAppaRao Puli     {
134028972063SAppaRao Puli         case FwUpdateCtrlReq::getCurrentControlStatus:
134128972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
134228972063SAppaRao Puli                 "ipmiGetSetFirmwareUpdateControl: Get status");
134328972063SAppaRao Puli             break;
134428972063SAppaRao Puli         case FwUpdateCtrlReq::imageTransferStart:
134528972063SAppaRao Puli         {
134628972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
134728972063SAppaRao Puli                 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
134828972063SAppaRao Puli             imageTransferStarted = true;
134928972063SAppaRao Puli             // reset buffer to empty (truncate file)
135028972063SAppaRao Puli             std::ofstream out(firmwareBufferFile,
135128972063SAppaRao Puli                               std::ofstream::binary | std::ofstream::trunc);
135228972063SAppaRao Puli             fwXferUriPath = std::string("file://") + firmwareBufferFile;
135328972063SAppaRao Puli             if (xferHashCheck)
135428972063SAppaRao Puli             {
1355153d4c14SArun Lal K M                 if (!xferHashCheck->clear())
1356153d4c14SArun Lal K M                 {
1357153d4c14SArun Lal K M                     phosphor::logging::log<phosphor::logging::level::ERR>(
1358153d4c14SArun Lal K M                         "clear() for xferHashCheck failed");
1359153d4c14SArun Lal K M                     return ipmi::responseUnspecifiedError();
1360153d4c14SArun Lal K M                 }
136128972063SAppaRao Puli             }
136228972063SAppaRao Puli             // Setting state to download
136328972063SAppaRao Puli             fwUpdateStatus.setState(
136428972063SAppaRao Puli                 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
136528972063SAppaRao Puli #ifdef INTEL_PFR_ENABLED
136628972063SAppaRao Puli             imgLength = 0;
136728972063SAppaRao Puli             imgType = 0;
136828972063SAppaRao Puli             block0Mapped = false;
1369c8864062SRajashekar Gade Reddy #endif
137028972063SAppaRao Puli         }
137128972063SAppaRao Puli         break;
137228972063SAppaRao Puli         case FwUpdateCtrlReq::imageTransferComplete:
137328972063SAppaRao Puli         {
13747599bcf9SMike Jones             if (!imageTransferStarted)
13757599bcf9SMike Jones             {
13767599bcf9SMike Jones                 phosphor::logging::log<phosphor::logging::level::ERR>(
13777599bcf9SMike Jones                     "transferFirmwareUpdate not started.");
13787599bcf9SMike Jones                 return ipmi::responseNotSupportedInPresentState();
13797599bcf9SMike Jones             }
138028972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
138128972063SAppaRao Puli                 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
138228972063SAppaRao Puli             if (usbAttached)
138328972063SAppaRao Puli             {
138428972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
138528972063SAppaRao Puli                     "USB should be detached to perform this operation.");
138628972063SAppaRao Puli                 return ipmi::responseNotSupportedInPresentState();
138728972063SAppaRao Puli             }
138828972063SAppaRao Puli             // finish transfer based on URI
138928972063SAppaRao Puli             if (!transferFirmwareFromUri(fwXferUriPath))
139028972063SAppaRao Puli             {
139128972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
139228972063SAppaRao Puli                     "transferFirmwareFromUri failed.");
139328972063SAppaRao Puli                 return ipmi::responseUnspecifiedError();
139428972063SAppaRao Puli             }
139528972063SAppaRao Puli             // transfer complete
139628972063SAppaRao Puli             if (xferHashCheck)
139728972063SAppaRao Puli             {
139828972063SAppaRao Puli                 if (TransferHashCheck::HashCheck::sha2Success !=
139928972063SAppaRao Puli                     xferHashCheck->verify())
140028972063SAppaRao Puli                 {
140128972063SAppaRao Puli                     phosphor::logging::log<phosphor::logging::level::ERR>(
140228972063SAppaRao Puli                         "xferHashCheck failed.");
140328972063SAppaRao Puli                     return ipmi::responseUnspecifiedError();
140428972063SAppaRao Puli                 }
140528972063SAppaRao Puli             }
140628972063SAppaRao Puli             // Set state to verify and start the update
140728972063SAppaRao Puli             fwUpdateStatus.setState(
140828972063SAppaRao Puli                 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
140928972063SAppaRao Puli             // start the request
141028972063SAppaRao Puli             if (!startFirmwareUpdate(firmwareBufferFile))
141128972063SAppaRao Puli             {
141228972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
141328972063SAppaRao Puli                     "startFirmwareUpdate failed.");
141428972063SAppaRao Puli                 return ipmi::responseUnspecifiedError();
141528972063SAppaRao Puli             }
141628972063SAppaRao Puli             imageTransferCompleted = true;
141728972063SAppaRao Puli         }
141828972063SAppaRao Puli         break;
141928972063SAppaRao Puli         case FwUpdateCtrlReq::imageTransferAbort:
142028972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
142128972063SAppaRao Puli                 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
142228972063SAppaRao Puli             if (usbAttached)
142328972063SAppaRao Puli             {
142428972063SAppaRao Puli                 if (detachUsbDevice())
142528972063SAppaRao Puli                 {
142628972063SAppaRao Puli                     phosphor::logging::log<phosphor::logging::level::ERR>(
142728972063SAppaRao Puli                         "Detach USB device failed.");
142828972063SAppaRao Puli                     return ipmi::responseUsbAttachOrDetachFailed();
142928972063SAppaRao Puli                 }
143028972063SAppaRao Puli                 usbAttached = false;
143128972063SAppaRao Puli             }
143228972063SAppaRao Puli             // During abort request reset the state to Init by cleaning update
143328972063SAppaRao Puli             // file.
143428972063SAppaRao Puli             fwUpdateStatus.firmwareUpdateAbortState();
143528972063SAppaRao Puli             imageTransferAborted = true;
143628972063SAppaRao Puli             break;
143728972063SAppaRao Puli         case FwUpdateCtrlReq::setFirmwareFilename:
143828972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
143928972063SAppaRao Puli                 "ipmiGetSetFirmwareUpdateControl: Set filename.");
144028972063SAppaRao Puli             if (!fileName || ((*fileName).length() == 0))
144128972063SAppaRao Puli             {
144228972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
144328972063SAppaRao Puli                     "Invalid Filename specified.");
144428972063SAppaRao Puli                 return ipmi::responseInvalidFieldRequest();
144528972063SAppaRao Puli             }
144628972063SAppaRao Puli 
144728972063SAppaRao Puli             fwXferUriPath = *fileName;
144828972063SAppaRao Puli             break;
144928972063SAppaRao Puli         case FwUpdateCtrlReq::attachUsbDevice:
145028972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
145128972063SAppaRao Puli                 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
145228972063SAppaRao Puli             if (usbAttached)
145328972063SAppaRao Puli             {
145428972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
145528972063SAppaRao Puli                     "USB device is already attached.");
145628972063SAppaRao Puli                 return ipmi::responseInvalidFieldRequest();
145728972063SAppaRao Puli             }
145828972063SAppaRao Puli             if (attachUsbDevice())
145928972063SAppaRao Puli             {
146028972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
146128972063SAppaRao Puli                     "Attach USB device failed.");
146228972063SAppaRao Puli                 return ipmi::responseUsbAttachOrDetachFailed();
146328972063SAppaRao Puli             }
146428972063SAppaRao Puli             usbAttached = true;
146528972063SAppaRao Puli             break;
146628972063SAppaRao Puli         case FwUpdateCtrlReq::detachUsbDevice:
146728972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::INFO>(
146828972063SAppaRao Puli                 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
146928972063SAppaRao Puli             if (!usbAttached)
147028972063SAppaRao Puli             {
147128972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
147228972063SAppaRao Puli                     "USB device is not attached.");
147328972063SAppaRao Puli                 return ipmi::responseInvalidFieldRequest();
147428972063SAppaRao Puli             }
147528972063SAppaRao Puli             if (detachUsbDevice())
147628972063SAppaRao Puli             {
147728972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
147828972063SAppaRao Puli                     "Detach USB device failed.");
147928972063SAppaRao Puli                 return ipmi::responseUsbAttachOrDetachFailed();
148028972063SAppaRao Puli             }
148128972063SAppaRao Puli             usbAttached = false;
148228972063SAppaRao Puli             break;
148328972063SAppaRao Puli         default:
148428972063SAppaRao Puli             phosphor::logging::log<phosphor::logging::level::ERR>(
148528972063SAppaRao Puli                 "Invalid control option specified.");
148628972063SAppaRao Puli             return ipmi::responseInvalidFieldRequest();
148728972063SAppaRao Puli     }
148828972063SAppaRao Puli 
148928972063SAppaRao Puli     return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
149028972063SAppaRao Puli                                  imageTransferAborted, usbAttached, uint4_t(0));
149128972063SAppaRao Puli }
149228972063SAppaRao Puli 
149328972063SAppaRao Puli /** @brief implements firmware get status command
149428972063SAppaRao Puli  *  @parameter
149528972063SAppaRao Puli  *   -  none
149628972063SAppaRao Puli  *  @returns IPMI completion code plus response data
149728972063SAppaRao Puli  *   - status     -  processing status
149828972063SAppaRao Puli  *   - percentage -  percentage completion
149928972063SAppaRao Puli  *   - check      -  channel integrity check status
150028972063SAppaRao Puli  **/
150128972063SAppaRao Puli ipmi::RspType<uint8_t, // status
150228972063SAppaRao Puli               uint8_t, // percentage
150328972063SAppaRao Puli               uint8_t  // check
150428972063SAppaRao Puli               >
ipmiGetFirmwareUpdateStatus()150528972063SAppaRao Puli     ipmiGetFirmwareUpdateStatus()
150628972063SAppaRao Puli 
150728972063SAppaRao Puli {
150828972063SAppaRao Puli     // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
150928972063SAppaRao Puli     //                  5=ready, f=error, 83=ac cycle required)
151028972063SAppaRao Puli     // Byte 2 - percent
151128972063SAppaRao Puli     // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
151228972063SAppaRao Puli     uint8_t status = fwUpdateStatus.getState();
151328972063SAppaRao Puli     uint8_t percent = fwUpdateStatus.percent();
151428972063SAppaRao Puli     uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
151528972063SAppaRao Puli 
151628972063SAppaRao Puli     // Status code.
151728972063SAppaRao Puli     return ipmi::responseSuccess(status, percent, check);
151828972063SAppaRao Puli }
151928972063SAppaRao Puli 
ipmiSetFirmwareUpdateOptions(const ipmi::Context::ptr & ctx,bool noDowngradeMask,bool deferRestartMask,bool sha2CheckMask,uint5_t reserved1,bool noDowngrade,bool deferRestart,bool sha2Check,uint5_t reserved2,std::optional<std::vector<uint8_t>> integrityCheckVal)152028972063SAppaRao Puli ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
15215b1988b1SRajashekar Gade Reddy     const ipmi::Context::ptr& ctx, bool noDowngradeMask, bool deferRestartMask,
15225b1988b1SRajashekar Gade Reddy     bool sha2CheckMask, uint5_t reserved1, bool noDowngrade, bool deferRestart,
15235b1988b1SRajashekar Gade Reddy     bool sha2Check, uint5_t reserved2,
15245b1988b1SRajashekar Gade Reddy     std::optional<std::vector<uint8_t>> integrityCheckVal)
152528972063SAppaRao Puli {
152628972063SAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
152728972063SAppaRao Puli         "Set firmware update options.");
15285b1988b1SRajashekar Gade Reddy     bool isIPMBChannel = false;
15295b1988b1SRajashekar Gade Reddy 
1530dcff1506SVernon Mauery     if (reserved1 || reserved2)
1531dcff1506SVernon Mauery     {
1532dcff1506SVernon Mauery         return ipmi::responseInvalidFieldRequest();
1533dcff1506SVernon Mauery     }
15345b1988b1SRajashekar Gade Reddy     if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
15355b1988b1SRajashekar Gade Reddy     {
15365b1988b1SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
15375b1988b1SRajashekar Gade Reddy     }
15385b1988b1SRajashekar Gade Reddy     if (isIPMBChannel)
15395b1988b1SRajashekar Gade Reddy     {
15405b1988b1SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::INFO>(
15415b1988b1SRajashekar Gade Reddy             "Channel not supported. Failed to set firmware update options");
15425b1988b1SRajashekar Gade Reddy         return ipmi::responseCommandNotAvailable();
15435b1988b1SRajashekar Gade Reddy     }
154428972063SAppaRao Puli     bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
154528972063SAppaRao Puli     bool deferRestartState = fwUpdateStatus.getDeferRestart();
154628972063SAppaRao Puli     bool sha2CheckState = xferHashCheck ? true : false;
154728972063SAppaRao Puli 
154828972063SAppaRao Puli     if (noDowngradeMask && (noDowngradeState != noDowngrade))
154928972063SAppaRao Puli     {
155028972063SAppaRao Puli         fwUpdateStatus.setInhibitDowngrade(noDowngrade);
155128972063SAppaRao Puli         noDowngradeState = noDowngrade;
155228972063SAppaRao Puli     }
155328972063SAppaRao Puli     if (deferRestartMask && (deferRestartState != deferRestart))
155428972063SAppaRao Puli     {
155528972063SAppaRao Puli         fwUpdateStatus.setDeferRestart(deferRestart);
155628972063SAppaRao Puli         deferRestartState = deferRestart;
155728972063SAppaRao Puli     }
155828972063SAppaRao Puli     if (sha2CheckMask)
155928972063SAppaRao Puli     {
156028972063SAppaRao Puli         if (sha2Check)
156128972063SAppaRao Puli         {
1562dcff1506SVernon Mauery             size_t hashSize = EVP_MD_size(EVP_sha256());
156328972063SAppaRao Puli             if ((*integrityCheckVal).size() != hashSize)
156428972063SAppaRao Puli             {
156528972063SAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::DEBUG>(
156628972063SAppaRao Puli                     "Invalid size of Hash specified.");
156728972063SAppaRao Puli                 return ipmi::responseInvalidFieldRequest();
156828972063SAppaRao Puli             }
1569153d4c14SArun Lal K M 
1570153d4c14SArun Lal K M             try
1571153d4c14SArun Lal K M             {
1572153d4c14SArun Lal K M                 xferHashCheck =
1573153d4c14SArun Lal K M                     std::make_unique<TransferHashCheck>(*integrityCheckVal);
1574153d4c14SArun Lal K M             }
1575bd51e6a9SPatrick Williams             catch (const std::exception& ex)
1576153d4c14SArun Lal K M             {
1577153d4c14SArun Lal K M                 phosphor::logging::log<phosphor::logging::level::ERR>(
1578153d4c14SArun Lal K M                     ex.what());
1579153d4c14SArun Lal K M                 return ipmi::responseUnspecifiedError();
1580153d4c14SArun Lal K M             }
158128972063SAppaRao Puli         }
158228972063SAppaRao Puli         else
158328972063SAppaRao Puli         {
158428972063SAppaRao Puli             // delete the xferHashCheck object
158528972063SAppaRao Puli             xferHashCheck.reset();
158628972063SAppaRao Puli         }
158728972063SAppaRao Puli         sha2CheckState = sha2CheckMask;
158828972063SAppaRao Puli     }
158928972063SAppaRao Puli     return ipmi::responseSuccess(noDowngradeState, deferRestartState,
1590dcff1506SVernon Mauery                                  sha2CheckState, uint5_t{});
159128972063SAppaRao Puli }
159252ce662cSVernon Mauery 
15933ec26204SRajashekar Gade Reddy ipmi::RspType<uint32_t>
ipmiFwImageWriteData(const std::vector<uint8_t> & writeData)15943ec26204SRajashekar Gade Reddy     ipmiFwImageWriteData(const std::vector<uint8_t>& writeData)
159552ce662cSVernon Mauery {
15963ec26204SRajashekar Gade Reddy     const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
15973ec26204SRajashekar Gade Reddy     size_t writeDataLen = writeData.size();
159852ce662cSVernon Mauery 
15993ec26204SRajashekar Gade Reddy     if (!writeDataLen)
16003ec26204SRajashekar Gade Reddy     {
16013ec26204SRajashekar Gade Reddy         return ipmi::responseReqDataLenInvalid();
16023ec26204SRajashekar Gade Reddy     }
16033ec26204SRajashekar Gade Reddy 
160428972063SAppaRao Puli     if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
16053ec26204SRajashekar Gade Reddy     {
160628972063SAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
16073ec26204SRajashekar Gade Reddy             "Invalid firmware update state.");
16083ec26204SRajashekar Gade Reddy         return ipmi::response(ccCmdNotSupportedInPresentState);
16093ec26204SRajashekar Gade Reddy     }
161052ce662cSVernon Mauery 
161128972063SAppaRao Puli     std::ofstream out(firmwareBufferFile,
161252ce662cSVernon Mauery                       std::ofstream::binary | std::ofstream::app);
161352ce662cSVernon Mauery     if (!out)
161452ce662cSVernon Mauery     {
16153ec26204SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::DEBUG>(
16163ec26204SRajashekar Gade Reddy             "Error while opening file.");
16173ec26204SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
161852ce662cSVernon Mauery     }
1619df5e3271SRajashekar Gade Reddy 
1620df5e3271SRajashekar Gade Reddy     uint64_t fileDataLen = out.tellp();
16213ec26204SRajashekar Gade Reddy 
162228972063SAppaRao Puli     if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
162352ce662cSVernon Mauery     {
16243ec26204SRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::DEBUG>(
16253ec26204SRajashekar Gade Reddy             "Firmware image size exceeds the limit");
16263ec26204SRajashekar Gade Reddy         return ipmi::responseInvalidFieldRequest();
162752ce662cSVernon Mauery     }
16283ec26204SRajashekar Gade Reddy 
16293ec26204SRajashekar Gade Reddy     const char* data = reinterpret_cast<const char*>(writeData.data());
16303ec26204SRajashekar Gade Reddy     out.write(data, writeDataLen);
163152ce662cSVernon Mauery     out.close();
16323ec26204SRajashekar Gade Reddy 
163328972063SAppaRao Puli     if (xferHashCheck)
163452ce662cSVernon Mauery     {
1635153d4c14SArun Lal K M         if (!xferHashCheck->hash(writeData))
1636153d4c14SArun Lal K M         {
1637153d4c14SArun Lal K M             phosphor::logging::log<phosphor::logging::level::ERR>(
1638153d4c14SArun Lal K M                 "ipmiFwImageWriteData: xferHashCheck->hash failed.");
1639153d4c14SArun Lal K M             return ipmi::responseUnspecifiedError();
1640153d4c14SArun Lal K M         }
164152ce662cSVernon Mauery     }
164252ce662cSVernon Mauery 
1643df5e3271SRajashekar Gade Reddy #ifdef INTEL_PFR_ENABLED
1644df5e3271SRajashekar Gade Reddy     /* PFR image block 0 - As defined in HAS */
1645df5e3271SRajashekar Gade Reddy     struct PFRImageBlock0
1646df5e3271SRajashekar Gade Reddy     {
1647df5e3271SRajashekar Gade Reddy         uint32_t tag;
1648df5e3271SRajashekar Gade Reddy         uint32_t pcLength;
1649df5e3271SRajashekar Gade Reddy         uint32_t pcType;
1650df5e3271SRajashekar Gade Reddy         uint32_t reserved1;
1651df5e3271SRajashekar Gade Reddy         uint8_t hash256[32];
1652df5e3271SRajashekar Gade Reddy         uint8_t hash384[48];
1653df5e3271SRajashekar Gade Reddy         uint8_t reserved2[32];
1654df5e3271SRajashekar Gade Reddy     } __attribute__((packed));
1655df5e3271SRajashekar Gade Reddy 
1656df5e3271SRajashekar Gade Reddy     /* Get the PFR block 0 data and read the uploaded image
1657df5e3271SRajashekar Gade Reddy      * information( Image type, length etc) */
16583ec26204SRajashekar Gade Reddy     if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
16593ec26204SRajashekar Gade Reddy         (!block0Mapped))
1660df5e3271SRajashekar Gade Reddy     {
1661dcff1506SVernon Mauery         PFRImageBlock0 block0Data{};
1662df5e3271SRajashekar Gade Reddy 
166328972063SAppaRao Puli         std::ifstream inFile(firmwareBufferFile,
1664df5e3271SRajashekar Gade Reddy                              std::ios::binary | std::ios::in);
1665df5e3271SRajashekar Gade Reddy         inFile.read(reinterpret_cast<char*>(&block0Data), sizeof(block0Data));
1666df5e3271SRajashekar Gade Reddy         inFile.close();
1667df5e3271SRajashekar Gade Reddy 
1668df5e3271SRajashekar Gade Reddy         uint32_t magicNum = block0Data.tag;
1669df5e3271SRajashekar Gade Reddy 
1670df5e3271SRajashekar Gade Reddy         /* Validate the magic number */
1671df5e3271SRajashekar Gade Reddy         if (magicNum != perBlock0MagicNum)
1672df5e3271SRajashekar Gade Reddy         {
16733ec26204SRajashekar Gade Reddy             phosphor::logging::log<phosphor::logging::level::DEBUG>(
16743ec26204SRajashekar Gade Reddy                 "PFR image magic number not matched");
16753ec26204SRajashekar Gade Reddy             return ipmi::responseInvalidFieldRequest();
1676df5e3271SRajashekar Gade Reddy         }
1677df5e3271SRajashekar Gade Reddy         // Note:imgLength, imgType and block0Mapped are in global scope, as
1678df5e3271SRajashekar Gade Reddy         // these are used in cascaded updates.
1679df5e3271SRajashekar Gade Reddy         imgLength = block0Data.pcLength;
1680df5e3271SRajashekar Gade Reddy         imgType = block0Data.pcType;
1681df5e3271SRajashekar Gade Reddy         block0Mapped = true;
1682df5e3271SRajashekar Gade Reddy     }
1683df5e3271SRajashekar Gade Reddy #endif // end of INTEL_PFR_ENABLED
16843ec26204SRajashekar Gade Reddy     return ipmi::responseSuccess(writeDataLen);
168552ce662cSVernon Mauery }
168652ce662cSVernon Mauery 
registerFirmwareFunctions()168728972063SAppaRao Puli static void registerFirmwareFunctions()
168852ce662cSVernon Mauery {
168952ce662cSVernon Mauery     // guarantee that we start with an already timed out timestamp
16901bcced08SPatrick Williams     fwRandomNumGenTs =
16911bcced08SPatrick Williams         std::chrono::steady_clock::now() - fwRandomNumExpirySeconds;
169228972063SAppaRao Puli     fwUpdateStatus.setState(
169328972063SAppaRao Puli         static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
169452ce662cSVernon Mauery 
169528972063SAppaRao Puli     unlink(firmwareBufferFile);
169652ce662cSVernon Mauery 
169737fde6b6SAppaRao Puli #ifdef INTEL_PFR_ENABLED
169837fde6b6SAppaRao Puli     // Following commands are supported only for PFR enabled platforms
169937fde6b6SAppaRao Puli     // CMD:0x20 - Get Firmware Version Information
170028972063SAppaRao Puli     // CMD:0x21 - Get Firmware Security Version Information
170128972063SAppaRao Puli     // CMD:0x25 - Get Root Certificate Data
170252ce662cSVernon Mauery 
170337fde6b6SAppaRao Puli     // get firmware version information
170437fde6b6SAppaRao Puli     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
170537fde6b6SAppaRao Puli                           ipmi::firmware::cmdGetFwVersionInfo,
170637fde6b6SAppaRao Puli                           ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
170728972063SAppaRao Puli 
170852ce662cSVernon Mauery     // get firmware security version information
170928972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
171028972063SAppaRao Puli                           ipmi::firmware::cmdGetFwSecurityVersionInfo,
171128972063SAppaRao Puli                           ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
171252ce662cSVernon Mauery 
171352ce662cSVernon Mauery     // get root certificate data
1714c8864062SRajashekar Gade Reddy     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1715c8864062SRajashekar Gade Reddy                           ipmi::firmware::cmdFwGetRootCertData,
1716c8864062SRajashekar Gade Reddy                           ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1717c8864062SRajashekar Gade Reddy #endif
171852ce662cSVernon Mauery 
171928972063SAppaRao Puli     // get firmware update channel information (max transfer sizes)
172028972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
172128972063SAppaRao Puli                           ipmi::firmware::cmdGetFwUpdateChannelInfo,
172228972063SAppaRao Puli                           ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
172352ce662cSVernon Mauery 
172428972063SAppaRao Puli     // get bmc execution context
172528972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
172628972063SAppaRao Puli                           ipmi::firmware::cmdGetBmcExecutionContext,
172728972063SAppaRao Puli                           ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
172828972063SAppaRao Puli 
172928972063SAppaRao Puli     // Get Firmware Update Random number
173028972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
173128972063SAppaRao Puli                           ipmi::firmware::cmdGetFwUpdateRandomNumber,
173228972063SAppaRao Puli                           ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
173328972063SAppaRao Puli 
173428972063SAppaRao Puli     // Set Firmware Update Mode
173528972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
173628972063SAppaRao Puli                           ipmi::firmware::cmdSetFirmwareUpdateMode,
17374b3e1c70SAppaRao Puli                           ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
173852ce662cSVernon Mauery 
173928972063SAppaRao Puli     // Exit Firmware Update Mode
1740b57098a6Sanil kumar appana     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
174128972063SAppaRao Puli                           ipmi::firmware::cmdExitFirmwareUpdateMode,
174228972063SAppaRao Puli                           ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
174352ce662cSVernon Mauery 
174428972063SAppaRao Puli     // Get/Set Firmware Update Control
174528972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
174628972063SAppaRao Puli                           ipmi::firmware::cmdGetSetFwUpdateControl,
174728972063SAppaRao Puli                           ipmi::Privilege::Admin,
174828972063SAppaRao Puli                           ipmiGetSetFirmwareUpdateControl);
174952ce662cSVernon Mauery 
175028972063SAppaRao Puli     // Get Firmware Update Status
175128972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
175228972063SAppaRao Puli                           ipmi::firmware::cmdGetFirmwareUpdateStatus,
175328972063SAppaRao Puli                           ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
175452ce662cSVernon Mauery 
175528972063SAppaRao Puli     // Set Firmware Update Options
175628972063SAppaRao Puli     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
175728972063SAppaRao Puli                           ipmi::firmware::cmdSetFirmwareUpdateOptions,
175828972063SAppaRao Puli                           ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
175952ce662cSVernon Mauery     // write image data
17603ec26204SRajashekar Gade Reddy     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
17613ec26204SRajashekar Gade Reddy                           ipmi::firmware::cmdFwImageWriteData,
17623ec26204SRajashekar Gade Reddy                           ipmi::Privilege::Admin, ipmiFwImageWriteData);
176352ce662cSVernon Mauery     return;
176452ce662cSVernon Mauery }
1765