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