blob: f8672fdc13bb206254a8078d171e3f4cbbe7774e [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;
77std::array<std::array<uint8_t, imageCount>, imageCount> imgFwSecurityVersion = {
78 (0, 0), (0, 0)};
79static 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}
AppaRao Puli28972062019-11-11 02:04:45 +0530170static constexpr size_t maxFirmwareImageSize = 32_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:
317 size_t fsize;
James Feistfcd2d3a2020-05-28 10:38:15 -0700318 void* addr;
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 Williamsb37abfb2023-05-10 07:50:33 -0500383 std::map<std::string, ipmi::DbusVariant> props;
384 std::vector<std::string> inVal;
385 std::string iface;
386 try
387 {
388 msg.read(iface, props, inVal);
389 }
390 catch (const std::exception& e)
391 {
392 phosphor::logging::log<phosphor::logging::level::ERR>(
393 "Exception caught in get ActivationProgress");
394 return;
395 }
AppaRao Puli28972062019-11-11 02:04:45 +0530396
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500397 auto it = props.find("Progress");
398 if (it != props.end())
399 {
400 progressPercent = std::get<uint8_t>(it->second);
401 if (progressPercent == 100)
AppaRao Puli28972062019-11-11 02:04:45 +0530402 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500403 fwUpdateState = fwStateUpdateSuccess;
AppaRao Puli28972062019-11-11 02:04:45 +0530404 }
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500405 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700406 });
407 }
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 Williamsb37abfb2023-05-10 07:50:33 -0500468 if (ec)
469 {
470 phosphor::logging::log<phosphor::logging::level::ERR>(
471 "async_method_call error: activateImage failed");
472 return;
473 }
AppaRao Puli28972062019-11-11 02:04:45 +0530474 },
475 "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
565 static phosphor::Timer timer(
AppaRao Puli28972062019-11-11 02:04:45 +0530566 [&fwUpdateMatchSignal]() { fwUpdateMatchSignal = nullptr; });
Vernon Mauery52ce6622019-05-22 09:19:46 -0700567
AppaRao Puli28972062019-11-11 02:04:45 +0530568 static phosphor::Timer activationStatusTimer([]() {
jayaprakash Mutyalab8f2bf92020-01-27 23:17:39 +0000569 if (fwUpdateStatus.activationTimerTimeout() > 95)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700570 {
AppaRao Puli28972062019-11-11 02:04:45 +0530571 activationStatusTimer.stop();
572 fwUpdateStatus.setState(
573 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700574 }
575 });
576
577 timer.start(std::chrono::microseconds(5000000), false);
578
579 // callback function for capturing signal
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500580 auto callback = [&](sdbusplus::message_t& m) {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700581 bool flag = false;
582
Jason M. Bills0748c692022-09-08 15:34:08 -0700583 std::vector<
584 std::pair<std::string,
585 std::vector<std::pair<std::string, ipmi::DbusVariant>>>>
AppaRao Puli28972062019-11-11 02:04:45 +0530586 intfPropsPair;
587 sdbusplus::message::object_path objPath;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700588
589 try
590 {
AppaRao Puli28972062019-11-11 02:04:45 +0530591 m.read(objPath, intfPropsPair); // Read in the object path
592 // that was just created
Vernon Mauery52ce6622019-05-22 09:19:46 -0700593 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700594 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700595 {
AppaRao Puli28972062019-11-11 02:04:45 +0530596 phosphor::logging::log<phosphor::logging::level::ERR>(
597 "Exception caught in reading created object path.");
598 return;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700599 }
600 // constructing response message
AppaRao Puli28972062019-11-11 02:04:45 +0530601 phosphor::logging::log<phosphor::logging::level::INFO>(
602 "New Interface Added.",
603 phosphor::logging::entry("OBJPATH=%s", objPath.str.c_str()));
James Feistfcd2d3a2020-05-28 10:38:15 -0700604 for (auto& interface : intfPropsPair)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700605 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700606 if (interface.first == "xyz.openbmc_project.Software.Activation")
607 {
AppaRao Puli28972062019-11-11 02:04:45 +0530608 // There are chances of getting two signals for
609 // InterfacesAdded. So cross check and discrad second instance.
610 if (fwUpdateMatchSignal == nullptr)
611 {
612 return;
613 }
614 // Found our interface, disable callbacks
615 fwUpdateMatchSignal = nullptr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700616
AppaRao Puli28972062019-11-11 02:04:45 +0530617 phosphor::logging::log<phosphor::logging::level::INFO>(
618 "Start activationStatusTimer for status.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700619 try
620 {
621 timer.stop();
AppaRao Puli28972062019-11-11 02:04:45 +0530622 activationStatusTimer.start(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700623 std::chrono::microseconds(3000000), true);
624 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700625 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700626 {
AppaRao Puli28972062019-11-11 02:04:45 +0530627 phosphor::logging::log<phosphor::logging::level::ERR>(
628 "Exception caught in start activationStatusTimer.",
629 phosphor::logging::entry("ERROR=%s", e.what()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700630 }
631
AppaRao Puli28972062019-11-11 02:04:45 +0530632 fwUpdateStatus.updateActivationPercent(objPath.str);
633 activateImage(objPath.str);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700634 }
635 }
636 };
637
638 // Adding matcher
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500639 fwUpdateMatchSignal = std::make_unique<sdbusplus::bus::match_t>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700640 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700641 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
642 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
643 callback);
644}
James Feistfcd2d3a2020-05-28 10:38:15 -0700645static bool startFirmwareUpdate(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700646{
AppaRao Puli28972062019-11-11 02:04:45 +0530647 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
648 // the code gets to this point, the file should be transferred start the
649 // request (creating a new file in /tmp/images causes the update manager to
650 // check if it is ready for activation)
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500651 static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatchSignal;
AppaRao Puli28972062019-11-11 02:04:45 +0530652 postTransferCompleteHandler(fwUpdateMatchSignal);
Johnathan Mantey152e9142023-06-15 13:46:02 -0700653 std::string randomFname =
654 "/tmp/images/" +
655 boost::uuids::to_string(boost::uuids::random_generator()());
656 std::error_code fsError{};
657 std::filesystem::rename(uri, randomFname, fsError);
658 if (fsError)
659 {
660 // The source and destination may not be in the same
661 // filesystem.
662 std::filesystem::copy(uri, randomFname, fsError);
663 if (fsError)
664 {
665 phosphor::logging::log<phosphor::logging::level::ERR>(
666 "Unable to move/copy image to destination directory.",
667 phosphor::logging::entry("ERROR=%s",
668 fsError.message().c_str()));
669 return false;
670 }
671 std::filesystem::remove(uri);
672 }
AppaRao Puli28972062019-11-11 02:04:45 +0530673 return true;
674}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700675
Arun Lal K M153d4c12021-08-25 22:00:37 +0000676static bool transferImageFromFile(const std::string& uri, bool move = true)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700677{
678 std::error_code ec;
AppaRao Puli28972062019-11-11 02:04:45 +0530679 phosphor::logging::log<phosphor::logging::level::INFO>(
680 "Transfer Image From File.",
681 phosphor::logging::entry("URI=%s", uri.c_str()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700682 if (move)
683 {
AppaRao Puli28972062019-11-11 02:04:45 +0530684 std::filesystem::rename(uri, firmwareBufferFile, ec);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700685 }
686 else
687 {
AppaRao Puli28972062019-11-11 02:04:45 +0530688 std::filesystem::copy(uri, firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700689 std::filesystem::copy_options::overwrite_existing,
690 ec);
691 }
AppaRao Puli28972062019-11-11 02:04:45 +0530692 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700693 {
694 MappedFile mappedfw(uri);
Arun Lal K M153d4c12021-08-25 22:00:37 +0000695 if (!xferHashCheck->hash(
696 {mappedfw.data(), mappedfw.data() + mappedfw.size()}))
697 {
698 phosphor::logging::log<phosphor::logging::level::ERR>(
699 "transferImageFromFile: xferHashCheck->hash failed.");
700 return false;
701 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700702 }
703 if (ec.value())
704 {
AppaRao Puli28972062019-11-11 02:04:45 +0530705 phosphor::logging::log<phosphor::logging::level::ERR>(
706 "Image copy failed.");
Arun Lal K M153d4c12021-08-25 22:00:37 +0000707 return false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700708 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000709
710 return true;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700711}
712
713template <typename... ArgTypes>
James Feistfcd2d3a2020-05-28 10:38:15 -0700714static int executeCmd(const char* path, ArgTypes&&... tArgs)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700715{
James Feistfcd2d3a2020-05-28 10:38:15 -0700716 boost::process::child execProg(path, const_cast<char*>(tArgs)...);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700717 execProg.wait();
718 return execProg.exit_code();
719}
720
Arun Lal K M153d4c12021-08-25 22:00:37 +0000721static bool transferImageFromUsb(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700722{
Arun Lal K M153d4c12021-08-25 22:00:37 +0000723 bool ret = false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700724 char fwpath[fwPathMaxLength];
Arun Lal K M153d4c12021-08-25 22:00:37 +0000725
AppaRao Puli28972062019-11-11 02:04:45 +0530726 phosphor::logging::log<phosphor::logging::level::INFO>(
727 "Transfer Image From USB.",
728 phosphor::logging::entry("URI=%s", uri.c_str()));
Arun Lal K M153d4c12021-08-25 22:00:37 +0000729
730 if (executeCmd(usbCtrlPath, "mount", fwUpdateUsbVolImage,
731 fwUpdateMountPoint) == 0)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700732 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000733 std::string usb_path = std::string(fwUpdateMountPoint) + "/" + uri;
734 ret = transferImageFromFile(usb_path, false);
735
736 executeCmd(usbCtrlPath, "cleanup", fwUpdateUsbVolImage,
737 fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700738 }
739
Vernon Mauery52ce6622019-05-22 09:19:46 -0700740 return ret;
741}
742
James Feistfcd2d3a2020-05-28 10:38:15 -0700743static bool transferFirmwareFromUri(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700744{
AppaRao Puli28972062019-11-11 02:04:45 +0530745 static constexpr char fwUriFile[] = "file://";
746 static constexpr char fwUriUsb[] = "usb://";
747 phosphor::logging::log<phosphor::logging::level::INFO>(
748 "Transfer Image From URI.",
749 phosphor::logging::entry("URI=%s", uri.c_str()));
750 if (boost::algorithm::starts_with(uri, fwUriFile))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700751 {
AppaRao Puli28972062019-11-11 02:04:45 +0530752 std::string fname = uri.substr(sizeof(fwUriFile) - 1);
753 if (fname != firmwareBufferFile)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700754 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000755 return transferImageFromFile(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700756 }
757 return true;
758 }
AppaRao Puli28972062019-11-11 02:04:45 +0530759 if (boost::algorithm::starts_with(uri, fwUriUsb))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700760 {
AppaRao Puli28972062019-11-11 02:04:45 +0530761 std::string fname = uri.substr(sizeof(fwUriUsb) - 1);
Arun Lal K M153d4c12021-08-25 22:00:37 +0000762 return transferImageFromUsb(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700763 }
764 return false;
765}
766
767/* Get USB-mass-storage device status: inserted => true, ejected => false */
AppaRao Puli28972062019-11-11 02:04:45 +0530768static bool getUsbStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700769{
AppaRao Puli28972062019-11-11 02:04:45 +0530770 std::filesystem::path usbDevPath =
771 std::filesystem::path("/sys/kernel/config/usb_gadget") /
772 fwUpdateUSBDevName;
773 return (std::filesystem::exists(usbDevPath) ? true : false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700774}
775
776/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530777static int attachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700778{
AppaRao Puli28972062019-11-11 02:04:45 +0530779 if (getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700780 {
781 return 1;
782 }
AppaRao Puli28972062019-11-11 02:04:45 +0530783 int ret = executeCmd(usbCtrlPath, "setup", fwUpdateUsbVolImage,
784 std::to_string(maxFirmwareImageSize / 1_MB).c_str());
Vernon Mauery52ce6622019-05-22 09:19:46 -0700785 if (!ret)
786 {
AppaRao Puli28972062019-11-11 02:04:45 +0530787 ret = executeCmd(usbCtrlPath, "insert", fwUpdateUSBDevName,
788 fwUpdateUsbVolImage);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700789 }
790 return ret;
791}
792
793/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530794static int detachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700795{
AppaRao Puli28972062019-11-11 02:04:45 +0530796 if (!getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700797 {
798 return 1;
799 }
AppaRao Puli28972062019-11-11 02:04:45 +0530800 return executeCmd(usbCtrlPath, "eject", fwUpdateUSBDevName);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700801}
AppaRao Puli28972062019-11-11 02:04:45 +0530802static uint8_t getActiveBootImage(ipmi::Context::ptr ctx)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700803{
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800804 constexpr uint8_t undefinedImage = 0x00;
AppaRao Puli28972062019-11-11 02:04:45 +0530805 constexpr uint8_t primaryImage = 0x01;
806 constexpr uint8_t secondaryImage = 0x02;
James Feistfcd2d3a2020-05-28 10:38:15 -0700807 constexpr const char* secondaryFitImageStartAddr = "22480000";
AppaRao Puli28972062019-11-11 02:04:45 +0530808
809 uint8_t bootImage = primaryImage;
810 boost::system::error_code ec;
811 std::string value = ctx->bus->yield_method_call<std::string>(
812 ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
813 "/xyz/openbmc_project/u_boot/environment/mgr",
814 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
815 if (ec)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700816 {
AppaRao Puli28972062019-11-11 02:04:45 +0530817 phosphor::logging::log<phosphor::logging::level::ERR>(
818 "Failed to read the bootcmd value");
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800819 /* don't fail, just give back undefined until it is ready */
820 bootImage = undefinedImage;
AppaRao Puli28972062019-11-11 02:04:45 +0530821 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700822
AppaRao Puli28972062019-11-11 02:04:45 +0530823 /* cheking for secondary FitImage Address 22480000 */
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800824 else if (value.find(secondaryFitImageStartAddr) != std::string::npos)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700825 {
AppaRao Puli28972062019-11-11 02:04:45 +0530826 bootImage = secondaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700827 }
828 else
829 {
AppaRao Puli28972062019-11-11 02:04:45 +0530830 bootImage = primaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700831 }
832
AppaRao Puli28972062019-11-11 02:04:45 +0530833 return bootImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700834}
835
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530836#ifdef INTEL_PFR_ENABLED
837using fwVersionInfoType = std::tuple<uint8_t, // ID Tag
838 uint8_t, // Major Version Number
839 uint8_t, // Minor Version Number
840 uint32_t, // Build Number
841 uint32_t, // Build Timestamp
842 uint32_t>; // Update Timestamp
843ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700844{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700845 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530846 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700847 // Bytes - 17:(15xN) - Repeat of 2 through 16
848
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530849 std::vector<fwVersionInfoType> fwVerInfoList;
850 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
James Feistfcd2d3a2020-05-28 10:38:15 -0700851 for (const auto& fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700852 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530853 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700854 try
855 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530856 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700857
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530858 ipmi::Value result = ipmi::getDbusProperty(
859 *busp, service, fwDev.second, versionIntf, "Version");
860 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700861 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700862 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700863 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530864 phosphor::logging::log<phosphor::logging::level::INFO>(
865 "Failed to fetch Version property",
866 phosphor::logging::entry("ERROR=%s", e.what()),
867 phosphor::logging::entry("PATH=%s", fwDev.second),
868 phosphor::logging::entry("INTERFACE=%s", versionIntf));
869 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700870 }
871
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530872 if (verStr.empty())
873 {
874 phosphor::logging::log<phosphor::logging::level::INFO>(
875 "Version is empty.",
876 phosphor::logging::entry("PATH=%s", fwDev.second),
877 phosphor::logging::entry("INTERFACE=%s", versionIntf));
878 continue;
879 }
880
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530881 uint8_t majorNum = 0;
882 uint8_t minorNum = 0;
883 uint32_t buildNum = 0;
884 try
885 {
srikanta mondal52a292b2020-07-27 23:49:14 +0000886 std::optional<ipmi::MetaRevision> rev =
887 ipmi::convertIntelVersion(verStr);
888 if (rev.has_value())
889 {
890 ipmi::MetaRevision revision = rev.value();
891 majorNum = revision.major % 10 + (revision.major / 10) * 16;
892 minorNum = (revision.minor > 99 ? 99 : revision.minor);
893 minorNum = minorNum % 10 + (minorNum / 10) * 16;
894 uint32_t hash = std::stoul(revision.metaHash, 0, 16);
895 hash = bswap_32(hash);
896 buildNum = (revision.buildNo & 0xFF) + (hash & 0xFFFFFF00);
897 }
898 else
899 {
900 std::vector<std::string> splitVer;
901 boost::split(splitVer, verStr, boost::is_any_of(".-"));
902 if (splitVer.size() < 3)
903 {
904 phosphor::logging::log<phosphor::logging::level::INFO>(
905 "Invalid Version format.",
906 phosphor::logging::entry("Version=%s", verStr.c_str()),
907 phosphor::logging::entry("PATH=%s", fwDev.second));
908 continue;
909 }
910 majorNum = std::stoul(splitVer[0], nullptr, 16);
911 minorNum = std::stoul(splitVer[1], nullptr, 16);
912 buildNum = std::stoul(splitVer[2], nullptr, 16);
913 }
914 // Build Timestamp - Not supported.
915 // Update Timestamp - TODO: Need to check with CPLD team.
916 fwVerInfoList.emplace_back(
917 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
918 minorNum, buildNum, 0, 0));
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530919 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700920 catch (const std::exception& e)
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530921 {
922 phosphor::logging::log<phosphor::logging::level::INFO>(
923 "Failed to convert stoul.",
924 phosphor::logging::entry("ERROR=%s", e.what()));
925 continue;
926 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700927 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700928
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530929 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700930}
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +0000931
932std::array<uint8_t, imageCount> getSecurityVersionInfo(const char* mtdDevBuf,
933 size_t svnVerOffsetInPfm,
934 size_t bkcVerOffsetInPfm)
935{
936 constexpr size_t bufLength = 1;
937 std::array<uint8_t, imageCount> fwSecurityVersionBuf = {0}, temp;
938 constexpr uint8_t svnIndexValue = 0x00;
939 constexpr uint8_t bkcIndexValue = 0x01;
940 constexpr uint8_t tempIndexValue = 0x00;
941 try
942 {
943 SPIDev spiDev(mtdDevBuf);
944 spiDev.spiReadData(svnVerOffsetInPfm, bufLength, temp.data());
945 fwSecurityVersionBuf.at(svnIndexValue) = temp.at(tempIndexValue);
946 spiDev.spiReadData(bkcVerOffsetInPfm, bufLength, temp.data());
947 fwSecurityVersionBuf.at(bkcIndexValue) = temp.at(tempIndexValue);
948 }
949 catch (const std::exception& e)
950 {
951 phosphor::logging::log<phosphor::logging::level::ERR>(
952 "Exception caught in getSecurityVersionInfo",
953 phosphor::logging::entry("MSG=%s", e.what()));
954 fwSecurityVersionBuf = {0, 0};
955 }
956
957 return fwSecurityVersionBuf;
958}
959
960ipmi::RspType<
961 uint8_t, // device ID
962 uint8_t, // Active Image Value
963 std::array<uint8_t, imageCount>, // Security version for Active Image
964 uint8_t, // recovery Image Value
965 std::array<uint8_t, imageCount>> // Security version for Recovery Image
AppaRao Puli28972062019-11-11 02:04:45 +0530966 ipmiGetFwSecurityVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700967{
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +0000968 static bool cacheFlag = false;
969 constexpr std::array<const char*, imageCount> mtdDevBuf = {
970 bmcActivePfmMTDDev, bmcRecoveryImgMTDDev};
971
972 // To avoid multiple reading from SPI device
973 if (!cacheFlag)
974 {
975 imgFwSecurityVersion[0] = getSecurityVersionInfo(
976 mtdDevBuf[0], svnActiveVerOffsetInPfm, bkcActiveVerOffsetInPfm);
977 imgFwSecurityVersion[1] = getSecurityVersionInfo(
978 mtdDevBuf[1], svnRecoveryVerOffsetInPfm, bkcRecoveryVerOffsetInPfm);
979 cacheFlag = true;
980 }
981
982 constexpr uint8_t ActivePfmMTDDev = 0x00;
983 constexpr uint8_t RecoveryImgMTDDev = 0x01;
984
985 return ipmi::responseSuccess(
986 imageCount, static_cast<uint8_t>(FWDeviceIDTag::bmcActiveImage),
987 imgFwSecurityVersion[ActivePfmMTDDev],
988 static_cast<uint8_t>(FWDeviceIDTag::bmcRecoveryImage),
989 imgFwSecurityVersion[RecoveryImgMTDDev]);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700990}
991
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530992ipmi::RspType<std::array<uint8_t, certKeyLen>,
993 std::optional<std::array<uint8_t, cskSignatureLen>>>
James Feistfcd2d3a2020-05-28 10:38:15 -0700994 ipmiGetFwRootCertData(const ipmi::Context::ptr& ctx, uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700995{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530996 bool isIPMBChannel = false;
997
998 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
999 {
1000 return ipmi::responseUnspecifiedError();
1001 }
1002 if (isIPMBChannel)
1003 {
1004 phosphor::logging::log<phosphor::logging::level::INFO>(
1005 "Command not supported. Failed to get root certificate data.");
1006 return ipmi::responseCommandNotAvailable();
1007 }
1008
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301009 size_t certKeyOffset = 0;
1010 size_t cskSigOffset = 0;
1011 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001012
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301013 switch (static_cast<FwGetRootCertDataTag>(certId))
1014 {
1015 case FwGetRootCertDataTag::activeRootKey:
1016 {
1017 mtdDev = bmcActivePfmMTDDev;
1018 certKeyOffset = rootkeyOffsetInPfm;
1019 break;
1020 }
1021 case FwGetRootCertDataTag::recoveryRootKey:
1022 {
1023 mtdDev = bmcRecoveryImgMTDDev;
1024 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
1025 break;
1026 }
1027 case FwGetRootCertDataTag::activeCSK:
1028 {
1029 mtdDev = bmcActivePfmMTDDev;
1030 certKeyOffset = cskKeyOffsetInPfm;
1031 cskSigOffset = cskSignatureOffsetInPfm;
1032 break;
1033 }
1034 case FwGetRootCertDataTag::recoveryCSK:
1035 {
1036 mtdDev = bmcRecoveryImgMTDDev;
1037 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
1038 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
1039 break;
1040 }
1041 default:
1042 {
1043 return ipmi::responseInvalidFieldRequest();
1044 }
1045 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001046
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301047 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -07001048
Vernon Mauery52ce6622019-05-22 09:19:46 -07001049 try
1050 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301051 SPIDev spiDev(mtdDev);
1052 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
1053
1054 if (cskSigOffset)
1055 {
1056 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
1057 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
1058 cskSignature.data());
1059 return ipmi::responseSuccess(certKey, cskSignature);
1060 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001061 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001062 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001063 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301064 phosphor::logging::log<phosphor::logging::level::ERR>(
1065 "Exception caught in ipmiGetFwRootCertData",
1066 phosphor::logging::entry("MSG=%s", e.what()));
1067 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001068 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001069
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301070 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001071}
AppaRao Puli28972062019-11-11 02:04:45 +05301072#endif // INTEL_PFR_ENABLED
1073
1074static constexpr uint8_t channelListSize = 3;
1075/** @brief implements Maximum Firmware Transfer size command
1076 * @parameter
1077 * - none
1078 * @returns IPMI completion code plus response data
1079 * - count - channel count
1080 * - channelList - channel list information
1081 */
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001082ipmi::RspType<uint8_t, // channel count
AppaRao Puli28972062019-11-11 02:04:45 +05301083 std::array<std::tuple<uint8_t, uint32_t>,
1084 channelListSize> // Channel List
1085 >
1086 ipmiFirmwareMaxTransferSize()
1087{
1088 constexpr size_t kcsMaxBufSize = 128;
1089 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
AppaRao Puli28972062019-11-11 02:04:45 +05301090 // Byte 1 - Count (N) Number of devices data is being returned for.
1091 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
1092 // Byte 3-6 - transfer size (little endian)
1093 // Bytes - 7:(5xN) - Repeat of 2 through 6
1094 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
1095 channelList = {
1096 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
AppaRao Puli28972062019-11-11 02:04:45 +05301097 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
1098 rmcpPlusMaxBufSize}}};
1099
1100 return ipmi::responseSuccess(channelListSize, channelList);
1101}
1102
1103ipmi::RspType<uint8_t, uint8_t>
1104 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
1105{
1106 // Byte 1 - Current execution context
1107 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
1108 // Byte 2 - Partition pointer
1109 // 0x01 - primary, 0x02 - secondary
1110 uint8_t partitionPtr = getActiveBootImage(ctx);
1111
1112 return ipmi::responseSuccess(
1113 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
1114}
AppaRao Puli28972062019-11-11 02:04:45 +05301115/** @brief Get Firmware Update Random Number
1116 *
1117 * This function generate the random number used for
1118 * setting the firmware update mode as authentication key.
1119 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301120 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301121 * @returns IPMI completion code along with
1122 * - random number
1123 **/
1124ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
James Feistfcd2d3a2020-05-28 10:38:15 -07001125 ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301126{
1127 phosphor::logging::log<phosphor::logging::level::INFO>(
1128 "Generate FW update random number");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301129 bool isIPMBChannel = false;
1130
1131 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1132 {
1133 return ipmi::responseUnspecifiedError();
1134 }
1135 if (isIPMBChannel)
1136 {
1137 phosphor::logging::log<phosphor::logging::level::INFO>(
1138 "Channel not supported. Failed to fetch FW update random number");
1139 return ipmi::responseCommandNotAvailable();
1140 }
AppaRao Puli28972062019-11-11 02:04:45 +05301141 std::random_device rd;
1142 std::default_random_engine gen(rd());
1143 std::uniform_int_distribution<> dist{0, 255};
1144
1145 fwRandomNumGenTs = std::chrono::steady_clock::now();
1146
1147 for (int i = 0; i < fwRandomNumLength; i++)
1148 {
1149 fwRandomNum[i] = dist(gen);
1150 }
1151
1152 return ipmi::responseSuccess(fwRandomNum);
1153}
1154
1155/** @brief Set Firmware Update Mode
1156 *
1157 * This function sets BMC into firmware update mode
1158 * after validating Random number obtained from the Get
1159 * Firmware Update Random Number command
1160 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301161 * @param[in] ctx - context of current session
1162 * @parameter randNum - Random number(token)
1163 * @returns IPMI completion code
AppaRao Puli28972062019-11-11 02:04:45 +05301164 **/
1165ipmi::RspType<>
James Feistfcd2d3a2020-05-28 10:38:15 -07001166 ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr& ctx,
1167 std::array<uint8_t, fwRandomNumLength>& randNum)
AppaRao Puli28972062019-11-11 02:04:45 +05301168{
1169 phosphor::logging::log<phosphor::logging::level::INFO>(
1170 "Start FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301171
1172 bool isIPMBChannel = false;
1173
1174 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1175 {
1176 return ipmi::responseUnspecifiedError();
1177 }
1178 if (isIPMBChannel)
1179 {
1180 phosphor::logging::log<phosphor::logging::level::INFO>(
1181 "Channel not supported. Failed to set FW update mode");
1182 return ipmi::responseCommandNotAvailable();
1183 }
AppaRao Puli28972062019-11-11 02:04:45 +05301184 /* Firmware Update Random number is valid for 30 seconds only */
1185 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1186 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1187 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1188 fwRandomNumExpirySeconds)
1189 .count())
1190 {
1191 phosphor::logging::log<phosphor::logging::level::INFO>(
1192 "Firmware update random number expired.");
1193 return ipmi::responseInvalidFieldRequest();
1194 }
1195
1196 /* Validate random number */
1197 for (int i = 0; i < fwRandomNumLength; i++)
1198 {
1199 if (fwRandomNum[i] != randNum[i])
1200 {
1201 phosphor::logging::log<phosphor::logging::level::INFO>(
1202 "Invalid random number specified.");
1203 return ipmi::responseInvalidFieldRequest();
1204 }
1205 }
1206
1207 try
1208 {
1209 if (getFirmwareUpdateMode())
1210 {
1211 phosphor::logging::log<phosphor::logging::level::INFO>(
1212 "Already firmware update is in progress.");
1213 return ipmi::responseBusy();
1214 }
1215 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001216 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301217 {
1218 return ipmi::responseUnspecifiedError();
1219 }
1220
1221 // FIXME? c++ doesn't off an option for exclusive file creation
James Feistfcd2d3a2020-05-28 10:38:15 -07001222 FILE* fp = fopen(firmwareBufferFile, "wx");
AppaRao Puli28972062019-11-11 02:04:45 +05301223 if (!fp)
1224 {
1225 phosphor::logging::log<phosphor::logging::level::INFO>(
1226 "Unable to open file.");
1227 return ipmi::responseUnspecifiedError();
1228 }
1229 fclose(fp);
1230
1231 try
1232 {
1233 setFirmwareUpdateMode(true);
1234 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001235 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301236 {
1237 unlink(firmwareBufferFile);
1238 return ipmi::responseUnspecifiedError();
1239 }
1240
1241 return ipmi::responseSuccess();
1242}
1243
1244/** @brief implements exit firmware update mode command
1245 * @param None
1246 *
1247 * @returns IPMI completion code
1248 */
James Feistfcd2d3a2020-05-28 10:38:15 -07001249ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301250{
1251 phosphor::logging::log<phosphor::logging::level::INFO>(
1252 "Exit FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301253 bool isIPMBChannel = false;
1254
1255 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1256 {
1257 return ipmi::responseUnspecifiedError();
1258 }
1259 if (isIPMBChannel)
1260 {
1261 phosphor::logging::log<phosphor::logging::level::INFO>(
1262 "Command not supported. Failed to exit firmware update mode");
1263 return ipmi::responseCommandNotAvailable();
1264 }
1265
AppaRao Puli28972062019-11-11 02:04:45 +05301266 switch (fwUpdateStatus.getState())
1267 {
1268 case FwUpdateStatusCache::fwStateInit:
1269 case FwUpdateStatusCache::fwStateIdle:
1270 return ipmi::responseInvalidFieldRequest();
1271 break;
1272 case FwUpdateStatusCache::fwStateDownload:
1273 case FwUpdateStatusCache::fwStateVerify:
1274 break;
1275 case FwUpdateStatusCache::fwStateProgram:
1276 break;
1277 case FwUpdateStatusCache::fwStateUpdateSuccess:
1278 case FwUpdateStatusCache::fwStateError:
1279 break;
1280 case FwUpdateStatusCache::fwStateAcCycleRequired:
1281 return ipmi::responseInvalidFieldRequest();
1282 break;
1283 }
1284 fwUpdateStatus.firmwareUpdateAbortState();
1285
1286 try
1287 {
1288 setFirmwareUpdateMode(false);
1289 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001290 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301291 {
1292 return ipmi::responseUnspecifiedError();
1293 }
1294
1295 return ipmi::responseSuccess();
1296}
1297
1298/** @brief implements Get/Set Firmware Update Control
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301299 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301300 * @parameter
1301 * - Byte 1: Control Byte
1302 * - Byte 2: Firmware filename length (Optional)
1303 * - Byte 3:N: Firmware filename data (Optional)
1304 * @returns IPMI completion code plus response data
1305 * - Byte 2: Current control status
1306 **/
1307ipmi::RspType<bool, bool, bool, bool, uint4_t>
James Feistfcd2d3a2020-05-28 10:38:15 -07001308 ipmiGetSetFirmwareUpdateControl(const ipmi::Context::ptr& ctx,
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301309 const uint8_t controlReq,
James Feistfcd2d3a2020-05-28 10:38:15 -07001310 const std::optional<std::string>& fileName)
AppaRao Puli28972062019-11-11 02:04:45 +05301311{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301312 bool isIPMBChannel = false;
1313
1314 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1315 {
1316 return ipmi::responseUnspecifiedError();
1317 }
1318 if (isIPMBChannel)
1319 {
1320 phosphor::logging::log<phosphor::logging::level::INFO>(
1321 "Channel not supported. Failed to get or set FW update control");
1322 return ipmi::responseCommandNotAvailable();
1323 }
1324
AppaRao Puli28972062019-11-11 02:04:45 +05301325 static std::string fwXferUriPath;
1326 static bool imageTransferStarted = false;
1327 static bool imageTransferCompleted = false;
1328 static bool imageTransferAborted = false;
1329
1330 if ((controlReq !=
1331 static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
1332 (fileName))
1333 {
1334 phosphor::logging::log<phosphor::logging::level::ERR>(
1335 "Invalid request field (Filename).");
1336 return ipmi::responseInvalidFieldRequest();
1337 }
1338
1339 static bool usbAttached = getUsbStatus();
1340
1341 switch (static_cast<FwUpdateCtrlReq>(controlReq))
1342 {
1343 case FwUpdateCtrlReq::getCurrentControlStatus:
1344 phosphor::logging::log<phosphor::logging::level::INFO>(
1345 "ipmiGetSetFirmwareUpdateControl: Get status");
1346 break;
1347 case FwUpdateCtrlReq::imageTransferStart:
1348 {
1349 phosphor::logging::log<phosphor::logging::level::INFO>(
1350 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
1351 imageTransferStarted = true;
1352 // reset buffer to empty (truncate file)
1353 std::ofstream out(firmwareBufferFile,
1354 std::ofstream::binary | std::ofstream::trunc);
1355 fwXferUriPath = std::string("file://") + firmwareBufferFile;
1356 if (xferHashCheck)
1357 {
Arun Lal K M153d4c12021-08-25 22:00:37 +00001358 if (!xferHashCheck->clear())
1359 {
1360 phosphor::logging::log<phosphor::logging::level::ERR>(
1361 "clear() for xferHashCheck failed");
1362 return ipmi::responseUnspecifiedError();
1363 }
AppaRao Puli28972062019-11-11 02:04:45 +05301364 }
1365 // Setting state to download
1366 fwUpdateStatus.setState(
1367 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
1368#ifdef INTEL_PFR_ENABLED
1369 imgLength = 0;
1370 imgType = 0;
1371 block0Mapped = false;
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301372#endif
AppaRao Puli28972062019-11-11 02:04:45 +05301373 }
1374 break;
1375 case FwUpdateCtrlReq::imageTransferComplete:
1376 {
Mike Jones7599bcf2022-06-01 08:51:11 -07001377 if (!imageTransferStarted)
1378 {
1379 phosphor::logging::log<phosphor::logging::level::ERR>(
1380 "transferFirmwareUpdate not started.");
1381 return ipmi::responseNotSupportedInPresentState();
1382 }
AppaRao Puli28972062019-11-11 02:04:45 +05301383 phosphor::logging::log<phosphor::logging::level::INFO>(
1384 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
1385 if (usbAttached)
1386 {
1387 phosphor::logging::log<phosphor::logging::level::ERR>(
1388 "USB should be detached to perform this operation.");
1389 return ipmi::responseNotSupportedInPresentState();
1390 }
1391 // finish transfer based on URI
1392 if (!transferFirmwareFromUri(fwXferUriPath))
1393 {
1394 phosphor::logging::log<phosphor::logging::level::ERR>(
1395 "transferFirmwareFromUri failed.");
1396 return ipmi::responseUnspecifiedError();
1397 }
1398 // transfer complete
1399 if (xferHashCheck)
1400 {
1401 if (TransferHashCheck::HashCheck::sha2Success !=
1402 xferHashCheck->verify())
1403 {
1404 phosphor::logging::log<phosphor::logging::level::ERR>(
1405 "xferHashCheck failed.");
1406 return ipmi::responseUnspecifiedError();
1407 }
1408 }
1409 // Set state to verify and start the update
1410 fwUpdateStatus.setState(
1411 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
1412 // start the request
1413 if (!startFirmwareUpdate(firmwareBufferFile))
1414 {
1415 phosphor::logging::log<phosphor::logging::level::ERR>(
1416 "startFirmwareUpdate failed.");
1417 return ipmi::responseUnspecifiedError();
1418 }
1419 imageTransferCompleted = true;
1420 }
1421 break;
1422 case FwUpdateCtrlReq::imageTransferAbort:
1423 phosphor::logging::log<phosphor::logging::level::INFO>(
1424 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
1425 if (usbAttached)
1426 {
1427 if (detachUsbDevice())
1428 {
1429 phosphor::logging::log<phosphor::logging::level::ERR>(
1430 "Detach USB device failed.");
1431 return ipmi::responseUsbAttachOrDetachFailed();
1432 }
1433 usbAttached = false;
1434 }
1435 // During abort request reset the state to Init by cleaning update
1436 // file.
1437 fwUpdateStatus.firmwareUpdateAbortState();
1438 imageTransferAborted = true;
1439 break;
1440 case FwUpdateCtrlReq::setFirmwareFilename:
1441 phosphor::logging::log<phosphor::logging::level::INFO>(
1442 "ipmiGetSetFirmwareUpdateControl: Set filename.");
1443 if (!fileName || ((*fileName).length() == 0))
1444 {
1445 phosphor::logging::log<phosphor::logging::level::ERR>(
1446 "Invalid Filename specified.");
1447 return ipmi::responseInvalidFieldRequest();
1448 }
1449
1450 fwXferUriPath = *fileName;
1451 break;
1452 case FwUpdateCtrlReq::attachUsbDevice:
1453 phosphor::logging::log<phosphor::logging::level::INFO>(
1454 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
1455 if (usbAttached)
1456 {
1457 phosphor::logging::log<phosphor::logging::level::ERR>(
1458 "USB device is already attached.");
1459 return ipmi::responseInvalidFieldRequest();
1460 }
1461 if (attachUsbDevice())
1462 {
1463 phosphor::logging::log<phosphor::logging::level::ERR>(
1464 "Attach USB device failed.");
1465 return ipmi::responseUsbAttachOrDetachFailed();
1466 }
1467 usbAttached = true;
1468 break;
1469 case FwUpdateCtrlReq::detachUsbDevice:
1470 phosphor::logging::log<phosphor::logging::level::INFO>(
1471 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
1472 if (!usbAttached)
1473 {
1474 phosphor::logging::log<phosphor::logging::level::ERR>(
1475 "USB device is not attached.");
1476 return ipmi::responseInvalidFieldRequest();
1477 }
1478 if (detachUsbDevice())
1479 {
1480 phosphor::logging::log<phosphor::logging::level::ERR>(
1481 "Detach USB device failed.");
1482 return ipmi::responseUsbAttachOrDetachFailed();
1483 }
1484 usbAttached = false;
1485 break;
1486 default:
1487 phosphor::logging::log<phosphor::logging::level::ERR>(
1488 "Invalid control option specified.");
1489 return ipmi::responseInvalidFieldRequest();
1490 }
1491
1492 return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
1493 imageTransferAborted, usbAttached, uint4_t(0));
1494}
1495
1496/** @brief implements firmware get status command
1497 * @parameter
1498 * - none
1499 * @returns IPMI completion code plus response data
1500 * - status - processing status
1501 * - percentage - percentage completion
1502 * - check - channel integrity check status
1503 **/
1504ipmi::RspType<uint8_t, // status
1505 uint8_t, // percentage
1506 uint8_t // check
1507 >
1508 ipmiGetFirmwareUpdateStatus()
1509
1510{
1511 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1512 // 5=ready, f=error, 83=ac cycle required)
1513 // Byte 2 - percent
1514 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
1515 uint8_t status = fwUpdateStatus.getState();
1516 uint8_t percent = fwUpdateStatus.percent();
1517 uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
1518
1519 // Status code.
1520 return ipmi::responseSuccess(status, percent, check);
1521}
1522
1523ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
James Feistfcd2d3a2020-05-28 10:38:15 -07001524 const ipmi::Context::ptr& ctx, bool noDowngradeMask, bool deferRestartMask,
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301525 bool sha2CheckMask, uint5_t reserved1, bool noDowngrade, bool deferRestart,
1526 bool sha2Check, uint5_t reserved2,
1527 std::optional<std::vector<uint8_t>> integrityCheckVal)
AppaRao Puli28972062019-11-11 02:04:45 +05301528{
1529 phosphor::logging::log<phosphor::logging::level::INFO>(
1530 "Set firmware update options.");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301531 bool isIPMBChannel = false;
1532
1533 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1534 {
1535 return ipmi::responseUnspecifiedError();
1536 }
1537 if (isIPMBChannel)
1538 {
1539 phosphor::logging::log<phosphor::logging::level::INFO>(
1540 "Channel not supported. Failed to set firmware update options");
1541 return ipmi::responseCommandNotAvailable();
1542 }
AppaRao Puli28972062019-11-11 02:04:45 +05301543 bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
1544 bool deferRestartState = fwUpdateStatus.getDeferRestart();
1545 bool sha2CheckState = xferHashCheck ? true : false;
1546
1547 if (noDowngradeMask && (noDowngradeState != noDowngrade))
1548 {
1549 fwUpdateStatus.setInhibitDowngrade(noDowngrade);
1550 noDowngradeState = noDowngrade;
1551 }
1552 if (deferRestartMask && (deferRestartState != deferRestart))
1553 {
1554 fwUpdateStatus.setDeferRestart(deferRestart);
1555 deferRestartState = deferRestart;
1556 }
1557 if (sha2CheckMask)
1558 {
1559 if (sha2Check)
1560 {
1561 auto hashSize = EVP_MD_size(EVP_sha256());
1562 if ((*integrityCheckVal).size() != hashSize)
1563 {
1564 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1565 "Invalid size of Hash specified.");
1566 return ipmi::responseInvalidFieldRequest();
1567 }
Arun Lal K M153d4c12021-08-25 22:00:37 +00001568
1569 try
1570 {
1571 xferHashCheck =
1572 std::make_unique<TransferHashCheck>(*integrityCheckVal);
1573 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001574 catch (const std::exception& ex)
Arun Lal K M153d4c12021-08-25 22:00:37 +00001575 {
1576 phosphor::logging::log<phosphor::logging::level::ERR>(
1577 ex.what());
1578 return ipmi::responseUnspecifiedError();
1579 }
AppaRao Puli28972062019-11-11 02:04:45 +05301580 }
1581 else
1582 {
1583 // delete the xferHashCheck object
1584 xferHashCheck.reset();
1585 }
1586 sha2CheckState = sha2CheckMask;
1587 }
1588 return ipmi::responseSuccess(noDowngradeState, deferRestartState,
1589 sha2CheckState, reserved1);
1590}
Vernon Mauery52ce6622019-05-22 09:19:46 -07001591
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301592ipmi::RspType<uint32_t>
James Feistfcd2d3a2020-05-28 10:38:15 -07001593 ipmiFwImageWriteData(const std::vector<uint8_t>& writeData)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001594{
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301595 const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
1596 size_t writeDataLen = writeData.size();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001597
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301598 if (!writeDataLen)
1599 {
1600 return ipmi::responseReqDataLenInvalid();
1601 }
1602
AppaRao Puli28972062019-11-11 02:04:45 +05301603 if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301604 {
AppaRao Puli28972062019-11-11 02:04:45 +05301605 phosphor::logging::log<phosphor::logging::level::ERR>(
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301606 "Invalid firmware update state.");
1607 return ipmi::response(ccCmdNotSupportedInPresentState);
1608 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001609
AppaRao Puli28972062019-11-11 02:04:45 +05301610 std::ofstream out(firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001611 std::ofstream::binary | std::ofstream::app);
1612 if (!out)
1613 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301614 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1615 "Error while opening file.");
1616 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001617 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301618
1619 uint64_t fileDataLen = out.tellp();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301620
AppaRao Puli28972062019-11-11 02:04:45 +05301621 if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001622 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301623 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1624 "Firmware image size exceeds the limit");
1625 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001626 }
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301627
James Feistfcd2d3a2020-05-28 10:38:15 -07001628 const char* data = reinterpret_cast<const char*>(writeData.data());
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301629 out.write(data, writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001630 out.close();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301631
AppaRao Puli28972062019-11-11 02:04:45 +05301632 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001633 {
Arun Lal K M153d4c12021-08-25 22:00:37 +00001634 if (!xferHashCheck->hash(writeData))
1635 {
1636 phosphor::logging::log<phosphor::logging::level::ERR>(
1637 "ipmiFwImageWriteData: xferHashCheck->hash failed.");
1638 return ipmi::responseUnspecifiedError();
1639 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001640 }
1641
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301642#ifdef INTEL_PFR_ENABLED
1643 /* PFR image block 0 - As defined in HAS */
1644 struct PFRImageBlock0
1645 {
1646 uint32_t tag;
1647 uint32_t pcLength;
1648 uint32_t pcType;
1649 uint32_t reserved1;
1650 uint8_t hash256[32];
1651 uint8_t hash384[48];
1652 uint8_t reserved2[32];
1653 } __attribute__((packed));
1654
1655 /* Get the PFR block 0 data and read the uploaded image
1656 * information( Image type, length etc) */
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301657 if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
1658 (!block0Mapped))
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301659 {
1660 struct PFRImageBlock0 block0Data = {0};
1661
AppaRao Puli28972062019-11-11 02:04:45 +05301662 std::ifstream inFile(firmwareBufferFile,
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301663 std::ios::binary | std::ios::in);
James Feistfcd2d3a2020-05-28 10:38:15 -07001664 inFile.read(reinterpret_cast<char*>(&block0Data), sizeof(block0Data));
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301665 inFile.close();
1666
1667 uint32_t magicNum = block0Data.tag;
1668
1669 /* Validate the magic number */
1670 if (magicNum != perBlock0MagicNum)
1671 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301672 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1673 "PFR image magic number not matched");
1674 return ipmi::responseInvalidFieldRequest();
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301675 }
1676 // Note:imgLength, imgType and block0Mapped are in global scope, as
1677 // these are used in cascaded updates.
1678 imgLength = block0Data.pcLength;
1679 imgType = block0Data.pcType;
1680 block0Mapped = true;
1681 }
1682#endif // end of INTEL_PFR_ENABLED
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301683 return ipmi::responseSuccess(writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001684}
1685
AppaRao Puli28972062019-11-11 02:04:45 +05301686static void registerFirmwareFunctions()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001687{
1688 // guarantee that we start with an already timed out timestamp
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001689 fwRandomNumGenTs = std::chrono::steady_clock::now() -
1690 fwRandomNumExpirySeconds;
AppaRao Puli28972062019-11-11 02:04:45 +05301691 fwUpdateStatus.setState(
1692 static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001693
AppaRao Puli28972062019-11-11 02:04:45 +05301694 unlink(firmwareBufferFile);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001695
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301696#ifdef INTEL_PFR_ENABLED
1697 // Following commands are supported only for PFR enabled platforms
1698 // CMD:0x20 - Get Firmware Version Information
AppaRao Puli28972062019-11-11 02:04:45 +05301699 // CMD:0x21 - Get Firmware Security Version Information
1700 // CMD:0x25 - Get Root Certificate Data
Vernon Mauery52ce6622019-05-22 09:19:46 -07001701
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301702 // get firmware version information
1703 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1704 ipmi::firmware::cmdGetFwVersionInfo,
1705 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
AppaRao Puli28972062019-11-11 02:04:45 +05301706
Vernon Mauery52ce6622019-05-22 09:19:46 -07001707 // get firmware security version information
AppaRao Puli28972062019-11-11 02:04:45 +05301708 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1709 ipmi::firmware::cmdGetFwSecurityVersionInfo,
1710 ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001711
Vernon Mauery52ce6622019-05-22 09:19:46 -07001712 // get root certificate data
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301713 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1714 ipmi::firmware::cmdFwGetRootCertData,
1715 ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1716#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001717
AppaRao Puli28972062019-11-11 02:04:45 +05301718 // get firmware update channel information (max transfer sizes)
1719 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1720 ipmi::firmware::cmdGetFwUpdateChannelInfo,
1721 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001722
AppaRao Puli28972062019-11-11 02:04:45 +05301723 // get bmc execution context
1724 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1725 ipmi::firmware::cmdGetBmcExecutionContext,
1726 ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
1727
1728 // Get Firmware Update Random number
1729 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1730 ipmi::firmware::cmdGetFwUpdateRandomNumber,
1731 ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
1732
1733 // Set Firmware Update Mode
1734 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1735 ipmi::firmware::cmdSetFirmwareUpdateMode,
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301736 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001737
AppaRao Puli28972062019-11-11 02:04:45 +05301738 // Exit Firmware Update Mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001739 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
AppaRao Puli28972062019-11-11 02:04:45 +05301740 ipmi::firmware::cmdExitFirmwareUpdateMode,
1741 ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001742
AppaRao Puli28972062019-11-11 02:04:45 +05301743 // Get/Set Firmware Update Control
1744 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1745 ipmi::firmware::cmdGetSetFwUpdateControl,
1746 ipmi::Privilege::Admin,
1747 ipmiGetSetFirmwareUpdateControl);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001748
AppaRao Puli28972062019-11-11 02:04:45 +05301749 // Get Firmware Update Status
1750 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1751 ipmi::firmware::cmdGetFirmwareUpdateStatus,
1752 ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001753
AppaRao Puli28972062019-11-11 02:04:45 +05301754 // Set Firmware Update Options
1755 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1756 ipmi::firmware::cmdSetFirmwareUpdateOptions,
1757 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001758 // write image data
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301759 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1760 ipmi::firmware::cmdFwImageWriteData,
1761 ipmi::Privilege::Admin, ipmiFwImageWriteData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001762 return;
1763}