blob: 7e8f82f4a8201a6fd5ad53aba06e7a0af0c6abf8 [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}
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:
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 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) {
Jason M. Bills0748c692022-09-08 15:34:08 -0700581 std::vector<
582 std::pair<std::string,
583 std::vector<std::pair<std::string, ipmi::DbusVariant>>>>
AppaRao Puli28972062019-11-11 02:04:45 +0530584 intfPropsPair;
585 sdbusplus::message::object_path objPath;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700586
587 try
588 {
AppaRao Puli28972062019-11-11 02:04:45 +0530589 m.read(objPath, intfPropsPair); // Read in the object path
590 // that was just created
Vernon Mauery52ce6622019-05-22 09:19:46 -0700591 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700592 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700593 {
AppaRao Puli28972062019-11-11 02:04:45 +0530594 phosphor::logging::log<phosphor::logging::level::ERR>(
595 "Exception caught in reading created object path.");
596 return;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700597 }
598 // constructing response message
AppaRao Puli28972062019-11-11 02:04:45 +0530599 phosphor::logging::log<phosphor::logging::level::INFO>(
600 "New Interface Added.",
601 phosphor::logging::entry("OBJPATH=%s", objPath.str.c_str()));
James Feistfcd2d3a2020-05-28 10:38:15 -0700602 for (auto& interface : intfPropsPair)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700603 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700604 if (interface.first == "xyz.openbmc_project.Software.Activation")
605 {
AppaRao Puli28972062019-11-11 02:04:45 +0530606 // There are chances of getting two signals for
607 // InterfacesAdded. So cross check and discrad second instance.
608 if (fwUpdateMatchSignal == nullptr)
609 {
610 return;
611 }
612 // Found our interface, disable callbacks
613 fwUpdateMatchSignal = nullptr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700614
AppaRao Puli28972062019-11-11 02:04:45 +0530615 phosphor::logging::log<phosphor::logging::level::INFO>(
616 "Start activationStatusTimer for status.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700617 try
618 {
619 timer.stop();
AppaRao Puli28972062019-11-11 02:04:45 +0530620 activationStatusTimer.start(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700621 std::chrono::microseconds(3000000), true);
622 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700623 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700624 {
AppaRao Puli28972062019-11-11 02:04:45 +0530625 phosphor::logging::log<phosphor::logging::level::ERR>(
626 "Exception caught in start activationStatusTimer.",
627 phosphor::logging::entry("ERROR=%s", e.what()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700628 }
629
AppaRao Puli28972062019-11-11 02:04:45 +0530630 fwUpdateStatus.updateActivationPercent(objPath.str);
631 activateImage(objPath.str);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700632 }
633 }
634 };
635
636 // Adding matcher
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500637 fwUpdateMatchSignal = std::make_unique<sdbusplus::bus::match_t>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700638 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700639 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
640 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
641 callback);
642}
James Feistfcd2d3a2020-05-28 10:38:15 -0700643static bool startFirmwareUpdate(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700644{
AppaRao Puli28972062019-11-11 02:04:45 +0530645 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
646 // the code gets to this point, the file should be transferred start the
647 // request (creating a new file in /tmp/images causes the update manager to
648 // check if it is ready for activation)
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500649 static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatchSignal;
AppaRao Puli28972062019-11-11 02:04:45 +0530650 postTransferCompleteHandler(fwUpdateMatchSignal);
Johnathan Mantey152e9142023-06-15 13:46:02 -0700651 std::string randomFname =
652 "/tmp/images/" +
653 boost::uuids::to_string(boost::uuids::random_generator()());
654 std::error_code fsError{};
655 std::filesystem::rename(uri, randomFname, fsError);
656 if (fsError)
657 {
658 // The source and destination may not be in the same
659 // filesystem.
660 std::filesystem::copy(uri, randomFname, fsError);
661 if (fsError)
662 {
663 phosphor::logging::log<phosphor::logging::level::ERR>(
664 "Unable to move/copy image to destination directory.",
665 phosphor::logging::entry("ERROR=%s",
666 fsError.message().c_str()));
667 return false;
668 }
669 std::filesystem::remove(uri);
670 }
AppaRao Puli28972062019-11-11 02:04:45 +0530671 return true;
672}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700673
Arun Lal K M153d4c12021-08-25 22:00:37 +0000674static bool transferImageFromFile(const std::string& uri, bool move = true)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700675{
676 std::error_code ec;
AppaRao Puli28972062019-11-11 02:04:45 +0530677 phosphor::logging::log<phosphor::logging::level::INFO>(
678 "Transfer Image From File.",
679 phosphor::logging::entry("URI=%s", uri.c_str()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700680 if (move)
681 {
AppaRao Puli28972062019-11-11 02:04:45 +0530682 std::filesystem::rename(uri, firmwareBufferFile, ec);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700683 }
684 else
685 {
AppaRao Puli28972062019-11-11 02:04:45 +0530686 std::filesystem::copy(uri, firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700687 std::filesystem::copy_options::overwrite_existing,
688 ec);
689 }
AppaRao Puli28972062019-11-11 02:04:45 +0530690 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700691 {
692 MappedFile mappedfw(uri);
Arun Lal K M153d4c12021-08-25 22:00:37 +0000693 if (!xferHashCheck->hash(
694 {mappedfw.data(), mappedfw.data() + mappedfw.size()}))
695 {
696 phosphor::logging::log<phosphor::logging::level::ERR>(
697 "transferImageFromFile: xferHashCheck->hash failed.");
698 return false;
699 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700700 }
701 if (ec.value())
702 {
AppaRao Puli28972062019-11-11 02:04:45 +0530703 phosphor::logging::log<phosphor::logging::level::ERR>(
704 "Image copy failed.");
Arun Lal K M153d4c12021-08-25 22:00:37 +0000705 return false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700706 }
Arun Lal K M153d4c12021-08-25 22:00:37 +0000707
708 return true;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700709}
710
711template <typename... ArgTypes>
James Feistfcd2d3a2020-05-28 10:38:15 -0700712static int executeCmd(const char* path, ArgTypes&&... tArgs)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700713{
James Feistfcd2d3a2020-05-28 10:38:15 -0700714 boost::process::child execProg(path, const_cast<char*>(tArgs)...);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700715 execProg.wait();
716 return execProg.exit_code();
717}
718
Arun Lal K M153d4c12021-08-25 22:00:37 +0000719static bool transferImageFromUsb(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700720{
Arun Lal K M153d4c12021-08-25 22:00:37 +0000721 bool ret = false;
Arun Lal K M153d4c12021-08-25 22:00:37 +0000722
AppaRao Puli28972062019-11-11 02:04:45 +0530723 phosphor::logging::log<phosphor::logging::level::INFO>(
724 "Transfer Image From USB.",
725 phosphor::logging::entry("URI=%s", uri.c_str()));
Arun Lal K M153d4c12021-08-25 22:00:37 +0000726
727 if (executeCmd(usbCtrlPath, "mount", fwUpdateUsbVolImage,
728 fwUpdateMountPoint) == 0)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700729 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000730 std::string usb_path = std::string(fwUpdateMountPoint) + "/" + uri;
731 ret = transferImageFromFile(usb_path, false);
732
733 executeCmd(usbCtrlPath, "cleanup", fwUpdateUsbVolImage,
734 fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700735 }
736
Vernon Mauery52ce6622019-05-22 09:19:46 -0700737 return ret;
738}
739
James Feistfcd2d3a2020-05-28 10:38:15 -0700740static bool transferFirmwareFromUri(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700741{
AppaRao Puli28972062019-11-11 02:04:45 +0530742 static constexpr char fwUriFile[] = "file://";
743 static constexpr char fwUriUsb[] = "usb://";
744 phosphor::logging::log<phosphor::logging::level::INFO>(
745 "Transfer Image From URI.",
746 phosphor::logging::entry("URI=%s", uri.c_str()));
747 if (boost::algorithm::starts_with(uri, fwUriFile))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700748 {
AppaRao Puli28972062019-11-11 02:04:45 +0530749 std::string fname = uri.substr(sizeof(fwUriFile) - 1);
750 if (fname != firmwareBufferFile)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700751 {
Arun Lal K M153d4c12021-08-25 22:00:37 +0000752 return transferImageFromFile(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700753 }
754 return true;
755 }
AppaRao Puli28972062019-11-11 02:04:45 +0530756 if (boost::algorithm::starts_with(uri, fwUriUsb))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700757 {
AppaRao Puli28972062019-11-11 02:04:45 +0530758 std::string fname = uri.substr(sizeof(fwUriUsb) - 1);
Arun Lal K M153d4c12021-08-25 22:00:37 +0000759 return transferImageFromUsb(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700760 }
761 return false;
762}
763
764/* Get USB-mass-storage device status: inserted => true, ejected => false */
AppaRao Puli28972062019-11-11 02:04:45 +0530765static bool getUsbStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700766{
AppaRao Puli28972062019-11-11 02:04:45 +0530767 std::filesystem::path usbDevPath =
768 std::filesystem::path("/sys/kernel/config/usb_gadget") /
769 fwUpdateUSBDevName;
770 return (std::filesystem::exists(usbDevPath) ? true : false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700771}
772
773/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530774static int attachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700775{
AppaRao Puli28972062019-11-11 02:04:45 +0530776 if (getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700777 {
778 return 1;
779 }
AppaRao Puli28972062019-11-11 02:04:45 +0530780 int ret = executeCmd(usbCtrlPath, "setup", fwUpdateUsbVolImage,
781 std::to_string(maxFirmwareImageSize / 1_MB).c_str());
Vernon Mauery52ce6622019-05-22 09:19:46 -0700782 if (!ret)
783 {
AppaRao Puli28972062019-11-11 02:04:45 +0530784 ret = executeCmd(usbCtrlPath, "insert", fwUpdateUSBDevName,
785 fwUpdateUsbVolImage);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700786 }
787 return ret;
788}
789
790/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530791static int detachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700792{
AppaRao Puli28972062019-11-11 02:04:45 +0530793 if (!getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700794 {
795 return 1;
796 }
AppaRao Puli28972062019-11-11 02:04:45 +0530797 return executeCmd(usbCtrlPath, "eject", fwUpdateUSBDevName);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700798}
AppaRao Puli28972062019-11-11 02:04:45 +0530799static uint8_t getActiveBootImage(ipmi::Context::ptr ctx)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700800{
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800801 constexpr uint8_t undefinedImage = 0x00;
AppaRao Puli28972062019-11-11 02:04:45 +0530802 constexpr uint8_t primaryImage = 0x01;
803 constexpr uint8_t secondaryImage = 0x02;
James Feistfcd2d3a2020-05-28 10:38:15 -0700804 constexpr const char* secondaryFitImageStartAddr = "22480000";
AppaRao Puli28972062019-11-11 02:04:45 +0530805
806 uint8_t bootImage = primaryImage;
807 boost::system::error_code ec;
808 std::string value = ctx->bus->yield_method_call<std::string>(
809 ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
810 "/xyz/openbmc_project/u_boot/environment/mgr",
811 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
812 if (ec)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700813 {
AppaRao Puli28972062019-11-11 02:04:45 +0530814 phosphor::logging::log<phosphor::logging::level::ERR>(
815 "Failed to read the bootcmd value");
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800816 /* don't fail, just give back undefined until it is ready */
817 bootImage = undefinedImage;
AppaRao Puli28972062019-11-11 02:04:45 +0530818 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700819
AppaRao Puli28972062019-11-11 02:04:45 +0530820 /* cheking for secondary FitImage Address 22480000 */
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800821 else if (value.find(secondaryFitImageStartAddr) != std::string::npos)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700822 {
AppaRao Puli28972062019-11-11 02:04:45 +0530823 bootImage = secondaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700824 }
825 else
826 {
AppaRao Puli28972062019-11-11 02:04:45 +0530827 bootImage = primaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700828 }
829
AppaRao Puli28972062019-11-11 02:04:45 +0530830 return bootImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700831}
832
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530833#ifdef INTEL_PFR_ENABLED
834using fwVersionInfoType = std::tuple<uint8_t, // ID Tag
835 uint8_t, // Major Version Number
836 uint8_t, // Minor Version Number
837 uint32_t, // Build Number
838 uint32_t, // Build Timestamp
839 uint32_t>; // Update Timestamp
840ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700841{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700842 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530843 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700844 // Bytes - 17:(15xN) - Repeat of 2 through 16
845
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530846 std::vector<fwVersionInfoType> fwVerInfoList;
847 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
James Feistfcd2d3a2020-05-28 10:38:15 -0700848 for (const auto& fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700849 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530850 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700851 try
852 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530853 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700854
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530855 ipmi::Value result = ipmi::getDbusProperty(
856 *busp, service, fwDev.second, versionIntf, "Version");
857 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700858 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700859 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700860 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530861 phosphor::logging::log<phosphor::logging::level::INFO>(
862 "Failed to fetch Version property",
863 phosphor::logging::entry("ERROR=%s", e.what()),
864 phosphor::logging::entry("PATH=%s", fwDev.second),
865 phosphor::logging::entry("INTERFACE=%s", versionIntf));
866 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700867 }
868
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530869 if (verStr.empty())
870 {
871 phosphor::logging::log<phosphor::logging::level::INFO>(
872 "Version is empty.",
873 phosphor::logging::entry("PATH=%s", fwDev.second),
874 phosphor::logging::entry("INTERFACE=%s", versionIntf));
875 continue;
876 }
877
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530878 uint8_t majorNum = 0;
879 uint8_t minorNum = 0;
880 uint32_t buildNum = 0;
881 try
882 {
srikanta mondal52a292b2020-07-27 23:49:14 +0000883 std::optional<ipmi::MetaRevision> rev =
884 ipmi::convertIntelVersion(verStr);
885 if (rev.has_value())
886 {
887 ipmi::MetaRevision revision = rev.value();
888 majorNum = revision.major % 10 + (revision.major / 10) * 16;
889 minorNum = (revision.minor > 99 ? 99 : revision.minor);
890 minorNum = minorNum % 10 + (minorNum / 10) * 16;
891 uint32_t hash = std::stoul(revision.metaHash, 0, 16);
892 hash = bswap_32(hash);
893 buildNum = (revision.buildNo & 0xFF) + (hash & 0xFFFFFF00);
894 }
895 else
896 {
897 std::vector<std::string> splitVer;
898 boost::split(splitVer, verStr, boost::is_any_of(".-"));
899 if (splitVer.size() < 3)
900 {
901 phosphor::logging::log<phosphor::logging::level::INFO>(
902 "Invalid Version format.",
903 phosphor::logging::entry("Version=%s", verStr.c_str()),
904 phosphor::logging::entry("PATH=%s", fwDev.second));
905 continue;
906 }
907 majorNum = std::stoul(splitVer[0], nullptr, 16);
908 minorNum = std::stoul(splitVer[1], nullptr, 16);
909 buildNum = std::stoul(splitVer[2], nullptr, 16);
910 }
911 // Build Timestamp - Not supported.
912 // Update Timestamp - TODO: Need to check with CPLD team.
913 fwVerInfoList.emplace_back(
914 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
915 minorNum, buildNum, 0, 0));
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530916 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700917 catch (const std::exception& e)
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530918 {
919 phosphor::logging::log<phosphor::logging::level::INFO>(
920 "Failed to convert stoul.",
921 phosphor::logging::entry("ERROR=%s", e.what()));
922 continue;
923 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700924 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700925
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530926 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700927}
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +0000928
929std::array<uint8_t, imageCount> getSecurityVersionInfo(const char* mtdDevBuf,
930 size_t svnVerOffsetInPfm,
931 size_t bkcVerOffsetInPfm)
932{
933 constexpr size_t bufLength = 1;
934 std::array<uint8_t, imageCount> fwSecurityVersionBuf = {0}, temp;
935 constexpr uint8_t svnIndexValue = 0x00;
936 constexpr uint8_t bkcIndexValue = 0x01;
937 constexpr uint8_t tempIndexValue = 0x00;
938 try
939 {
940 SPIDev spiDev(mtdDevBuf);
941 spiDev.spiReadData(svnVerOffsetInPfm, bufLength, temp.data());
942 fwSecurityVersionBuf.at(svnIndexValue) = temp.at(tempIndexValue);
943 spiDev.spiReadData(bkcVerOffsetInPfm, bufLength, temp.data());
944 fwSecurityVersionBuf.at(bkcIndexValue) = temp.at(tempIndexValue);
945 }
946 catch (const std::exception& e)
947 {
948 phosphor::logging::log<phosphor::logging::level::ERR>(
949 "Exception caught in getSecurityVersionInfo",
950 phosphor::logging::entry("MSG=%s", e.what()));
951 fwSecurityVersionBuf = {0, 0};
952 }
953
954 return fwSecurityVersionBuf;
955}
956
957ipmi::RspType<
958 uint8_t, // device ID
959 uint8_t, // Active Image Value
960 std::array<uint8_t, imageCount>, // Security version for Active Image
961 uint8_t, // recovery Image Value
962 std::array<uint8_t, imageCount>> // Security version for Recovery Image
AppaRao Puli28972062019-11-11 02:04:45 +0530963 ipmiGetFwSecurityVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700964{
Punith Nadur Basavarajaiaha8dd1972020-08-19 18:05:44 +0000965 static bool cacheFlag = false;
966 constexpr std::array<const char*, imageCount> mtdDevBuf = {
967 bmcActivePfmMTDDev, bmcRecoveryImgMTDDev};
968
969 // To avoid multiple reading from SPI device
970 if (!cacheFlag)
971 {
972 imgFwSecurityVersion[0] = getSecurityVersionInfo(
973 mtdDevBuf[0], svnActiveVerOffsetInPfm, bkcActiveVerOffsetInPfm);
974 imgFwSecurityVersion[1] = getSecurityVersionInfo(
975 mtdDevBuf[1], svnRecoveryVerOffsetInPfm, bkcRecoveryVerOffsetInPfm);
976 cacheFlag = true;
977 }
978
979 constexpr uint8_t ActivePfmMTDDev = 0x00;
980 constexpr uint8_t RecoveryImgMTDDev = 0x01;
981
982 return ipmi::responseSuccess(
983 imageCount, static_cast<uint8_t>(FWDeviceIDTag::bmcActiveImage),
984 imgFwSecurityVersion[ActivePfmMTDDev],
985 static_cast<uint8_t>(FWDeviceIDTag::bmcRecoveryImage),
986 imgFwSecurityVersion[RecoveryImgMTDDev]);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700987}
988
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530989ipmi::RspType<std::array<uint8_t, certKeyLen>,
990 std::optional<std::array<uint8_t, cskSignatureLen>>>
James Feistfcd2d3a2020-05-28 10:38:15 -0700991 ipmiGetFwRootCertData(const ipmi::Context::ptr& ctx, uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700992{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530993 bool isIPMBChannel = false;
994
995 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
996 {
997 return ipmi::responseUnspecifiedError();
998 }
999 if (isIPMBChannel)
1000 {
1001 phosphor::logging::log<phosphor::logging::level::INFO>(
1002 "Command not supported. Failed to get root certificate data.");
1003 return ipmi::responseCommandNotAvailable();
1004 }
1005
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301006 size_t certKeyOffset = 0;
1007 size_t cskSigOffset = 0;
1008 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -07001009
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301010 switch (static_cast<FwGetRootCertDataTag>(certId))
1011 {
1012 case FwGetRootCertDataTag::activeRootKey:
1013 {
1014 mtdDev = bmcActivePfmMTDDev;
1015 certKeyOffset = rootkeyOffsetInPfm;
1016 break;
1017 }
1018 case FwGetRootCertDataTag::recoveryRootKey:
1019 {
1020 mtdDev = bmcRecoveryImgMTDDev;
1021 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
1022 break;
1023 }
1024 case FwGetRootCertDataTag::activeCSK:
1025 {
1026 mtdDev = bmcActivePfmMTDDev;
1027 certKeyOffset = cskKeyOffsetInPfm;
1028 cskSigOffset = cskSignatureOffsetInPfm;
1029 break;
1030 }
1031 case FwGetRootCertDataTag::recoveryCSK:
1032 {
1033 mtdDev = bmcRecoveryImgMTDDev;
1034 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
1035 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
1036 break;
1037 }
1038 default:
1039 {
1040 return ipmi::responseInvalidFieldRequest();
1041 }
1042 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001043
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301044 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -07001045
Vernon Mauery52ce6622019-05-22 09:19:46 -07001046 try
1047 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301048 SPIDev spiDev(mtdDev);
1049 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
1050
1051 if (cskSigOffset)
1052 {
1053 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
1054 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
1055 cskSignature.data());
1056 return ipmi::responseSuccess(certKey, cskSignature);
1057 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001058 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001059 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001060 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301061 phosphor::logging::log<phosphor::logging::level::ERR>(
1062 "Exception caught in ipmiGetFwRootCertData",
1063 phosphor::logging::entry("MSG=%s", e.what()));
1064 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001065 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001066
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301067 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001068}
AppaRao Puli28972062019-11-11 02:04:45 +05301069#endif // INTEL_PFR_ENABLED
1070
1071static constexpr uint8_t channelListSize = 3;
1072/** @brief implements Maximum Firmware Transfer size command
1073 * @parameter
1074 * - none
1075 * @returns IPMI completion code plus response data
1076 * - count - channel count
1077 * - channelList - channel list information
1078 */
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001079ipmi::RspType<uint8_t, // channel count
AppaRao Puli28972062019-11-11 02:04:45 +05301080 std::array<std::tuple<uint8_t, uint32_t>,
1081 channelListSize> // Channel List
1082 >
1083 ipmiFirmwareMaxTransferSize()
1084{
1085 constexpr size_t kcsMaxBufSize = 128;
1086 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
AppaRao Puli28972062019-11-11 02:04:45 +05301087 // Byte 1 - Count (N) Number of devices data is being returned for.
1088 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
1089 // Byte 3-6 - transfer size (little endian)
1090 // Bytes - 7:(5xN) - Repeat of 2 through 6
1091 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
1092 channelList = {
1093 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
AppaRao Puli28972062019-11-11 02:04:45 +05301094 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
1095 rmcpPlusMaxBufSize}}};
1096
1097 return ipmi::responseSuccess(channelListSize, channelList);
1098}
1099
1100ipmi::RspType<uint8_t, uint8_t>
1101 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
1102{
1103 // Byte 1 - Current execution context
1104 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
1105 // Byte 2 - Partition pointer
1106 // 0x01 - primary, 0x02 - secondary
1107 uint8_t partitionPtr = getActiveBootImage(ctx);
1108
1109 return ipmi::responseSuccess(
1110 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
1111}
AppaRao Puli28972062019-11-11 02:04:45 +05301112/** @brief Get Firmware Update Random Number
1113 *
1114 * This function generate the random number used for
1115 * setting the firmware update mode as authentication key.
1116 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301117 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301118 * @returns IPMI completion code along with
1119 * - random number
1120 **/
1121ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
James Feistfcd2d3a2020-05-28 10:38:15 -07001122 ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301123{
1124 phosphor::logging::log<phosphor::logging::level::INFO>(
1125 "Generate FW update random number");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301126 bool isIPMBChannel = false;
1127
1128 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1129 {
1130 return ipmi::responseUnspecifiedError();
1131 }
1132 if (isIPMBChannel)
1133 {
1134 phosphor::logging::log<phosphor::logging::level::INFO>(
1135 "Channel not supported. Failed to fetch FW update random number");
1136 return ipmi::responseCommandNotAvailable();
1137 }
AppaRao Puli28972062019-11-11 02:04:45 +05301138 std::random_device rd;
1139 std::default_random_engine gen(rd());
1140 std::uniform_int_distribution<> dist{0, 255};
1141
1142 fwRandomNumGenTs = std::chrono::steady_clock::now();
1143
Vernon Mauerydcff1502022-09-28 11:12:46 -07001144 for (size_t i = 0; i < fwRandomNumLength; i++)
AppaRao Puli28972062019-11-11 02:04:45 +05301145 {
1146 fwRandomNum[i] = dist(gen);
1147 }
1148
1149 return ipmi::responseSuccess(fwRandomNum);
1150}
1151
1152/** @brief Set Firmware Update Mode
1153 *
1154 * This function sets BMC into firmware update mode
1155 * after validating Random number obtained from the Get
1156 * Firmware Update Random Number command
1157 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301158 * @param[in] ctx - context of current session
1159 * @parameter randNum - Random number(token)
1160 * @returns IPMI completion code
AppaRao Puli28972062019-11-11 02:04:45 +05301161 **/
1162ipmi::RspType<>
James Feistfcd2d3a2020-05-28 10:38:15 -07001163 ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr& ctx,
1164 std::array<uint8_t, fwRandomNumLength>& randNum)
AppaRao Puli28972062019-11-11 02:04:45 +05301165{
1166 phosphor::logging::log<phosphor::logging::level::INFO>(
1167 "Start FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301168
1169 bool isIPMBChannel = false;
1170
1171 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1172 {
1173 return ipmi::responseUnspecifiedError();
1174 }
1175 if (isIPMBChannel)
1176 {
1177 phosphor::logging::log<phosphor::logging::level::INFO>(
1178 "Channel not supported. Failed to set FW update mode");
1179 return ipmi::responseCommandNotAvailable();
1180 }
AppaRao Puli28972062019-11-11 02:04:45 +05301181 /* Firmware Update Random number is valid for 30 seconds only */
1182 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1183 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1184 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1185 fwRandomNumExpirySeconds)
1186 .count())
1187 {
1188 phosphor::logging::log<phosphor::logging::level::INFO>(
1189 "Firmware update random number expired.");
1190 return ipmi::responseInvalidFieldRequest();
1191 }
1192
1193 /* Validate random number */
Vernon Mauerydcff1502022-09-28 11:12:46 -07001194 for (size_t i = 0; i < fwRandomNumLength; i++)
AppaRao Puli28972062019-11-11 02:04:45 +05301195 {
1196 if (fwRandomNum[i] != randNum[i])
1197 {
1198 phosphor::logging::log<phosphor::logging::level::INFO>(
1199 "Invalid random number specified.");
1200 return ipmi::responseInvalidFieldRequest();
1201 }
1202 }
1203
1204 try
1205 {
1206 if (getFirmwareUpdateMode())
1207 {
1208 phosphor::logging::log<phosphor::logging::level::INFO>(
1209 "Already firmware update is in progress.");
1210 return ipmi::responseBusy();
1211 }
1212 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001213 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301214 {
1215 return ipmi::responseUnspecifiedError();
1216 }
1217
1218 // FIXME? c++ doesn't off an option for exclusive file creation
James Feistfcd2d3a2020-05-28 10:38:15 -07001219 FILE* fp = fopen(firmwareBufferFile, "wx");
AppaRao Puli28972062019-11-11 02:04:45 +05301220 if (!fp)
1221 {
1222 phosphor::logging::log<phosphor::logging::level::INFO>(
1223 "Unable to open file.");
1224 return ipmi::responseUnspecifiedError();
1225 }
1226 fclose(fp);
1227
1228 try
1229 {
1230 setFirmwareUpdateMode(true);
1231 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001232 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301233 {
1234 unlink(firmwareBufferFile);
1235 return ipmi::responseUnspecifiedError();
1236 }
1237
1238 return ipmi::responseSuccess();
1239}
1240
1241/** @brief implements exit firmware update mode command
1242 * @param None
1243 *
1244 * @returns IPMI completion code
1245 */
James Feistfcd2d3a2020-05-28 10:38:15 -07001246ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301247{
1248 phosphor::logging::log<phosphor::logging::level::INFO>(
1249 "Exit FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301250 bool isIPMBChannel = false;
1251
1252 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1253 {
1254 return ipmi::responseUnspecifiedError();
1255 }
1256 if (isIPMBChannel)
1257 {
1258 phosphor::logging::log<phosphor::logging::level::INFO>(
1259 "Command not supported. Failed to exit firmware update mode");
1260 return ipmi::responseCommandNotAvailable();
1261 }
1262
AppaRao Puli28972062019-11-11 02:04:45 +05301263 switch (fwUpdateStatus.getState())
1264 {
1265 case FwUpdateStatusCache::fwStateInit:
1266 case FwUpdateStatusCache::fwStateIdle:
1267 return ipmi::responseInvalidFieldRequest();
1268 break;
1269 case FwUpdateStatusCache::fwStateDownload:
1270 case FwUpdateStatusCache::fwStateVerify:
1271 break;
1272 case FwUpdateStatusCache::fwStateProgram:
1273 break;
1274 case FwUpdateStatusCache::fwStateUpdateSuccess:
1275 case FwUpdateStatusCache::fwStateError:
1276 break;
1277 case FwUpdateStatusCache::fwStateAcCycleRequired:
1278 return ipmi::responseInvalidFieldRequest();
1279 break;
1280 }
1281 fwUpdateStatus.firmwareUpdateAbortState();
1282
1283 try
1284 {
1285 setFirmwareUpdateMode(false);
1286 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001287 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301288 {
1289 return ipmi::responseUnspecifiedError();
1290 }
1291
1292 return ipmi::responseSuccess();
1293}
1294
1295/** @brief implements Get/Set Firmware Update Control
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301296 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301297 * @parameter
1298 * - Byte 1: Control Byte
1299 * - Byte 2: Firmware filename length (Optional)
1300 * - Byte 3:N: Firmware filename data (Optional)
1301 * @returns IPMI completion code plus response data
1302 * - Byte 2: Current control status
1303 **/
1304ipmi::RspType<bool, bool, bool, bool, uint4_t>
James Feistfcd2d3a2020-05-28 10:38:15 -07001305 ipmiGetSetFirmwareUpdateControl(const ipmi::Context::ptr& ctx,
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301306 const uint8_t controlReq,
James Feistfcd2d3a2020-05-28 10:38:15 -07001307 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 Williamsb37abfb2023-05-10 07:50:33 -05001690 fwRandomNumGenTs = std::chrono::steady_clock::now() -
1691 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}