blob: 59554d03a9525dd94086255333e2c3c048c7571b [file] [log] [blame]
srikanta mondal52a292b2020-07-27 23:49:14 +00001#include <byteswap.h>
Vernon Mauery52ce6622019-05-22 09:19:46 -07002#include <ipmid/api.h>
3#include <openssl/evp.h>
4#include <openssl/sha.h>
5#include <sys/mman.h>
6#include <sys/stat.h>
7#include <sys/types.h>
8#include <unistd.h>
9
srikanta mondal52a292b2020-07-27 23:49:14 +000010#include <appcommands.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070011#include <boost/algorithm/string.hpp>
AppaRao Puli28972062019-11-11 02:04:45 +053012#include <boost/container/flat_map.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070013#include <boost/process/child.hpp>
14#include <boost/uuid/random_generator.hpp>
15#include <boost/uuid/uuid_io.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070016#include <commandutils.hpp>
anil kumar appana6c7d9382019-05-31 14:33:13 +000017#include <ipmid/api.hpp>
AppaRao Puli37fde6b2019-10-25 16:37:50 +053018#include <ipmid/utils.hpp>
AppaRao Puli28972062019-11-11 02:04:45 +053019#include <phosphor-logging/log.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070020#include <sdbusplus/bus.hpp>
21#include <sdbusplus/bus/match.hpp>
22#include <sdbusplus/server/object.hpp>
23#include <sdbusplus/timer.hpp>
Patrick Venturec2a07d42020-05-30 16:35:03 -070024#include <types.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070025
26#include <chrono>
27#include <cstdint>
28#include <filesystem>
29#include <fstream>
30#include <iostream>
31#include <map>
32#include <random>
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +053033#ifdef INTEL_PFR_ENABLED
34#include <spiDev.hpp>
35#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -070036
Arun Lal K M153d4c12021-08-25 22:00:37 +000037static constexpr int openSslSuccess = 1;
AppaRao Puli28972062019-11-11 02:04:45 +053038static constexpr bool DEBUG = true;
39static void registerFirmwareFunctions() __attribute__((constructor));
40
AppaRao Puli37fde6b2019-10-25 16:37:50 +053041namespace ipmi
42{
43namespace firmware
44{
45constexpr Cmd cmdGetFwVersionInfo = 0x20;
AppaRao Puli28972062019-11-11 02:04:45 +053046constexpr Cmd cmdGetFwSecurityVersionInfo = 0x21;
47constexpr Cmd cmdGetFwUpdateChannelInfo = 0x22;
48constexpr Cmd cmdGetBmcExecutionContext = 0x23;
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +053049constexpr Cmd cmdFwGetRootCertData = 0x25;
AppaRao Puli28972062019-11-11 02:04:45 +053050constexpr Cmd cmdGetFwUpdateRandomNumber = 0x26;
51constexpr Cmd cmdSetFirmwareUpdateMode = 0x27;
52constexpr Cmd cmdExitFirmwareUpdateMode = 0x28;
53constexpr Cmd cmdGetSetFwUpdateControl = 0x29;
54constexpr Cmd cmdGetFirmwareUpdateStatus = 0x2A;
55constexpr Cmd cmdSetFirmwareUpdateOptions = 0x2B;
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +053056constexpr Cmd cmdFwImageWriteData = 0x2c;
AppaRao Puli37fde6b2019-10-25 16:37:50 +053057} // namespace firmware
58} // namespace ipmi
59
AppaRao Puli28972062019-11-11 02:04:45 +053060namespace ipmi
61{
62// Custom completion codes
63constexpr Cc ccUsbAttachOrDetachFailed = 0x80;
64constexpr Cc ccNotSupportedInPresentState = 0xD5;
65
66static inline auto responseUsbAttachOrDetachFailed()
67{
68 return response(ccUsbAttachOrDetachFailed);
69}
70static inline auto responseNotSupportedInPresentState()
71{
72 return response(ccNotSupportedInPresentState);
73}
74} // namespace ipmi
75
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +000076static constexpr size_t imageCount = 2;
Vernon Mauerydcff1502022-09-28 11:12:46 -070077std::array<std::array<uint8_t, imageCount>, imageCount> imgFwSecurityVersion =
78 {};
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +000079static constexpr size_t svnActiveVerOffsetInPfm = 0x404;
80static constexpr size_t bkcActiveVerOffsetInPfm = 0x405;
81static constexpr size_t svnRecoveryVerOffsetInPfm = 0x804;
82static constexpr size_t bkcRecoveryVerOffsetInPfm = 0x805;
James Feistfcd2d3a2020-05-28 10:38:15 -070083static constexpr const char* bmcStateIntf = "xyz.openbmc_project.State.BMC";
84static constexpr const char* bmcStatePath = "/xyz/openbmc_project/state/bmc0";
85static constexpr const char* bmcStateReady =
AppaRao Puli28972062019-11-11 02:04:45 +053086 "xyz.openbmc_project.State.BMC.BMCState.Ready";
James Feistfcd2d3a2020-05-28 10:38:15 -070087static constexpr const char* bmcStateUpdateInProgress =
AppaRao Puli28972062019-11-11 02:04:45 +053088 "xyz.openbmc_project.State.BMC.BMCState.UpdateInProgress";
89
90static constexpr char firmwareBufferFile[] = "/tmp/fw-download.bin";
91static std::chrono::steady_clock::time_point fwRandomNumGenTs;
92static constexpr auto fwRandomNumExpirySeconds = std::chrono::seconds(30);
93static constexpr size_t fwRandomNumLength = 8;
94static std::array<uint8_t, fwRandomNumLength> fwRandomNum;
95constexpr char usbCtrlPath[] = "/usr/bin/usb-ctrl";
96constexpr char fwUpdateMountPoint[] = "/tmp/usb-fwupd.mnt";
97constexpr char fwUpdateUsbVolImage[] = "/tmp/usb-fwupd.img";
98constexpr char fwUpdateUSBDevName[] = "fw-usb-mass-storage-dev";
99constexpr size_t fwPathMaxLength = 255;
100
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +0530101#ifdef INTEL_PFR_ENABLED
102uint32_t imgLength = 0;
103uint32_t imgType = 0;
104bool block0Mapped = false;
105static constexpr uint32_t perBlock0MagicNum = 0xB6EAFD19;
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530106
James Feistfcd2d3a2020-05-28 10:38:15 -0700107static constexpr const char* bmcActivePfmMTDDev = "/dev/mtd/pfm";
108static constexpr const char* bmcRecoveryImgMTDDev = "/dev/mtd/rc-image";
AppaRao Puli28972062019-11-11 02:04:45 +0530109static constexpr size_t pfmBaseOffsetInImage = 0x400;
110static constexpr size_t rootkeyOffsetInPfm = 0xA0;
111static constexpr size_t cskKeyOffsetInPfm = 0x124;
112static constexpr size_t cskSignatureOffsetInPfm = 0x19c;
113static constexpr size_t certKeyLen = 96;
114static constexpr size_t cskSignatureLen = 96;
115
James Feistfcd2d3a2020-05-28 10:38:15 -0700116static constexpr const char* versionIntf =
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530117 "xyz.openbmc_project.Software.Version";
118
AppaRao Puli28972062019-11-11 02:04:45 +0530119enum class FwGetRootCertDataTag : uint8_t
120{
121 activeRootKey = 1,
122 recoveryRootKey,
123 activeCSK,
124 recoveryCSK,
125};
126
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530127enum class FWDeviceIDTag : uint8_t
128{
129 bmcActiveImage = 1,
130 bmcRecoveryImage,
131};
132
James Feistfcd2d3a2020-05-28 10:38:15 -0700133const static boost::container::flat_map<FWDeviceIDTag, const char*>
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530134 fwVersionIdMap{{FWDeviceIDTag::bmcActiveImage,
135 "/xyz/openbmc_project/software/bmc_active"},
136 {FWDeviceIDTag::bmcRecoveryImage,
137 "/xyz/openbmc_project/software/bmc_recovery"}};
AppaRao Puli28972062019-11-11 02:04:45 +0530138#endif // INTEL_PFR_ENABLED
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530139
AppaRao Puli28972062019-11-11 02:04:45 +0530140enum class ChannelIdTag : uint8_t
141{
142 reserved = 0,
143 kcs = 1,
144 ipmb = 2,
145 rmcpPlus = 3
146};
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +0530147
AppaRao Puli28972062019-11-11 02:04:45 +0530148enum class BmcExecutionContext : uint8_t
149{
150 reserved = 0,
151 linuxOs = 0x10,
152 bootLoader = 0x11,
153};
AppaRao Puli09a83142019-11-23 02:46:06 +0530154
AppaRao Puli28972062019-11-11 02:04:45 +0530155enum class FwUpdateCtrlReq : uint8_t
156{
157 getCurrentControlStatus = 0x00,
158 imageTransferStart = 0x01,
159 imageTransferComplete = 0x02,
160 imageTransferAbort = 0x03,
161 setFirmwareFilename = 0x04,
162 attachUsbDevice = 0x05,
163 detachUsbDevice = 0x06
164};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700165
166constexpr std::size_t operator""_MB(unsigned long long v)
167{
168 return 1024u * 1024u * v;
169}
Jayaprakash Mutyalaab5c0e52024-10-17 05:01:17 +0000170static constexpr size_t maxFirmwareImageSize = 37_MB;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700171
AppaRao Puli28972062019-11-11 02:04:45 +0530172static bool localDownloadInProgress(void)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700173{
174 struct stat sb;
AppaRao Puli28972062019-11-11 02:04:45 +0530175 if (stat(firmwareBufferFile, &sb) < 0)
176 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700177 return false;
AppaRao Puli28972062019-11-11 02:04:45 +0530178 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700179 return true;
180}
181
AppaRao Puli28972062019-11-11 02:04:45 +0530182class TransferHashCheck
183{
184 public:
185 enum class HashCheck : uint8_t
186 {
187 notRequested = 0,
188 requested,
189 sha2Success,
190 sha2Failed = 0xe2,
191 };
192
193 protected:
Arun Lal K M153d4c12021-08-25 22:00:37 +0000194 std::unique_ptr<EVP_MD_CTX, std::function<void(EVP_MD_CTX*)>> ctx;
AppaRao Puli28972062019-11-11 02:04:45 +0530195 std::vector<uint8_t> expectedHash;
Arun Lal K M153d4c12021-08-25 22:00:37 +0000196 HashCheck check;
AppaRao Puli28972062019-11-11 02:04:45 +0530197
198 public:
Arun Lal K M153d4c12021-08-25 22:00:37 +0000199 TransferHashCheck(const std::vector<uint8_t>& expected) :
200 ctx(EVP_MD_CTX_new(), &EVP_MD_CTX_free), expectedHash(expected)
AppaRao Puli28972062019-11-11 02:04:45 +0530201 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000202 if (!ctx)
AppaRao Puli28972062019-11-11 02:04:45 +0530203 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000204 throw std::runtime_error("Unable to allocate for ctx.");
AppaRao Puli28972062019-11-11 02:04:45 +0530205 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000206
207 if (EVP_DigestInit(ctx.get(), EVP_sha256()) != openSslSuccess)
208 {
209 throw std::runtime_error("Unable to allocate for ctx.");
210 }
211
AppaRao Puli28972062019-11-11 02:04:45 +0530212 check = HashCheck::requested;
AppaRao Puli28972062019-11-11 02:04:45 +0530213 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000214
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500215 ~TransferHashCheck() {}
Arun Lal K M153d4c12021-08-25 22:00:37 +0000216
217 bool hash(const std::vector<uint8_t>& data)
AppaRao Puli28972062019-11-11 02:04:45 +0530218 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000219 if (EVP_DigestUpdate(ctx.get(), data.data(), data.size()) !=
220 openSslSuccess)
AppaRao Puli28972062019-11-11 02:04:45 +0530221 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000222 return false;
AppaRao Puli28972062019-11-11 02:04:45 +0530223 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000224
225 return true;
AppaRao Puli28972062019-11-11 02:04:45 +0530226 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000227
228 bool clear()
AppaRao Puli28972062019-11-11 02:04:45 +0530229 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000230 /*
231 * EVP_DigestInit() always uses the default digest implementation and
232 * calls EVP_MD_CTX_reset().
233 */
234 if (EVP_DigestInit(ctx.get(), EVP_sha256()) != openSslSuccess)
AppaRao Puli28972062019-11-11 02:04:45 +0530235 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000236 return false;
AppaRao Puli28972062019-11-11 02:04:45 +0530237 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000238
239 return true;
AppaRao Puli28972062019-11-11 02:04:45 +0530240 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000241
AppaRao Puli28972062019-11-11 02:04:45 +0530242 enum HashCheck verify()
243 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000244 unsigned int len = 0;
245 std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
246
247 check = HashCheck::sha2Failed;
248
249 if (EVP_DigestFinal(ctx.get(), digest.data(), &len) == openSslSuccess)
AppaRao Puli28972062019-11-11 02:04:45 +0530250 {
AppaRao Puli28972062019-11-11 02:04:45 +0530251 if (digest == expectedHash)
252 {
253 phosphor::logging::log<phosphor::logging::level::INFO>(
254 "Transfer sha2 verify passed.");
255 check = HashCheck::sha2Success;
256 }
257 else
258 {
259 phosphor::logging::log<phosphor::logging::level::ERR>(
260 "Transfer sha2 verify failed.");
261 check = HashCheck::sha2Failed;
262 }
263 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000264
AppaRao Puli28972062019-11-11 02:04:45 +0530265 return check;
266 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000267
AppaRao Puli28972062019-11-11 02:04:45 +0530268 uint8_t status() const
269 {
270 return static_cast<uint8_t>(check);
271 }
272};
273
274class MappedFile
275{
276 public:
James Feistfcd2d3a2020-05-28 10:38:15 -0700277 MappedFile(const std::string& fname) : addr(nullptr), fsize(0)
AppaRao Puli28972062019-11-11 02:04:45 +0530278 {
279 std::error_code ec;
280 size_t sz = std::filesystem::file_size(fname, ec);
P Dheeraj Srujan Kumarc08e9752021-07-14 19:38:32 +0530281 if (!ec)
282 {
283 return;
284 }
AppaRao Puli28972062019-11-11 02:04:45 +0530285 int fd = open(fname.c_str(), O_RDONLY);
P Dheeraj Srujan Kumarc08e9752021-07-14 19:38:32 +0530286 if (fd < 0)
AppaRao Puli28972062019-11-11 02:04:45 +0530287 {
288 return;
289 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700290 void* tmp = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
AppaRao Puli28972062019-11-11 02:04:45 +0530291 close(fd);
292 if (tmp == MAP_FAILED)
293 {
294 return;
295 }
296 addr = tmp;
297 fsize = sz;
298 }
299
300 ~MappedFile()
301 {
302 if (addr)
303 {
304 munmap(addr, fsize);
305 }
306 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700307 const uint8_t* data() const
AppaRao Puli28972062019-11-11 02:04:45 +0530308 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700309 return static_cast<const uint8_t*>(addr);
AppaRao Puli28972062019-11-11 02:04:45 +0530310 }
311 size_t size() const
312 {
313 return fsize;
314 }
315
316 private:
James Feistfcd2d3a2020-05-28 10:38:15 -0700317 void* addr;
Vernon Mauerydcff1502022-09-28 11:12:46 -0700318 size_t fsize;
AppaRao Puli28972062019-11-11 02:04:45 +0530319};
320
321class FwUpdateStatusCache
Vernon Mauery52ce6622019-05-22 09:19:46 -0700322{
323 public:
324 enum
325 {
AppaRao Puli28972062019-11-11 02:04:45 +0530326 fwStateInit = 0,
327 fwStateIdle,
328 fwStateDownload,
329 fwStateVerify,
330 fwStateProgram,
331 fwStateUpdateSuccess,
332 fwStateError = 0x0f,
333 fwStateAcCycleRequired = 0x83,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700334 };
AppaRao Puli28972062019-11-11 02:04:45 +0530335 uint8_t getState()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700336 {
AppaRao Puli28972062019-11-11 02:04:45 +0530337 if ((fwUpdateState == fwStateIdle || fwUpdateState == fwStateInit) &&
338 localDownloadInProgress())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700339 {
AppaRao Puli28972062019-11-11 02:04:45 +0530340 fwUpdateState = fwStateDownload;
341 progressPercent = 0;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700342 }
AppaRao Puli28972062019-11-11 02:04:45 +0530343 return fwUpdateState;
344 }
345 void resetStatusCache()
346 {
347 unlink(firmwareBufferFile);
348 }
349 void setState(const uint8_t state)
350 {
351 switch (state)
352 {
353 case fwStateInit:
354 case fwStateIdle:
355 case fwStateError:
356 resetStatusCache();
357 break;
358 case fwStateDownload:
359 case fwStateVerify:
360 case fwStateProgram:
361 case fwStateUpdateSuccess:
362 break;
363 default:
364 // Error
365 break;
366 }
367 fwUpdateState = state;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700368 }
369 uint8_t percent()
370 {
AppaRao Puli28972062019-11-11 02:04:45 +0530371 return progressPercent;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700372 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700373 void updateActivationPercent(const std::string& objPath)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700374 {
AppaRao Puli28972062019-11-11 02:04:45 +0530375 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
376 fwUpdateState = fwStateProgram;
377 progressPercent = 0;
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500378 match = std::make_shared<sdbusplus::bus::match_t>(
AppaRao Puli28972062019-11-11 02:04:45 +0530379 *busp,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700380 sdbusplus::bus::match::rules::propertiesChanged(
AppaRao Puli28972062019-11-11 02:04:45 +0530381 objPath, "xyz.openbmc_project.Software.ActivationProgress"),
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500382 [&](sdbusplus::message_t& msg) {
Patrick Williams1bcced02024-08-16 15:20:24 -0400383 std::map<std::string, ipmi::DbusVariant> props;
384 std::vector<std::string> inVal;
385 std::string iface;
386 try
AppaRao Puli28972062019-11-11 02:04:45 +0530387 {
Patrick Williams1bcced02024-08-16 15:20:24 -0400388 msg.read(iface, props, inVal);
AppaRao Puli28972062019-11-11 02:04:45 +0530389 }
Patrick Williams1bcced02024-08-16 15:20:24 -0400390 catch (const std::exception& e)
391 {
392 phosphor::logging::log<phosphor::logging::level::ERR>(
393 "Exception caught in get ActivationProgress");
394 return;
395 }
396
397 auto it = props.find("Progress");
398 if (it != props.end())
399 {
400 progressPercent = std::get<uint8_t>(it->second);
401 if (progressPercent == 100)
402 {
403 fwUpdateState = fwStateUpdateSuccess;
404 }
405 }
406 });
Vernon Mauery52ce6622019-05-22 09:19:46 -0700407 }
AppaRao Puli28972062019-11-11 02:04:45 +0530408 uint8_t activationTimerTimeout()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700409 {
AppaRao Puli28972062019-11-11 02:04:45 +0530410 phosphor::logging::log<phosphor::logging::level::INFO>(
411 "activationTimerTimeout: Increase percentage...",
412 phosphor::logging::entry("PERCENT:%d", progressPercent));
413 progressPercent = progressPercent + 5;
jayaprakash Mutyalab8f2bf92020-01-27 23:17:39 +0000414 if (progressPercent > 95)
anil kumar appana31f88872019-08-02 15:16:27 +0000415 {
416 /*changing the state to ready to update firmware utility */
AppaRao Puli28972062019-11-11 02:04:45 +0530417 fwUpdateState = fwStateUpdateSuccess;
anil kumar appana31f88872019-08-02 15:16:27 +0000418 }
AppaRao Puli28972062019-11-11 02:04:45 +0530419 return progressPercent;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700420 }
anil kumar appana31f88872019-08-02 15:16:27 +0000421 /* API for changing state to ERROR */
422 void firmwareUpdateAbortState()
423 {
AppaRao Puli28972062019-11-11 02:04:45 +0530424 unlink(firmwareBufferFile);
anil kumar appana31f88872019-08-02 15:16:27 +0000425 // changing the state to error
AppaRao Puli28972062019-11-11 02:04:45 +0530426 fwUpdateState = fwStateError;
anil kumar appana31f88872019-08-02 15:16:27 +0000427 }
428 void setDeferRestart(bool deferRestart)
429 {
AppaRao Puli28972062019-11-11 02:04:45 +0530430 deferRestartState = deferRestart;
anil kumar appana31f88872019-08-02 15:16:27 +0000431 }
432 void setInhibitDowngrade(bool inhibitDowngrade)
433 {
AppaRao Puli28972062019-11-11 02:04:45 +0530434 inhibitDowngradeState = inhibitDowngrade;
anil kumar appana31f88872019-08-02 15:16:27 +0000435 }
436 bool getDeferRestart()
437 {
AppaRao Puli28972062019-11-11 02:04:45 +0530438 return deferRestartState;
anil kumar appana31f88872019-08-02 15:16:27 +0000439 }
440 bool getInhibitDowngrade()
441 {
AppaRao Puli28972062019-11-11 02:04:45 +0530442 return inhibitDowngradeState;
anil kumar appana31f88872019-08-02 15:16:27 +0000443 }
444
Vernon Mauery52ce6622019-05-22 09:19:46 -0700445 protected:
AppaRao Puli28972062019-11-11 02:04:45 +0530446 std::shared_ptr<sdbusplus::asio::connection> busp;
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500447 std::shared_ptr<sdbusplus::bus::match_t> match;
AppaRao Puli28972062019-11-11 02:04:45 +0530448 uint8_t fwUpdateState = 0;
449 uint8_t progressPercent = 0;
450 bool deferRestartState = false;
451 bool inhibitDowngradeState = false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700452};
453
AppaRao Puli28972062019-11-11 02:04:45 +0530454static FwUpdateStatusCache fwUpdateStatus;
Arun Lal K M153d4c12021-08-25 22:00:37 +0000455std::unique_ptr<TransferHashCheck> xferHashCheck;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700456
James Feistfcd2d3a2020-05-28 10:38:15 -0700457static void activateImage(const std::string& objPath)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700458{
AppaRao Puli28972062019-11-11 02:04:45 +0530459 // If flag is false means to reboot
460 if (fwUpdateStatus.getDeferRestart() == false)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700461 {
AppaRao Puli28972062019-11-11 02:04:45 +0530462 phosphor::logging::log<phosphor::logging::level::INFO>(
463 "activating Image: ",
464 phosphor::logging::entry("OBJPATH =%s", objPath.c_str()));
465 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
466 bus->async_method_call(
467 [](const boost::system::error_code ec) {
Patrick Williams1bcced02024-08-16 15:20:24 -0400468 if (ec)
469 {
470 phosphor::logging::log<phosphor::logging::level::ERR>(
471 "async_method_call error: activateImage failed");
472 return;
473 }
474 },
AppaRao Puli28972062019-11-11 02:04:45 +0530475 "xyz.openbmc_project.Software.BMC.Updater", objPath,
476 "org.freedesktop.DBus.Properties", "Set",
477 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Jason M. Bills0748c692022-09-08 15:34:08 -0700478 ipmi::DbusVariant("xyz.openbmc_project.Software.Activation."
479 "RequestedActivations.Active"));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700480 }
AppaRao Puli28972062019-11-11 02:04:45 +0530481 else
482 {
483 phosphor::logging::log<phosphor::logging::level::INFO>(
484 "Firmware image activation is deferred.");
485 }
486 fwUpdateStatus.setState(
487 static_cast<uint8_t>(FwUpdateStatusCache::fwStateUpdateSuccess));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700488}
489
AppaRao Puli09a83142019-11-23 02:46:06 +0530490static bool getFirmwareUpdateMode()
491{
492 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
493 try
494 {
495 auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
496 ipmi::Value state = ipmi::getDbusProperty(
497 *busp, service, bmcStatePath, bmcStateIntf, "CurrentBMCState");
498 std::string bmcState = std::get<std::string>(state);
499 return (bmcState == bmcStateUpdateInProgress);
500 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700501 catch (const std::exception& e)
AppaRao Puli09a83142019-11-23 02:46:06 +0530502 {
503 phosphor::logging::log<phosphor::logging::level::ERR>(
504 "Exception caught while getting BMC state.",
505 phosphor::logging::entry("EXCEPTION=%s", e.what()));
506 throw;
507 }
508}
509
510static void setFirmwareUpdateMode(const bool mode)
511{
AppaRao Puli09a83142019-11-23 02:46:06 +0530512 std::string bmcState(bmcStateReady);
513 if (mode)
514 {
515 bmcState = bmcStateUpdateInProgress;
516 }
517
518 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
519 try
520 {
521 auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
522 ipmi::setDbusProperty(*busp, service, bmcStatePath, bmcStateIntf,
523 "CurrentBMCState", bmcState);
524 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700525 catch (const std::exception& e)
AppaRao Puli09a83142019-11-23 02:46:06 +0530526 {
527 phosphor::logging::log<phosphor::logging::level::ERR>(
528 "Exception caught while setting BMC state.",
529 phosphor::logging::entry("EXCEPTION=%s", e.what()));
530 throw;
531 }
532}
533
AppaRao Pulie2cddf62020-01-31 00:30:08 +0530534/** @brief check if channel IPMB
535 *
536 * This function checks if the command is from IPMB
537 *
538 * @param[in] ctx - context of current session.
539 * @returns true if the medium is IPMB else return true.
540 **/
James Feistfcd2d3a2020-05-28 10:38:15 -0700541ipmi::Cc checkIPMBChannel(const ipmi::Context::ptr& ctx, bool& isIPMBChannel)
AppaRao Pulie2cddf62020-01-31 00:30:08 +0530542{
543 ipmi::ChannelInfo chInfo;
544
545 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
546 {
547 phosphor::logging::log<phosphor::logging::level::ERR>(
548 "Failed to get Channel Info",
549 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
550 return ipmi::ccUnspecifiedError;
551 }
552
553 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
554 ipmi::EChannelMediumType::ipmb)
555 {
556 isIPMBChannel = true;
557 }
558 return ipmi::ccSuccess;
559}
560
AppaRao Puli28972062019-11-11 02:04:45 +0530561static void postTransferCompleteHandler(
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500562 std::unique_ptr<sdbusplus::bus::match_t>& fwUpdateMatchSignal)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700563{
564 // Setup timer for watching signal
Patrick Williams1bcced02024-08-16 15:20:24 -0400565 static sdbusplus::Timer timer([&fwUpdateMatchSignal]() {
566 fwUpdateMatchSignal = nullptr;
567 });
Vernon Mauery52ce6622019-05-22 09:19:46 -0700568
Patrick Williamsf0feb492023-12-05 12:45:02 -0600569 static sdbusplus::Timer activationStatusTimer([]() {
jayaprakash Mutyalab8f2bf92020-01-27 23:17:39 +0000570 if (fwUpdateStatus.activationTimerTimeout() > 95)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700571 {
AppaRao Puli28972062019-11-11 02:04:45 +0530572 activationStatusTimer.stop();
573 fwUpdateStatus.setState(
574 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700575 }
576 });
577
578 timer.start(std::chrono::microseconds(5000000), false);
579
580 // callback function for capturing signal
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500581 auto callback = [&](sdbusplus::message_t& m) {
Jason M. Bills0748c692022-09-08 15:34:08 -0700582 std::vector<
583 std::pair<std::string,
584 std::vector<std::pair<std::string, ipmi::DbusVariant>>>>
AppaRao Puli28972062019-11-11 02:04:45 +0530585 intfPropsPair;
586 sdbusplus::message::object_path objPath;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700587
588 try
589 {
AppaRao Puli28972062019-11-11 02:04:45 +0530590 m.read(objPath, intfPropsPair); // Read in the object path
591 // that was just created
Vernon Mauery52ce6622019-05-22 09:19:46 -0700592 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700593 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700594 {
AppaRao Puli28972062019-11-11 02:04:45 +0530595 phosphor::logging::log<phosphor::logging::level::ERR>(
596 "Exception caught in reading created object path.");
597 return;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700598 }
599 // constructing response message
AppaRao Puli28972062019-11-11 02:04:45 +0530600 phosphor::logging::log<phosphor::logging::level::INFO>(
601 "New Interface Added.",
602 phosphor::logging::entry("OBJPATH=%s", objPath.str.c_str()));
James Feistfcd2d3a2020-05-28 10:38:15 -0700603 for (auto& interface : intfPropsPair)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700604 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700605 if (interface.first == "xyz.openbmc_project.Software.Activation")
606 {
AppaRao Puli28972062019-11-11 02:04:45 +0530607 // There are chances of getting two signals for
608 // InterfacesAdded. So cross check and discrad second instance.
609 if (fwUpdateMatchSignal == nullptr)
610 {
611 return;
612 }
613 // Found our interface, disable callbacks
614 fwUpdateMatchSignal = nullptr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700615
AppaRao Puli28972062019-11-11 02:04:45 +0530616 phosphor::logging::log<phosphor::logging::level::INFO>(
617 "Start activationStatusTimer for status.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700618 try
619 {
620 timer.stop();
AppaRao Puli28972062019-11-11 02:04:45 +0530621 activationStatusTimer.start(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700622 std::chrono::microseconds(3000000), true);
623 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700624 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700625 {
AppaRao Puli28972062019-11-11 02:04:45 +0530626 phosphor::logging::log<phosphor::logging::level::ERR>(
627 "Exception caught in start activationStatusTimer.",
628 phosphor::logging::entry("ERROR=%s", e.what()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700629 }
630
AppaRao Puli28972062019-11-11 02:04:45 +0530631 fwUpdateStatus.updateActivationPercent(objPath.str);
632 activateImage(objPath.str);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700633 }
634 }
635 };
636
637 // Adding matcher
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500638 fwUpdateMatchSignal = std::make_unique<sdbusplus::bus::match_t>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700639 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700640 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
641 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
642 callback);
643}
James Feistfcd2d3a2020-05-28 10:38:15 -0700644static bool startFirmwareUpdate(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700645{
AppaRao Puli28972062019-11-11 02:04:45 +0530646 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
647 // the code gets to this point, the file should be transferred start the
648 // request (creating a new file in /tmp/images causes the update manager to
649 // check if it is ready for activation)
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500650 static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatchSignal;
AppaRao Puli28972062019-11-11 02:04:45 +0530651 postTransferCompleteHandler(fwUpdateMatchSignal);
Johnathan Mantey152e9142023-06-15 13:46:02 -0700652 std::string randomFname =
653 "/tmp/images/" +
654 boost::uuids::to_string(boost::uuids::random_generator()());
655 std::error_code fsError{};
656 std::filesystem::rename(uri, randomFname, fsError);
657 if (fsError)
658 {
659 // The source and destination may not be in the same
660 // filesystem.
661 std::filesystem::copy(uri, randomFname, fsError);
662 if (fsError)
663 {
664 phosphor::logging::log<phosphor::logging::level::ERR>(
665 "Unable to move/copy image to destination directory.",
666 phosphor::logging::entry("ERROR=%s",
667 fsError.message().c_str()));
668 return false;
669 }
670 std::filesystem::remove(uri);
671 }
AppaRao Puli28972062019-11-11 02:04:45 +0530672 return true;
673}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700674
Arun Lal K M153d4c12021-08-25 22:00:37 +0000675static bool transferImageFromFile(const std::string& uri, bool move = true)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700676{
677 std::error_code ec;
AppaRao Puli28972062019-11-11 02:04:45 +0530678 phosphor::logging::log<phosphor::logging::level::INFO>(
679 "Transfer Image From File.",
680 phosphor::logging::entry("URI=%s", uri.c_str()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700681 if (move)
682 {
AppaRao Puli28972062019-11-11 02:04:45 +0530683 std::filesystem::rename(uri, firmwareBufferFile, ec);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700684 }
685 else
686 {
AppaRao Puli28972062019-11-11 02:04:45 +0530687 std::filesystem::copy(uri, firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700688 std::filesystem::copy_options::overwrite_existing,
689 ec);
690 }
AppaRao Puli28972062019-11-11 02:04:45 +0530691 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700692 {
693 MappedFile mappedfw(uri);
Arun Lal K M153d4c12021-08-25 22:00:37 +0000694 if (!xferHashCheck->hash(
695 {mappedfw.data(), mappedfw.data() + mappedfw.size()}))
696 {
697 phosphor::logging::log<phosphor::logging::level::ERR>(
698 "transferImageFromFile: xferHashCheck->hash failed.");
699 return false;
700 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700701 }
702 if (ec.value())
703 {
AppaRao Puli28972062019-11-11 02:04:45 +0530704 phosphor::logging::log<phosphor::logging::level::ERR>(
705 "Image copy failed.");
Arun Lal K M153d4c12021-08-25 22:00:37 +0000706 return false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700707 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000708
709 return true;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700710}
711
712template <typename... ArgTypes>
James Feistfcd2d3a2020-05-28 10:38:15 -0700713static int executeCmd(const char* path, ArgTypes&&... tArgs)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700714{
James Feistfcd2d3a2020-05-28 10:38:15 -0700715 boost::process::child execProg(path, const_cast<char*>(tArgs)...);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700716 execProg.wait();
717 return execProg.exit_code();
718}
719
Arun Lal K M153d4c12021-08-25 22:00:37 +0000720static bool transferImageFromUsb(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700721{
Arun Lal K M153d4c12021-08-25 22:00:37 +0000722 bool ret = false;
Arun Lal K M153d4c12021-08-25 22:00:37 +0000723
AppaRao Puli28972062019-11-11 02:04:45 +0530724 phosphor::logging::log<phosphor::logging::level::INFO>(
725 "Transfer Image From USB.",
726 phosphor::logging::entry("URI=%s", uri.c_str()));
Arun Lal K M153d4c12021-08-25 22:00:37 +0000727
728 if (executeCmd(usbCtrlPath, "mount", fwUpdateUsbVolImage,
729 fwUpdateMountPoint) == 0)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700730 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000731 std::string usb_path = std::string(fwUpdateMountPoint) + "/" + uri;
732 ret = transferImageFromFile(usb_path, false);
733
734 executeCmd(usbCtrlPath, "cleanup", fwUpdateUsbVolImage,
735 fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700736 }
737
Vernon Mauery52ce6622019-05-22 09:19:46 -0700738 return ret;
739}
740
James Feistfcd2d3a2020-05-28 10:38:15 -0700741static bool transferFirmwareFromUri(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700742{
AppaRao Puli28972062019-11-11 02:04:45 +0530743 static constexpr char fwUriFile[] = "file://";
744 static constexpr char fwUriUsb[] = "usb://";
745 phosphor::logging::log<phosphor::logging::level::INFO>(
746 "Transfer Image From URI.",
747 phosphor::logging::entry("URI=%s", uri.c_str()));
748 if (boost::algorithm::starts_with(uri, fwUriFile))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700749 {
AppaRao Puli28972062019-11-11 02:04:45 +0530750 std::string fname = uri.substr(sizeof(fwUriFile) - 1);
751 if (fname != firmwareBufferFile)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700752 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000753 return transferImageFromFile(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700754 }
755 return true;
756 }
AppaRao Puli28972062019-11-11 02:04:45 +0530757 if (boost::algorithm::starts_with(uri, fwUriUsb))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700758 {
AppaRao Puli28972062019-11-11 02:04:45 +0530759 std::string fname = uri.substr(sizeof(fwUriUsb) - 1);
Arun Lal K M153d4c12021-08-25 22:00:37 +0000760 return transferImageFromUsb(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700761 }
762 return false;
763}
764
765/* Get USB-mass-storage device status: inserted => true, ejected => false */
AppaRao Puli28972062019-11-11 02:04:45 +0530766static bool getUsbStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700767{
AppaRao Puli28972062019-11-11 02:04:45 +0530768 std::filesystem::path usbDevPath =
769 std::filesystem::path("/sys/kernel/config/usb_gadget") /
770 fwUpdateUSBDevName;
771 return (std::filesystem::exists(usbDevPath) ? true : false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700772}
773
774/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530775static int attachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700776{
AppaRao Puli28972062019-11-11 02:04:45 +0530777 if (getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700778 {
779 return 1;
780 }
AppaRao Puli28972062019-11-11 02:04:45 +0530781 int ret = executeCmd(usbCtrlPath, "setup", fwUpdateUsbVolImage,
782 std::to_string(maxFirmwareImageSize / 1_MB).c_str());
Vernon Mauery52ce6622019-05-22 09:19:46 -0700783 if (!ret)
784 {
AppaRao Puli28972062019-11-11 02:04:45 +0530785 ret = executeCmd(usbCtrlPath, "insert", fwUpdateUSBDevName,
786 fwUpdateUsbVolImage);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700787 }
788 return ret;
789}
790
791/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530792static int detachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700793{
AppaRao Puli28972062019-11-11 02:04:45 +0530794 if (!getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700795 {
796 return 1;
797 }
AppaRao Puli28972062019-11-11 02:04:45 +0530798 return executeCmd(usbCtrlPath, "eject", fwUpdateUSBDevName);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700799}
AppaRao Puli28972062019-11-11 02:04:45 +0530800static uint8_t getActiveBootImage(ipmi::Context::ptr ctx)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700801{
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800802 constexpr uint8_t undefinedImage = 0x00;
AppaRao Puli28972062019-11-11 02:04:45 +0530803 constexpr uint8_t primaryImage = 0x01;
804 constexpr uint8_t secondaryImage = 0x02;
James Feistfcd2d3a2020-05-28 10:38:15 -0700805 constexpr const char* secondaryFitImageStartAddr = "22480000";
AppaRao Puli28972062019-11-11 02:04:45 +0530806
807 uint8_t bootImage = primaryImage;
808 boost::system::error_code ec;
809 std::string value = ctx->bus->yield_method_call<std::string>(
810 ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
811 "/xyz/openbmc_project/u_boot/environment/mgr",
812 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
813 if (ec)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700814 {
AppaRao Puli28972062019-11-11 02:04:45 +0530815 phosphor::logging::log<phosphor::logging::level::ERR>(
816 "Failed to read the bootcmd value");
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800817 /* don't fail, just give back undefined until it is ready */
818 bootImage = undefinedImage;
AppaRao Puli28972062019-11-11 02:04:45 +0530819 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700820
AppaRao Puli28972062019-11-11 02:04:45 +0530821 /* cheking for secondary FitImage Address 22480000 */
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800822 else if (value.find(secondaryFitImageStartAddr) != std::string::npos)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700823 {
AppaRao Puli28972062019-11-11 02:04:45 +0530824 bootImage = secondaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700825 }
826 else
827 {
AppaRao Puli28972062019-11-11 02:04:45 +0530828 bootImage = primaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700829 }
830
AppaRao Puli28972062019-11-11 02:04:45 +0530831 return bootImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700832}
833
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530834#ifdef INTEL_PFR_ENABLED
Patrick Williams1bcced02024-08-16 15:20:24 -0400835using fwVersionInfoType =
836 std::tuple<uint8_t, // ID Tag
837 uint8_t, // Major Version Number
838 uint8_t, // Minor Version Number
839 uint32_t, // Build Number
840 uint32_t, // Build Timestamp
841 uint32_t>; // Update Timestamp
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530842ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700843{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700844 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530845 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700846 // Bytes - 17:(15xN) - Repeat of 2 through 16
847
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530848 std::vector<fwVersionInfoType> fwVerInfoList;
849 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
James Feistfcd2d3a2020-05-28 10:38:15 -0700850 for (const auto& fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700851 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530852 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700853 try
854 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530855 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700856
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530857 ipmi::Value result = ipmi::getDbusProperty(
858 *busp, service, fwDev.second, versionIntf, "Version");
859 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700860 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700861 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700862 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530863 phosphor::logging::log<phosphor::logging::level::INFO>(
864 "Failed to fetch Version property",
865 phosphor::logging::entry("ERROR=%s", e.what()),
866 phosphor::logging::entry("PATH=%s", fwDev.second),
867 phosphor::logging::entry("INTERFACE=%s", versionIntf));
868 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700869 }
870
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530871 if (verStr.empty())
872 {
873 phosphor::logging::log<phosphor::logging::level::INFO>(
874 "Version is empty.",
875 phosphor::logging::entry("PATH=%s", fwDev.second),
876 phosphor::logging::entry("INTERFACE=%s", versionIntf));
877 continue;
878 }
879
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530880 uint8_t majorNum = 0;
881 uint8_t minorNum = 0;
882 uint32_t buildNum = 0;
883 try
884 {
srikanta mondal52a292b2020-07-27 23:49:14 +0000885 std::optional<ipmi::MetaRevision> rev =
886 ipmi::convertIntelVersion(verStr);
887 if (rev.has_value())
888 {
889 ipmi::MetaRevision revision = rev.value();
890 majorNum = revision.major % 10 + (revision.major / 10) * 16;
891 minorNum = (revision.minor > 99 ? 99 : revision.minor);
892 minorNum = minorNum % 10 + (minorNum / 10) * 16;
893 uint32_t hash = std::stoul(revision.metaHash, 0, 16);
894 hash = bswap_32(hash);
895 buildNum = (revision.buildNo & 0xFF) + (hash & 0xFFFFFF00);
896 }
897 else
898 {
899 std::vector<std::string> splitVer;
900 boost::split(splitVer, verStr, boost::is_any_of(".-"));
901 if (splitVer.size() < 3)
902 {
903 phosphor::logging::log<phosphor::logging::level::INFO>(
904 "Invalid Version format.",
905 phosphor::logging::entry("Version=%s", verStr.c_str()),
906 phosphor::logging::entry("PATH=%s", fwDev.second));
907 continue;
908 }
909 majorNum = std::stoul(splitVer[0], nullptr, 16);
910 minorNum = std::stoul(splitVer[1], nullptr, 16);
911 buildNum = std::stoul(splitVer[2], nullptr, 16);
912 }
913 // Build Timestamp - Not supported.
914 // Update Timestamp - TODO: Need to check with CPLD team.
915 fwVerInfoList.emplace_back(
916 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
917 minorNum, buildNum, 0, 0));
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530918 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700919 catch (const std::exception& e)
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530920 {
921 phosphor::logging::log<phosphor::logging::level::INFO>(
922 "Failed to convert stoul.",
923 phosphor::logging::entry("ERROR=%s", e.what()));
924 continue;
925 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700926 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700927
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530928 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700929}
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +0000930
Patrick Williams1bcced02024-08-16 15:20:24 -0400931std::array<uint8_t, imageCount> getSecurityVersionInfo(
932 const char* mtdDevBuf, size_t svnVerOffsetInPfm, size_t bkcVerOffsetInPfm)
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +0000933{
934 constexpr size_t bufLength = 1;
935 std::array<uint8_t, imageCount> fwSecurityVersionBuf = {0}, temp;
936 constexpr uint8_t svnIndexValue = 0x00;
937 constexpr uint8_t bkcIndexValue = 0x01;
938 constexpr uint8_t tempIndexValue = 0x00;
939 try
940 {
941 SPIDev spiDev(mtdDevBuf);
942 spiDev.spiReadData(svnVerOffsetInPfm, bufLength, temp.data());
943 fwSecurityVersionBuf.at(svnIndexValue) = temp.at(tempIndexValue);
944 spiDev.spiReadData(bkcVerOffsetInPfm, bufLength, temp.data());
945 fwSecurityVersionBuf.at(bkcIndexValue) = temp.at(tempIndexValue);
946 }
947 catch (const std::exception& e)
948 {
949 phosphor::logging::log<phosphor::logging::level::ERR>(
950 "Exception caught in getSecurityVersionInfo",
951 phosphor::logging::entry("MSG=%s", e.what()));
952 fwSecurityVersionBuf = {0, 0};
953 }
954
955 return fwSecurityVersionBuf;
956}
957
958ipmi::RspType<
959 uint8_t, // device ID
960 uint8_t, // Active Image Value
961 std::array<uint8_t, imageCount>, // Security version for Active Image
962 uint8_t, // recovery Image Value
963 std::array<uint8_t, imageCount>> // Security version for Recovery Image
AppaRao Puli28972062019-11-11 02:04:45 +0530964 ipmiGetFwSecurityVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700965{
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +0000966 static bool cacheFlag = false;
967 constexpr std::array<const char*, imageCount> mtdDevBuf = {
968 bmcActivePfmMTDDev, bmcRecoveryImgMTDDev};
969
970 // To avoid multiple reading from SPI device
971 if (!cacheFlag)
972 {
973 imgFwSecurityVersion[0] = getSecurityVersionInfo(
974 mtdDevBuf[0], svnActiveVerOffsetInPfm, bkcActiveVerOffsetInPfm);
975 imgFwSecurityVersion[1] = getSecurityVersionInfo(
976 mtdDevBuf[1], svnRecoveryVerOffsetInPfm, bkcRecoveryVerOffsetInPfm);
977 cacheFlag = true;
978 }
979
980 constexpr uint8_t ActivePfmMTDDev = 0x00;
981 constexpr uint8_t RecoveryImgMTDDev = 0x01;
982
983 return ipmi::responseSuccess(
984 imageCount, static_cast<uint8_t>(FWDeviceIDTag::bmcActiveImage),
985 imgFwSecurityVersion[ActivePfmMTDDev],
986 static_cast<uint8_t>(FWDeviceIDTag::bmcRecoveryImage),
987 imgFwSecurityVersion[RecoveryImgMTDDev]);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700988}
989
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530990ipmi::RspType<std::array<uint8_t, certKeyLen>,
991 std::optional<std::array<uint8_t, cskSignatureLen>>>
James Feistfcd2d3a2020-05-28 10:38:15 -0700992 ipmiGetFwRootCertData(const ipmi::Context::ptr& ctx, uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700993{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530994 bool isIPMBChannel = false;
995
996 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
997 {
998 return ipmi::responseUnspecifiedError();
999 }
1000 if (isIPMBChannel)
1001 {
1002 phosphor::logging::log<phosphor::logging::level::INFO>(
1003 "Command not supported. Failed to get root certificate data.");
1004 return ipmi::responseCommandNotAvailable();
1005 }
1006
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301007 size_t certKeyOffset = 0;
1008 size_t cskSigOffset = 0;
1009 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001010
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301011 switch (static_cast<FwGetRootCertDataTag>(certId))
1012 {
1013 case FwGetRootCertDataTag::activeRootKey:
1014 {
1015 mtdDev = bmcActivePfmMTDDev;
1016 certKeyOffset = rootkeyOffsetInPfm;
1017 break;
1018 }
1019 case FwGetRootCertDataTag::recoveryRootKey:
1020 {
1021 mtdDev = bmcRecoveryImgMTDDev;
1022 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
1023 break;
1024 }
1025 case FwGetRootCertDataTag::activeCSK:
1026 {
1027 mtdDev = bmcActivePfmMTDDev;
1028 certKeyOffset = cskKeyOffsetInPfm;
1029 cskSigOffset = cskSignatureOffsetInPfm;
1030 break;
1031 }
1032 case FwGetRootCertDataTag::recoveryCSK:
1033 {
1034 mtdDev = bmcRecoveryImgMTDDev;
1035 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
1036 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
1037 break;
1038 }
1039 default:
1040 {
1041 return ipmi::responseInvalidFieldRequest();
1042 }
1043 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001044
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301045 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -07001046
Vernon Mauery52ce6622019-05-22 09:19:46 -07001047 try
1048 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301049 SPIDev spiDev(mtdDev);
1050 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
1051
1052 if (cskSigOffset)
1053 {
1054 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
1055 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
1056 cskSignature.data());
1057 return ipmi::responseSuccess(certKey, cskSignature);
1058 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001059 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001060 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001061 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301062 phosphor::logging::log<phosphor::logging::level::ERR>(
1063 "Exception caught in ipmiGetFwRootCertData",
1064 phosphor::logging::entry("MSG=%s", e.what()));
1065 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001066 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001067
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301068 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001069}
AppaRao Puli28972062019-11-11 02:04:45 +05301070#endif // INTEL_PFR_ENABLED
1071
1072static constexpr uint8_t channelListSize = 3;
1073/** @brief implements Maximum Firmware Transfer size command
1074 * @parameter
1075 * - none
1076 * @returns IPMI completion code plus response data
1077 * - count - channel count
1078 * - channelList - channel list information
1079 */
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001080ipmi::RspType<uint8_t, // channel count
AppaRao Puli28972062019-11-11 02:04:45 +05301081 std::array<std::tuple<uint8_t, uint32_t>,
1082 channelListSize> // Channel List
1083 >
1084 ipmiFirmwareMaxTransferSize()
1085{
1086 constexpr size_t kcsMaxBufSize = 128;
1087 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
AppaRao Puli28972062019-11-11 02:04:45 +05301088 // Byte 1 - Count (N) Number of devices data is being returned for.
1089 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
1090 // Byte 3-6 - transfer size (little endian)
1091 // Bytes - 7:(5xN) - Repeat of 2 through 6
1092 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
1093 channelList = {
1094 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
AppaRao Puli28972062019-11-11 02:04:45 +05301095 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
1096 rmcpPlusMaxBufSize}}};
1097
1098 return ipmi::responseSuccess(channelListSize, channelList);
1099}
1100
1101ipmi::RspType<uint8_t, uint8_t>
1102 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
1103{
1104 // Byte 1 - Current execution context
1105 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
1106 // Byte 2 - Partition pointer
1107 // 0x01 - primary, 0x02 - secondary
1108 uint8_t partitionPtr = getActiveBootImage(ctx);
1109
1110 return ipmi::responseSuccess(
1111 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
1112}
AppaRao Puli28972062019-11-11 02:04:45 +05301113/** @brief Get Firmware Update Random Number
1114 *
1115 * This function generate the random number used for
1116 * setting the firmware update mode as authentication key.
1117 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301118 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301119 * @returns IPMI completion code along with
1120 * - random number
1121 **/
1122ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
James Feistfcd2d3a2020-05-28 10:38:15 -07001123 ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301124{
1125 phosphor::logging::log<phosphor::logging::level::INFO>(
1126 "Generate FW update random number");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301127 bool isIPMBChannel = false;
1128
1129 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1130 {
1131 return ipmi::responseUnspecifiedError();
1132 }
1133 if (isIPMBChannel)
1134 {
1135 phosphor::logging::log<phosphor::logging::level::INFO>(
1136 "Channel not supported. Failed to fetch FW update random number");
1137 return ipmi::responseCommandNotAvailable();
1138 }
AppaRao Puli28972062019-11-11 02:04:45 +05301139 std::random_device rd;
1140 std::default_random_engine gen(rd());
1141 std::uniform_int_distribution<> dist{0, 255};
1142
1143 fwRandomNumGenTs = std::chrono::steady_clock::now();
1144
Vernon Mauerydcff1502022-09-28 11:12:46 -07001145 for (size_t i = 0; i < fwRandomNumLength; i++)
AppaRao Puli28972062019-11-11 02:04:45 +05301146 {
1147 fwRandomNum[i] = dist(gen);
1148 }
1149
1150 return ipmi::responseSuccess(fwRandomNum);
1151}
1152
1153/** @brief Set Firmware Update Mode
1154 *
1155 * This function sets BMC into firmware update mode
1156 * after validating Random number obtained from the Get
1157 * Firmware Update Random Number command
1158 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301159 * @param[in] ctx - context of current session
1160 * @parameter randNum - Random number(token)
1161 * @returns IPMI completion code
AppaRao Puli28972062019-11-11 02:04:45 +05301162 **/
1163ipmi::RspType<>
James Feistfcd2d3a2020-05-28 10:38:15 -07001164 ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr& ctx,
1165 std::array<uint8_t, fwRandomNumLength>& randNum)
AppaRao Puli28972062019-11-11 02:04:45 +05301166{
1167 phosphor::logging::log<phosphor::logging::level::INFO>(
1168 "Start FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301169
1170 bool isIPMBChannel = false;
1171
1172 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1173 {
1174 return ipmi::responseUnspecifiedError();
1175 }
1176 if (isIPMBChannel)
1177 {
1178 phosphor::logging::log<phosphor::logging::level::INFO>(
1179 "Channel not supported. Failed to set FW update mode");
1180 return ipmi::responseCommandNotAvailable();
1181 }
AppaRao Puli28972062019-11-11 02:04:45 +05301182 /* Firmware Update Random number is valid for 30 seconds only */
1183 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1184 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1185 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1186 fwRandomNumExpirySeconds)
1187 .count())
1188 {
1189 phosphor::logging::log<phosphor::logging::level::INFO>(
1190 "Firmware update random number expired.");
1191 return ipmi::responseInvalidFieldRequest();
1192 }
1193
1194 /* Validate random number */
Vernon Mauerydcff1502022-09-28 11:12:46 -07001195 for (size_t i = 0; i < fwRandomNumLength; i++)
AppaRao Puli28972062019-11-11 02:04:45 +05301196 {
1197 if (fwRandomNum[i] != randNum[i])
1198 {
1199 phosphor::logging::log<phosphor::logging::level::INFO>(
1200 "Invalid random number specified.");
1201 return ipmi::responseInvalidFieldRequest();
1202 }
1203 }
1204
1205 try
1206 {
1207 if (getFirmwareUpdateMode())
1208 {
1209 phosphor::logging::log<phosphor::logging::level::INFO>(
1210 "Already firmware update is in progress.");
1211 return ipmi::responseBusy();
1212 }
1213 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001214 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301215 {
1216 return ipmi::responseUnspecifiedError();
1217 }
1218
1219 // FIXME? c++ doesn't off an option for exclusive file creation
James Feistfcd2d3a2020-05-28 10:38:15 -07001220 FILE* fp = fopen(firmwareBufferFile, "wx");
AppaRao Puli28972062019-11-11 02:04:45 +05301221 if (!fp)
1222 {
1223 phosphor::logging::log<phosphor::logging::level::INFO>(
1224 "Unable to open file.");
1225 return ipmi::responseUnspecifiedError();
1226 }
1227 fclose(fp);
1228
1229 try
1230 {
1231 setFirmwareUpdateMode(true);
1232 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001233 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301234 {
1235 unlink(firmwareBufferFile);
1236 return ipmi::responseUnspecifiedError();
1237 }
1238
1239 return ipmi::responseSuccess();
1240}
1241
1242/** @brief implements exit firmware update mode command
1243 * @param None
1244 *
1245 * @returns IPMI completion code
1246 */
James Feistfcd2d3a2020-05-28 10:38:15 -07001247ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301248{
1249 phosphor::logging::log<phosphor::logging::level::INFO>(
1250 "Exit FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301251 bool isIPMBChannel = false;
1252
1253 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1254 {
1255 return ipmi::responseUnspecifiedError();
1256 }
1257 if (isIPMBChannel)
1258 {
1259 phosphor::logging::log<phosphor::logging::level::INFO>(
1260 "Command not supported. Failed to exit firmware update mode");
1261 return ipmi::responseCommandNotAvailable();
1262 }
1263
AppaRao Puli28972062019-11-11 02:04:45 +05301264 switch (fwUpdateStatus.getState())
1265 {
1266 case FwUpdateStatusCache::fwStateInit:
1267 case FwUpdateStatusCache::fwStateIdle:
1268 return ipmi::responseInvalidFieldRequest();
1269 break;
1270 case FwUpdateStatusCache::fwStateDownload:
1271 case FwUpdateStatusCache::fwStateVerify:
1272 break;
1273 case FwUpdateStatusCache::fwStateProgram:
1274 break;
1275 case FwUpdateStatusCache::fwStateUpdateSuccess:
1276 case FwUpdateStatusCache::fwStateError:
1277 break;
1278 case FwUpdateStatusCache::fwStateAcCycleRequired:
1279 return ipmi::responseInvalidFieldRequest();
1280 break;
1281 }
1282 fwUpdateStatus.firmwareUpdateAbortState();
1283
1284 try
1285 {
1286 setFirmwareUpdateMode(false);
1287 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001288 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301289 {
1290 return ipmi::responseUnspecifiedError();
1291 }
1292
1293 return ipmi::responseSuccess();
1294}
1295
1296/** @brief implements Get/Set Firmware Update Control
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301297 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301298 * @parameter
1299 * - Byte 1: Control Byte
1300 * - Byte 2: Firmware filename length (Optional)
1301 * - Byte 3:N: Firmware filename data (Optional)
1302 * @returns IPMI completion code plus response data
1303 * - Byte 2: Current control status
1304 **/
Patrick Williams1bcced02024-08-16 15:20:24 -04001305ipmi::RspType<bool, bool, bool, bool, uint4_t> ipmiGetSetFirmwareUpdateControl(
1306 const ipmi::Context::ptr& ctx, const uint8_t controlReq,
1307 const std::optional<std::string>& fileName)
AppaRao Puli28972062019-11-11 02:04:45 +05301308{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301309 bool isIPMBChannel = false;
1310
1311 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1312 {
1313 return ipmi::responseUnspecifiedError();
1314 }
1315 if (isIPMBChannel)
1316 {
1317 phosphor::logging::log<phosphor::logging::level::INFO>(
1318 "Channel not supported. Failed to get or set FW update control");
1319 return ipmi::responseCommandNotAvailable();
1320 }
1321
AppaRao Puli28972062019-11-11 02:04:45 +05301322 static std::string fwXferUriPath;
1323 static bool imageTransferStarted = false;
1324 static bool imageTransferCompleted = false;
1325 static bool imageTransferAborted = false;
1326
1327 if ((controlReq !=
1328 static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
1329 (fileName))
1330 {
1331 phosphor::logging::log<phosphor::logging::level::ERR>(
1332 "Invalid request field (Filename).");
1333 return ipmi::responseInvalidFieldRequest();
1334 }
1335
1336 static bool usbAttached = getUsbStatus();
1337
1338 switch (static_cast<FwUpdateCtrlReq>(controlReq))
1339 {
1340 case FwUpdateCtrlReq::getCurrentControlStatus:
1341 phosphor::logging::log<phosphor::logging::level::INFO>(
1342 "ipmiGetSetFirmwareUpdateControl: Get status");
1343 break;
1344 case FwUpdateCtrlReq::imageTransferStart:
1345 {
1346 phosphor::logging::log<phosphor::logging::level::INFO>(
1347 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
1348 imageTransferStarted = true;
1349 // reset buffer to empty (truncate file)
1350 std::ofstream out(firmwareBufferFile,
1351 std::ofstream::binary | std::ofstream::trunc);
1352 fwXferUriPath = std::string("file://") + firmwareBufferFile;
1353 if (xferHashCheck)
1354 {
Arun Lal K M153d4c12021-08-25 22:00:37 +00001355 if (!xferHashCheck->clear())
1356 {
1357 phosphor::logging::log<phosphor::logging::level::ERR>(
1358 "clear() for xferHashCheck failed");
1359 return ipmi::responseUnspecifiedError();
1360 }
AppaRao Puli28972062019-11-11 02:04:45 +05301361 }
1362 // Setting state to download
1363 fwUpdateStatus.setState(
1364 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
1365#ifdef INTEL_PFR_ENABLED
1366 imgLength = 0;
1367 imgType = 0;
1368 block0Mapped = false;
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301369#endif
AppaRao Puli28972062019-11-11 02:04:45 +05301370 }
1371 break;
1372 case FwUpdateCtrlReq::imageTransferComplete:
1373 {
Mike Jones7599bcf2022-06-01 08:51:11 -07001374 if (!imageTransferStarted)
1375 {
1376 phosphor::logging::log<phosphor::logging::level::ERR>(
1377 "transferFirmwareUpdate not started.");
1378 return ipmi::responseNotSupportedInPresentState();
1379 }
AppaRao Puli28972062019-11-11 02:04:45 +05301380 phosphor::logging::log<phosphor::logging::level::INFO>(
1381 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
1382 if (usbAttached)
1383 {
1384 phosphor::logging::log<phosphor::logging::level::ERR>(
1385 "USB should be detached to perform this operation.");
1386 return ipmi::responseNotSupportedInPresentState();
1387 }
1388 // finish transfer based on URI
1389 if (!transferFirmwareFromUri(fwXferUriPath))
1390 {
1391 phosphor::logging::log<phosphor::logging::level::ERR>(
1392 "transferFirmwareFromUri failed.");
1393 return ipmi::responseUnspecifiedError();
1394 }
1395 // transfer complete
1396 if (xferHashCheck)
1397 {
1398 if (TransferHashCheck::HashCheck::sha2Success !=
1399 xferHashCheck->verify())
1400 {
1401 phosphor::logging::log<phosphor::logging::level::ERR>(
1402 "xferHashCheck failed.");
1403 return ipmi::responseUnspecifiedError();
1404 }
1405 }
1406 // Set state to verify and start the update
1407 fwUpdateStatus.setState(
1408 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
1409 // start the request
1410 if (!startFirmwareUpdate(firmwareBufferFile))
1411 {
1412 phosphor::logging::log<phosphor::logging::level::ERR>(
1413 "startFirmwareUpdate failed.");
1414 return ipmi::responseUnspecifiedError();
1415 }
1416 imageTransferCompleted = true;
1417 }
1418 break;
1419 case FwUpdateCtrlReq::imageTransferAbort:
1420 phosphor::logging::log<phosphor::logging::level::INFO>(
1421 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
1422 if (usbAttached)
1423 {
1424 if (detachUsbDevice())
1425 {
1426 phosphor::logging::log<phosphor::logging::level::ERR>(
1427 "Detach USB device failed.");
1428 return ipmi::responseUsbAttachOrDetachFailed();
1429 }
1430 usbAttached = false;
1431 }
1432 // During abort request reset the state to Init by cleaning update
1433 // file.
1434 fwUpdateStatus.firmwareUpdateAbortState();
1435 imageTransferAborted = true;
1436 break;
1437 case FwUpdateCtrlReq::setFirmwareFilename:
1438 phosphor::logging::log<phosphor::logging::level::INFO>(
1439 "ipmiGetSetFirmwareUpdateControl: Set filename.");
1440 if (!fileName || ((*fileName).length() == 0))
1441 {
1442 phosphor::logging::log<phosphor::logging::level::ERR>(
1443 "Invalid Filename specified.");
1444 return ipmi::responseInvalidFieldRequest();
1445 }
1446
1447 fwXferUriPath = *fileName;
1448 break;
1449 case FwUpdateCtrlReq::attachUsbDevice:
1450 phosphor::logging::log<phosphor::logging::level::INFO>(
1451 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
1452 if (usbAttached)
1453 {
1454 phosphor::logging::log<phosphor::logging::level::ERR>(
1455 "USB device is already attached.");
1456 return ipmi::responseInvalidFieldRequest();
1457 }
1458 if (attachUsbDevice())
1459 {
1460 phosphor::logging::log<phosphor::logging::level::ERR>(
1461 "Attach USB device failed.");
1462 return ipmi::responseUsbAttachOrDetachFailed();
1463 }
1464 usbAttached = true;
1465 break;
1466 case FwUpdateCtrlReq::detachUsbDevice:
1467 phosphor::logging::log<phosphor::logging::level::INFO>(
1468 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
1469 if (!usbAttached)
1470 {
1471 phosphor::logging::log<phosphor::logging::level::ERR>(
1472 "USB device is not attached.");
1473 return ipmi::responseInvalidFieldRequest();
1474 }
1475 if (detachUsbDevice())
1476 {
1477 phosphor::logging::log<phosphor::logging::level::ERR>(
1478 "Detach USB device failed.");
1479 return ipmi::responseUsbAttachOrDetachFailed();
1480 }
1481 usbAttached = false;
1482 break;
1483 default:
1484 phosphor::logging::log<phosphor::logging::level::ERR>(
1485 "Invalid control option specified.");
1486 return ipmi::responseInvalidFieldRequest();
1487 }
1488
1489 return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
1490 imageTransferAborted, usbAttached, uint4_t(0));
1491}
1492
1493/** @brief implements firmware get status command
1494 * @parameter
1495 * - none
1496 * @returns IPMI completion code plus response data
1497 * - status - processing status
1498 * - percentage - percentage completion
1499 * - check - channel integrity check status
1500 **/
1501ipmi::RspType<uint8_t, // status
1502 uint8_t, // percentage
1503 uint8_t // check
1504 >
1505 ipmiGetFirmwareUpdateStatus()
1506
1507{
1508 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1509 // 5=ready, f=error, 83=ac cycle required)
1510 // Byte 2 - percent
1511 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
1512 uint8_t status = fwUpdateStatus.getState();
1513 uint8_t percent = fwUpdateStatus.percent();
1514 uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
1515
1516 // Status code.
1517 return ipmi::responseSuccess(status, percent, check);
1518}
1519
1520ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
James Feistfcd2d3a2020-05-28 10:38:15 -07001521 const ipmi::Context::ptr& ctx, bool noDowngradeMask, bool deferRestartMask,
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301522 bool sha2CheckMask, uint5_t reserved1, bool noDowngrade, bool deferRestart,
1523 bool sha2Check, uint5_t reserved2,
1524 std::optional<std::vector<uint8_t>> integrityCheckVal)
AppaRao Puli28972062019-11-11 02:04:45 +05301525{
1526 phosphor::logging::log<phosphor::logging::level::INFO>(
1527 "Set firmware update options.");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301528 bool isIPMBChannel = false;
1529
Vernon Mauerydcff1502022-09-28 11:12:46 -07001530 if (reserved1 || reserved2)
1531 {
1532 return ipmi::responseInvalidFieldRequest();
1533 }
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301534 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1535 {
1536 return ipmi::responseUnspecifiedError();
1537 }
1538 if (isIPMBChannel)
1539 {
1540 phosphor::logging::log<phosphor::logging::level::INFO>(
1541 "Channel not supported. Failed to set firmware update options");
1542 return ipmi::responseCommandNotAvailable();
1543 }
AppaRao Puli28972062019-11-11 02:04:45 +05301544 bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
1545 bool deferRestartState = fwUpdateStatus.getDeferRestart();
1546 bool sha2CheckState = xferHashCheck ? true : false;
1547
1548 if (noDowngradeMask && (noDowngradeState != noDowngrade))
1549 {
1550 fwUpdateStatus.setInhibitDowngrade(noDowngrade);
1551 noDowngradeState = noDowngrade;
1552 }
1553 if (deferRestartMask && (deferRestartState != deferRestart))
1554 {
1555 fwUpdateStatus.setDeferRestart(deferRestart);
1556 deferRestartState = deferRestart;
1557 }
1558 if (sha2CheckMask)
1559 {
1560 if (sha2Check)
1561 {
Vernon Mauerydcff1502022-09-28 11:12:46 -07001562 size_t hashSize = EVP_MD_size(EVP_sha256());
AppaRao Puli28972062019-11-11 02:04:45 +05301563 if ((*integrityCheckVal).size() != hashSize)
1564 {
1565 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1566 "Invalid size of Hash specified.");
1567 return ipmi::responseInvalidFieldRequest();
1568 }
Arun Lal K M153d4c12021-08-25 22:00:37 +00001569
1570 try
1571 {
1572 xferHashCheck =
1573 std::make_unique<TransferHashCheck>(*integrityCheckVal);
1574 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001575 catch (const std::exception& ex)
Arun Lal K M153d4c12021-08-25 22:00:37 +00001576 {
1577 phosphor::logging::log<phosphor::logging::level::ERR>(
1578 ex.what());
1579 return ipmi::responseUnspecifiedError();
1580 }
AppaRao Puli28972062019-11-11 02:04:45 +05301581 }
1582 else
1583 {
1584 // delete the xferHashCheck object
1585 xferHashCheck.reset();
1586 }
1587 sha2CheckState = sha2CheckMask;
1588 }
1589 return ipmi::responseSuccess(noDowngradeState, deferRestartState,
Vernon Mauerydcff1502022-09-28 11:12:46 -07001590 sha2CheckState, uint5_t{});
AppaRao Puli28972062019-11-11 02:04:45 +05301591}
Vernon Mauery52ce6622019-05-22 09:19:46 -07001592
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301593ipmi::RspType<uint32_t>
James Feistfcd2d3a2020-05-28 10:38:15 -07001594 ipmiFwImageWriteData(const std::vector<uint8_t>& writeData)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001595{
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301596 const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
1597 size_t writeDataLen = writeData.size();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001598
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301599 if (!writeDataLen)
1600 {
1601 return ipmi::responseReqDataLenInvalid();
1602 }
1603
AppaRao Puli28972062019-11-11 02:04:45 +05301604 if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301605 {
AppaRao Puli28972062019-11-11 02:04:45 +05301606 phosphor::logging::log<phosphor::logging::level::ERR>(
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301607 "Invalid firmware update state.");
1608 return ipmi::response(ccCmdNotSupportedInPresentState);
1609 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001610
AppaRao Puli28972062019-11-11 02:04:45 +05301611 std::ofstream out(firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001612 std::ofstream::binary | std::ofstream::app);
1613 if (!out)
1614 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301615 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1616 "Error while opening file.");
1617 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001618 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301619
1620 uint64_t fileDataLen = out.tellp();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301621
AppaRao Puli28972062019-11-11 02:04:45 +05301622 if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001623 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301624 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1625 "Firmware image size exceeds the limit");
1626 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001627 }
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301628
James Feistfcd2d3a2020-05-28 10:38:15 -07001629 const char* data = reinterpret_cast<const char*>(writeData.data());
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301630 out.write(data, writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001631 out.close();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301632
AppaRao Puli28972062019-11-11 02:04:45 +05301633 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001634 {
Arun Lal K M153d4c12021-08-25 22:00:37 +00001635 if (!xferHashCheck->hash(writeData))
1636 {
1637 phosphor::logging::log<phosphor::logging::level::ERR>(
1638 "ipmiFwImageWriteData: xferHashCheck->hash failed.");
1639 return ipmi::responseUnspecifiedError();
1640 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001641 }
1642
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301643#ifdef INTEL_PFR_ENABLED
1644 /* PFR image block 0 - As defined in HAS */
1645 struct PFRImageBlock0
1646 {
1647 uint32_t tag;
1648 uint32_t pcLength;
1649 uint32_t pcType;
1650 uint32_t reserved1;
1651 uint8_t hash256[32];
1652 uint8_t hash384[48];
1653 uint8_t reserved2[32];
1654 } __attribute__((packed));
1655
1656 /* Get the PFR block 0 data and read the uploaded image
1657 * information( Image type, length etc) */
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301658 if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
1659 (!block0Mapped))
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301660 {
Vernon Mauerydcff1502022-09-28 11:12:46 -07001661 PFRImageBlock0 block0Data{};
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301662
AppaRao Puli28972062019-11-11 02:04:45 +05301663 std::ifstream inFile(firmwareBufferFile,
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301664 std::ios::binary | std::ios::in);
James Feistfcd2d3a2020-05-28 10:38:15 -07001665 inFile.read(reinterpret_cast<char*>(&block0Data), sizeof(block0Data));
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301666 inFile.close();
1667
1668 uint32_t magicNum = block0Data.tag;
1669
1670 /* Validate the magic number */
1671 if (magicNum != perBlock0MagicNum)
1672 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301673 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1674 "PFR image magic number not matched");
1675 return ipmi::responseInvalidFieldRequest();
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301676 }
1677 // Note:imgLength, imgType and block0Mapped are in global scope, as
1678 // these are used in cascaded updates.
1679 imgLength = block0Data.pcLength;
1680 imgType = block0Data.pcType;
1681 block0Mapped = true;
1682 }
1683#endif // end of INTEL_PFR_ENABLED
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301684 return ipmi::responseSuccess(writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001685}
1686
AppaRao Puli28972062019-11-11 02:04:45 +05301687static void registerFirmwareFunctions()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001688{
1689 // guarantee that we start with an already timed out timestamp
Patrick Williams1bcced02024-08-16 15:20:24 -04001690 fwRandomNumGenTs =
1691 std::chrono::steady_clock::now() - fwRandomNumExpirySeconds;
AppaRao Puli28972062019-11-11 02:04:45 +05301692 fwUpdateStatus.setState(
1693 static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001694
AppaRao Puli28972062019-11-11 02:04:45 +05301695 unlink(firmwareBufferFile);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001696
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301697#ifdef INTEL_PFR_ENABLED
1698 // Following commands are supported only for PFR enabled platforms
1699 // CMD:0x20 - Get Firmware Version Information
AppaRao Puli28972062019-11-11 02:04:45 +05301700 // CMD:0x21 - Get Firmware Security Version Information
1701 // CMD:0x25 - Get Root Certificate Data
Vernon Mauery52ce6622019-05-22 09:19:46 -07001702
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301703 // get firmware version information
1704 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1705 ipmi::firmware::cmdGetFwVersionInfo,
1706 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
AppaRao Puli28972062019-11-11 02:04:45 +05301707
Vernon Mauery52ce6622019-05-22 09:19:46 -07001708 // get firmware security version information
AppaRao Puli28972062019-11-11 02:04:45 +05301709 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1710 ipmi::firmware::cmdGetFwSecurityVersionInfo,
1711 ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001712
Vernon Mauery52ce6622019-05-22 09:19:46 -07001713 // get root certificate data
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301714 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1715 ipmi::firmware::cmdFwGetRootCertData,
1716 ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1717#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001718
AppaRao Puli28972062019-11-11 02:04:45 +05301719 // get firmware update channel information (max transfer sizes)
1720 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1721 ipmi::firmware::cmdGetFwUpdateChannelInfo,
1722 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001723
AppaRao Puli28972062019-11-11 02:04:45 +05301724 // get bmc execution context
1725 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1726 ipmi::firmware::cmdGetBmcExecutionContext,
1727 ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
1728
1729 // Get Firmware Update Random number
1730 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1731 ipmi::firmware::cmdGetFwUpdateRandomNumber,
1732 ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
1733
1734 // Set Firmware Update Mode
1735 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1736 ipmi::firmware::cmdSetFirmwareUpdateMode,
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301737 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001738
AppaRao Puli28972062019-11-11 02:04:45 +05301739 // Exit Firmware Update Mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001740 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
AppaRao Puli28972062019-11-11 02:04:45 +05301741 ipmi::firmware::cmdExitFirmwareUpdateMode,
1742 ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001743
AppaRao Puli28972062019-11-11 02:04:45 +05301744 // Get/Set Firmware Update Control
1745 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1746 ipmi::firmware::cmdGetSetFwUpdateControl,
1747 ipmi::Privilege::Admin,
1748 ipmiGetSetFirmwareUpdateControl);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001749
AppaRao Puli28972062019-11-11 02:04:45 +05301750 // Get Firmware Update Status
1751 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1752 ipmi::firmware::cmdGetFirmwareUpdateStatus,
1753 ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001754
AppaRao Puli28972062019-11-11 02:04:45 +05301755 // Set Firmware Update Options
1756 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1757 ipmi::firmware::cmdSetFirmwareUpdateOptions,
1758 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001759 // write image data
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301760 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1761 ipmi::firmware::cmdFwImageWriteData,
1762 ipmi::Privilege::Admin, ipmiFwImageWriteData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001763 return;
1764}