blob: 8c3cc94b5349d155add11dd8b7f0743a8ad405fe [file] [log] [blame]
Vernon Mauery52ce6622019-05-22 09:19:46 -07001#include <ipmid/api.h>
2#include <openssl/evp.h>
3#include <openssl/sha.h>
4#include <sys/mman.h>
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8
9#include <boost/algorithm/string.hpp>
AppaRao Puli28972062019-11-11 02:04:45 +053010#include <boost/container/flat_map.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070011#include <boost/process/child.hpp>
12#include <boost/uuid/random_generator.hpp>
13#include <boost/uuid/uuid_io.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070014#include <commandutils.hpp>
anil kumar appana6c7d9382019-05-31 14:33:13 +000015#include <ipmid/api.hpp>
AppaRao Puli37fde6b2019-10-25 16:37:50 +053016#include <ipmid/utils.hpp>
AppaRao Puli28972062019-11-11 02:04:45 +053017#include <phosphor-logging/log.hpp>
Vernon Mauery52ce6622019-05-22 09:19:46 -070018#include <sdbusplus/bus.hpp>
19#include <sdbusplus/bus/match.hpp>
20#include <sdbusplus/server/object.hpp>
21#include <sdbusplus/timer.hpp>
Patrick Venturec2a07d42020-05-30 16:35:03 -070022#include <types.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070023
24#include <chrono>
25#include <cstdint>
26#include <filesystem>
27#include <fstream>
28#include <iostream>
29#include <map>
30#include <random>
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +053031#ifdef INTEL_PFR_ENABLED
32#include <spiDev.hpp>
33#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -070034
AppaRao Puli28972062019-11-11 02:04:45 +053035static constexpr bool DEBUG = true;
36static void registerFirmwareFunctions() __attribute__((constructor));
37
AppaRao Puli37fde6b2019-10-25 16:37:50 +053038namespace ipmi
39{
40namespace firmware
41{
42constexpr Cmd cmdGetFwVersionInfo = 0x20;
AppaRao Puli28972062019-11-11 02:04:45 +053043constexpr Cmd cmdGetFwSecurityVersionInfo = 0x21;
44constexpr Cmd cmdGetFwUpdateChannelInfo = 0x22;
45constexpr Cmd cmdGetBmcExecutionContext = 0x23;
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +053046constexpr Cmd cmdFwGetRootCertData = 0x25;
AppaRao Puli28972062019-11-11 02:04:45 +053047constexpr Cmd cmdGetFwUpdateRandomNumber = 0x26;
48constexpr Cmd cmdSetFirmwareUpdateMode = 0x27;
49constexpr Cmd cmdExitFirmwareUpdateMode = 0x28;
50constexpr Cmd cmdGetSetFwUpdateControl = 0x29;
51constexpr Cmd cmdGetFirmwareUpdateStatus = 0x2A;
52constexpr Cmd cmdSetFirmwareUpdateOptions = 0x2B;
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +053053constexpr Cmd cmdFwImageWriteData = 0x2c;
AppaRao Puli37fde6b2019-10-25 16:37:50 +053054} // namespace firmware
55} // namespace ipmi
56
AppaRao Puli28972062019-11-11 02:04:45 +053057namespace ipmi
58{
59// Custom completion codes
60constexpr Cc ccUsbAttachOrDetachFailed = 0x80;
61constexpr Cc ccNotSupportedInPresentState = 0xD5;
62
63static inline auto responseUsbAttachOrDetachFailed()
64{
65 return response(ccUsbAttachOrDetachFailed);
66}
67static inline auto responseNotSupportedInPresentState()
68{
69 return response(ccNotSupportedInPresentState);
70}
71} // namespace ipmi
72
James Feistfcd2d3a2020-05-28 10:38:15 -070073static constexpr const char* bmcStateIntf = "xyz.openbmc_project.State.BMC";
74static constexpr const char* bmcStatePath = "/xyz/openbmc_project/state/bmc0";
75static constexpr const char* bmcStateReady =
AppaRao Puli28972062019-11-11 02:04:45 +053076 "xyz.openbmc_project.State.BMC.BMCState.Ready";
James Feistfcd2d3a2020-05-28 10:38:15 -070077static constexpr const char* bmcStateUpdateInProgress =
AppaRao Puli28972062019-11-11 02:04:45 +053078 "xyz.openbmc_project.State.BMC.BMCState.UpdateInProgress";
79
80static constexpr char firmwareBufferFile[] = "/tmp/fw-download.bin";
81static std::chrono::steady_clock::time_point fwRandomNumGenTs;
82static constexpr auto fwRandomNumExpirySeconds = std::chrono::seconds(30);
83static constexpr size_t fwRandomNumLength = 8;
84static std::array<uint8_t, fwRandomNumLength> fwRandomNum;
85constexpr char usbCtrlPath[] = "/usr/bin/usb-ctrl";
86constexpr char fwUpdateMountPoint[] = "/tmp/usb-fwupd.mnt";
87constexpr char fwUpdateUsbVolImage[] = "/tmp/usb-fwupd.img";
88constexpr char fwUpdateUSBDevName[] = "fw-usb-mass-storage-dev";
89constexpr size_t fwPathMaxLength = 255;
90
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +053091#ifdef INTEL_PFR_ENABLED
92uint32_t imgLength = 0;
93uint32_t imgType = 0;
94bool block0Mapped = false;
95static constexpr uint32_t perBlock0MagicNum = 0xB6EAFD19;
AppaRao Puli37fde6b2019-10-25 16:37:50 +053096
James Feistfcd2d3a2020-05-28 10:38:15 -070097static constexpr const char* bmcActivePfmMTDDev = "/dev/mtd/pfm";
98static constexpr const char* bmcRecoveryImgMTDDev = "/dev/mtd/rc-image";
AppaRao Puli28972062019-11-11 02:04:45 +053099static constexpr size_t pfmBaseOffsetInImage = 0x400;
100static constexpr size_t rootkeyOffsetInPfm = 0xA0;
101static constexpr size_t cskKeyOffsetInPfm = 0x124;
102static constexpr size_t cskSignatureOffsetInPfm = 0x19c;
103static constexpr size_t certKeyLen = 96;
104static constexpr size_t cskSignatureLen = 96;
105
James Feistfcd2d3a2020-05-28 10:38:15 -0700106static constexpr const char* versionIntf =
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530107 "xyz.openbmc_project.Software.Version";
108
AppaRao Puli28972062019-11-11 02:04:45 +0530109enum class FwGetRootCertDataTag : uint8_t
110{
111 activeRootKey = 1,
112 recoveryRootKey,
113 activeCSK,
114 recoveryCSK,
115};
116
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530117enum class FWDeviceIDTag : uint8_t
118{
119 bmcActiveImage = 1,
120 bmcRecoveryImage,
121};
122
James Feistfcd2d3a2020-05-28 10:38:15 -0700123const static boost::container::flat_map<FWDeviceIDTag, const char*>
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530124 fwVersionIdMap{{FWDeviceIDTag::bmcActiveImage,
125 "/xyz/openbmc_project/software/bmc_active"},
126 {FWDeviceIDTag::bmcRecoveryImage,
127 "/xyz/openbmc_project/software/bmc_recovery"}};
AppaRao Puli28972062019-11-11 02:04:45 +0530128#endif // INTEL_PFR_ENABLED
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530129
AppaRao Puli28972062019-11-11 02:04:45 +0530130enum class ChannelIdTag : uint8_t
131{
132 reserved = 0,
133 kcs = 1,
134 ipmb = 2,
135 rmcpPlus = 3
136};
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +0530137
AppaRao Puli28972062019-11-11 02:04:45 +0530138enum class BmcExecutionContext : uint8_t
139{
140 reserved = 0,
141 linuxOs = 0x10,
142 bootLoader = 0x11,
143};
AppaRao Puli09a83142019-11-23 02:46:06 +0530144
AppaRao Puli28972062019-11-11 02:04:45 +0530145enum class FwUpdateCtrlReq : uint8_t
146{
147 getCurrentControlStatus = 0x00,
148 imageTransferStart = 0x01,
149 imageTransferComplete = 0x02,
150 imageTransferAbort = 0x03,
151 setFirmwareFilename = 0x04,
152 attachUsbDevice = 0x05,
153 detachUsbDevice = 0x06
154};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700155
156constexpr std::size_t operator""_MB(unsigned long long v)
157{
158 return 1024u * 1024u * v;
159}
AppaRao Puli28972062019-11-11 02:04:45 +0530160static constexpr size_t maxFirmwareImageSize = 32_MB;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700161
AppaRao Puli28972062019-11-11 02:04:45 +0530162static bool localDownloadInProgress(void)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700163{
164 struct stat sb;
AppaRao Puli28972062019-11-11 02:04:45 +0530165 if (stat(firmwareBufferFile, &sb) < 0)
166 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700167 return false;
AppaRao Puli28972062019-11-11 02:04:45 +0530168 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700169 return true;
170}
171
AppaRao Puli28972062019-11-11 02:04:45 +0530172class TransferHashCheck
173{
174 public:
175 enum class HashCheck : uint8_t
176 {
177 notRequested = 0,
178 requested,
179 sha2Success,
180 sha2Failed = 0xe2,
181 };
182
183 protected:
James Feistfcd2d3a2020-05-28 10:38:15 -0700184 EVP_MD_CTX* ctx;
AppaRao Puli28972062019-11-11 02:04:45 +0530185 std::vector<uint8_t> expectedHash;
186 enum HashCheck check;
187 bool started;
188
189 public:
190 TransferHashCheck() : check(HashCheck::notRequested), started(false)
James Feistfcd2d3a2020-05-28 10:38:15 -0700191 {}
AppaRao Puli28972062019-11-11 02:04:45 +0530192 ~TransferHashCheck()
193 {
194 if (ctx)
195 {
196 EVP_MD_CTX_destroy(ctx);
197 ctx = NULL;
198 }
199 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700200 void init(const std::vector<uint8_t>& expected)
AppaRao Puli28972062019-11-11 02:04:45 +0530201 {
202 expectedHash = expected;
203 check = HashCheck::requested;
204 ctx = EVP_MD_CTX_create();
205 EVP_DigestInit(ctx, EVP_sha256());
206 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700207 void hash(const std::vector<uint8_t>& data)
AppaRao Puli28972062019-11-11 02:04:45 +0530208 {
209 if (!started)
210 {
211 started = true;
212 }
213 EVP_DigestUpdate(ctx, data.data(), data.size());
214 }
215 void clear()
216 {
217 // if not started, nothing to clear
218 if (started)
219 {
220 if (ctx)
221 {
222 EVP_MD_CTX_destroy(ctx);
223 }
224 if (check != HashCheck::notRequested)
225 {
226 check = HashCheck::requested;
227 }
228 ctx = EVP_MD_CTX_create();
229 EVP_DigestInit(ctx, EVP_sha256());
230 }
231 }
232 enum HashCheck verify()
233 {
234 if (check == HashCheck::requested)
235 {
236 unsigned int len = 0;
237 std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
238 EVP_DigestFinal(ctx, digest.data(), &len);
239 if (digest == expectedHash)
240 {
241 phosphor::logging::log<phosphor::logging::level::INFO>(
242 "Transfer sha2 verify passed.");
243 check = HashCheck::sha2Success;
244 }
245 else
246 {
247 phosphor::logging::log<phosphor::logging::level::ERR>(
248 "Transfer sha2 verify failed.");
249 check = HashCheck::sha2Failed;
250 }
251 }
252 return check;
253 }
254 uint8_t status() const
255 {
256 return static_cast<uint8_t>(check);
257 }
258};
259
260class MappedFile
261{
262 public:
James Feistfcd2d3a2020-05-28 10:38:15 -0700263 MappedFile(const std::string& fname) : addr(nullptr), fsize(0)
AppaRao Puli28972062019-11-11 02:04:45 +0530264 {
265 std::error_code ec;
266 size_t sz = std::filesystem::file_size(fname, ec);
267 int fd = open(fname.c_str(), O_RDONLY);
268 if (!ec || fd < 0)
269 {
270 return;
271 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700272 void* tmp = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
AppaRao Puli28972062019-11-11 02:04:45 +0530273 close(fd);
274 if (tmp == MAP_FAILED)
275 {
276 return;
277 }
278 addr = tmp;
279 fsize = sz;
280 }
281
282 ~MappedFile()
283 {
284 if (addr)
285 {
286 munmap(addr, fsize);
287 }
288 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700289 const uint8_t* data() const
AppaRao Puli28972062019-11-11 02:04:45 +0530290 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700291 return static_cast<const uint8_t*>(addr);
AppaRao Puli28972062019-11-11 02:04:45 +0530292 }
293 size_t size() const
294 {
295 return fsize;
296 }
297
298 private:
299 size_t fsize;
James Feistfcd2d3a2020-05-28 10:38:15 -0700300 void* addr;
AppaRao Puli28972062019-11-11 02:04:45 +0530301};
302
303class FwUpdateStatusCache
Vernon Mauery52ce6622019-05-22 09:19:46 -0700304{
305 public:
306 enum
307 {
AppaRao Puli28972062019-11-11 02:04:45 +0530308 fwStateInit = 0,
309 fwStateIdle,
310 fwStateDownload,
311 fwStateVerify,
312 fwStateProgram,
313 fwStateUpdateSuccess,
314 fwStateError = 0x0f,
315 fwStateAcCycleRequired = 0x83,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700316 };
AppaRao Puli28972062019-11-11 02:04:45 +0530317 uint8_t getState()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700318 {
AppaRao Puli28972062019-11-11 02:04:45 +0530319 if ((fwUpdateState == fwStateIdle || fwUpdateState == fwStateInit) &&
320 localDownloadInProgress())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700321 {
AppaRao Puli28972062019-11-11 02:04:45 +0530322 fwUpdateState = fwStateDownload;
323 progressPercent = 0;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700324 }
AppaRao Puli28972062019-11-11 02:04:45 +0530325 return fwUpdateState;
326 }
327 void resetStatusCache()
328 {
329 unlink(firmwareBufferFile);
330 }
331 void setState(const uint8_t state)
332 {
333 switch (state)
334 {
335 case fwStateInit:
336 case fwStateIdle:
337 case fwStateError:
338 resetStatusCache();
339 break;
340 case fwStateDownload:
341 case fwStateVerify:
342 case fwStateProgram:
343 case fwStateUpdateSuccess:
344 break;
345 default:
346 // Error
347 break;
348 }
349 fwUpdateState = state;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700350 }
351 uint8_t percent()
352 {
AppaRao Puli28972062019-11-11 02:04:45 +0530353 return progressPercent;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700354 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700355 void updateActivationPercent(const std::string& objPath)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700356 {
AppaRao Puli28972062019-11-11 02:04:45 +0530357 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
358 fwUpdateState = fwStateProgram;
359 progressPercent = 0;
360 match = std::make_shared<sdbusplus::bus::match::match>(
361 *busp,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700362 sdbusplus::bus::match::rules::propertiesChanged(
AppaRao Puli28972062019-11-11 02:04:45 +0530363 objPath, "xyz.openbmc_project.Software.ActivationProgress"),
James Feistfcd2d3a2020-05-28 10:38:15 -0700364 [&](sdbusplus::message::message& msg) {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700365 std::map<std::string, ipmi::DbusVariant> props;
AppaRao Puli28972062019-11-11 02:04:45 +0530366 std::vector<std::string> inVal;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700367 std::string iface;
AppaRao Puli28972062019-11-11 02:04:45 +0530368 try
369 {
370 msg.read(iface, props, inVal);
371 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700372 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +0530373 {
374 phosphor::logging::log<phosphor::logging::level::ERR>(
375 "Exception caught in get ActivationProgress");
376 return;
377 }
378
379 auto it = props.find("Progress");
380 if (it != props.end())
381 {
382 progressPercent = std::get<uint8_t>(it->second);
383 if (progressPercent == 100)
384 {
385 fwUpdateState = fwStateUpdateSuccess;
386 }
387 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700388 });
389 }
AppaRao Puli28972062019-11-11 02:04:45 +0530390 uint8_t activationTimerTimeout()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700391 {
AppaRao Puli28972062019-11-11 02:04:45 +0530392 phosphor::logging::log<phosphor::logging::level::INFO>(
393 "activationTimerTimeout: Increase percentage...",
394 phosphor::logging::entry("PERCENT:%d", progressPercent));
395 progressPercent = progressPercent + 5;
jayaprakash Mutyalab8f2bf92020-01-27 23:17:39 +0000396 if (progressPercent > 95)
anil kumar appana31f88872019-08-02 15:16:27 +0000397 {
398 /*changing the state to ready to update firmware utility */
AppaRao Puli28972062019-11-11 02:04:45 +0530399 fwUpdateState = fwStateUpdateSuccess;
anil kumar appana31f88872019-08-02 15:16:27 +0000400 }
AppaRao Puli28972062019-11-11 02:04:45 +0530401 return progressPercent;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700402 }
anil kumar appana31f88872019-08-02 15:16:27 +0000403 /* API for changing state to ERROR */
404 void firmwareUpdateAbortState()
405 {
AppaRao Puli28972062019-11-11 02:04:45 +0530406 unlink(firmwareBufferFile);
anil kumar appana31f88872019-08-02 15:16:27 +0000407 // changing the state to error
AppaRao Puli28972062019-11-11 02:04:45 +0530408 fwUpdateState = fwStateError;
anil kumar appana31f88872019-08-02 15:16:27 +0000409 }
410 void setDeferRestart(bool deferRestart)
411 {
AppaRao Puli28972062019-11-11 02:04:45 +0530412 deferRestartState = deferRestart;
anil kumar appana31f88872019-08-02 15:16:27 +0000413 }
414 void setInhibitDowngrade(bool inhibitDowngrade)
415 {
AppaRao Puli28972062019-11-11 02:04:45 +0530416 inhibitDowngradeState = inhibitDowngrade;
anil kumar appana31f88872019-08-02 15:16:27 +0000417 }
418 bool getDeferRestart()
419 {
AppaRao Puli28972062019-11-11 02:04:45 +0530420 return deferRestartState;
anil kumar appana31f88872019-08-02 15:16:27 +0000421 }
422 bool getInhibitDowngrade()
423 {
AppaRao Puli28972062019-11-11 02:04:45 +0530424 return inhibitDowngradeState;
anil kumar appana31f88872019-08-02 15:16:27 +0000425 }
426
Vernon Mauery52ce6622019-05-22 09:19:46 -0700427 protected:
AppaRao Puli28972062019-11-11 02:04:45 +0530428 std::shared_ptr<sdbusplus::asio::connection> busp;
429 std::shared_ptr<sdbusplus::bus::match::match> match;
430 uint8_t fwUpdateState = 0;
431 uint8_t progressPercent = 0;
432 bool deferRestartState = false;
433 bool inhibitDowngradeState = false;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700434};
435
AppaRao Puli28972062019-11-11 02:04:45 +0530436static FwUpdateStatusCache fwUpdateStatus;
437std::shared_ptr<TransferHashCheck> xferHashCheck;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700438
James Feistfcd2d3a2020-05-28 10:38:15 -0700439static void activateImage(const std::string& objPath)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700440{
AppaRao Puli28972062019-11-11 02:04:45 +0530441 // If flag is false means to reboot
442 if (fwUpdateStatus.getDeferRestart() == false)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700443 {
AppaRao Puli28972062019-11-11 02:04:45 +0530444 phosphor::logging::log<phosphor::logging::level::INFO>(
445 "activating Image: ",
446 phosphor::logging::entry("OBJPATH =%s", objPath.c_str()));
447 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
448 bus->async_method_call(
449 [](const boost::system::error_code ec) {
450 if (ec)
451 {
452 phosphor::logging::log<phosphor::logging::level::ERR>(
453 "async_method_call error: activateImage failed");
454 return;
455 }
456 },
457 "xyz.openbmc_project.Software.BMC.Updater", objPath,
458 "org.freedesktop.DBus.Properties", "Set",
459 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
460 std::variant<std::string>("xyz.openbmc_project.Software.Activation."
461 "RequestedActivations.Active"));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700462 }
AppaRao Puli28972062019-11-11 02:04:45 +0530463 else
464 {
465 phosphor::logging::log<phosphor::logging::level::INFO>(
466 "Firmware image activation is deferred.");
467 }
468 fwUpdateStatus.setState(
469 static_cast<uint8_t>(FwUpdateStatusCache::fwStateUpdateSuccess));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700470}
471
AppaRao Puli09a83142019-11-23 02:46:06 +0530472static bool getFirmwareUpdateMode()
473{
474 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
475 try
476 {
477 auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
478 ipmi::Value state = ipmi::getDbusProperty(
479 *busp, service, bmcStatePath, bmcStateIntf, "CurrentBMCState");
480 std::string bmcState = std::get<std::string>(state);
481 return (bmcState == bmcStateUpdateInProgress);
482 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700483 catch (const std::exception& e)
AppaRao Puli09a83142019-11-23 02:46:06 +0530484 {
485 phosphor::logging::log<phosphor::logging::level::ERR>(
486 "Exception caught while getting BMC state.",
487 phosphor::logging::entry("EXCEPTION=%s", e.what()));
488 throw;
489 }
490}
491
492static void setFirmwareUpdateMode(const bool mode)
493{
494
495 std::string bmcState(bmcStateReady);
496 if (mode)
497 {
498 bmcState = bmcStateUpdateInProgress;
499 }
500
501 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
502 try
503 {
504 auto service = ipmi::getService(*busp, bmcStateIntf, bmcStatePath);
505 ipmi::setDbusProperty(*busp, service, bmcStatePath, bmcStateIntf,
506 "CurrentBMCState", bmcState);
507 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700508 catch (const std::exception& e)
AppaRao Puli09a83142019-11-23 02:46:06 +0530509 {
510 phosphor::logging::log<phosphor::logging::level::ERR>(
511 "Exception caught while setting BMC state.",
512 phosphor::logging::entry("EXCEPTION=%s", e.what()));
513 throw;
514 }
515}
516
AppaRao Pulie2cddf62020-01-31 00:30:08 +0530517/** @brief check if channel IPMB
518 *
519 * This function checks if the command is from IPMB
520 *
521 * @param[in] ctx - context of current session.
522 * @returns true if the medium is IPMB else return true.
523 **/
James Feistfcd2d3a2020-05-28 10:38:15 -0700524ipmi::Cc checkIPMBChannel(const ipmi::Context::ptr& ctx, bool& isIPMBChannel)
AppaRao Pulie2cddf62020-01-31 00:30:08 +0530525{
526 ipmi::ChannelInfo chInfo;
527
528 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
529 {
530 phosphor::logging::log<phosphor::logging::level::ERR>(
531 "Failed to get Channel Info",
532 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
533 return ipmi::ccUnspecifiedError;
534 }
535
536 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
537 ipmi::EChannelMediumType::ipmb)
538 {
539 isIPMBChannel = true;
540 }
541 return ipmi::ccSuccess;
542}
543
AppaRao Puli28972062019-11-11 02:04:45 +0530544static void postTransferCompleteHandler(
James Feistfcd2d3a2020-05-28 10:38:15 -0700545 std::unique_ptr<sdbusplus::bus::match::match>& fwUpdateMatchSignal)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700546{
547 // Setup timer for watching signal
548 static phosphor::Timer timer(
AppaRao Puli28972062019-11-11 02:04:45 +0530549 [&fwUpdateMatchSignal]() { fwUpdateMatchSignal = nullptr; });
Vernon Mauery52ce6622019-05-22 09:19:46 -0700550
AppaRao Puli28972062019-11-11 02:04:45 +0530551 static phosphor::Timer activationStatusTimer([]() {
jayaprakash Mutyalab8f2bf92020-01-27 23:17:39 +0000552 if (fwUpdateStatus.activationTimerTimeout() > 95)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700553 {
AppaRao Puli28972062019-11-11 02:04:45 +0530554 activationStatusTimer.stop();
555 fwUpdateStatus.setState(
556 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700557 }
558 });
559
560 timer.start(std::chrono::microseconds(5000000), false);
561
562 // callback function for capturing signal
James Feistfcd2d3a2020-05-28 10:38:15 -0700563 auto callback = [&](sdbusplus::message::message& m) {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700564 bool flag = false;
565
566 std::vector<std::pair<
567 std::string,
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700568 std::vector<std::pair<std::string, std::variant<std::string>>>>>
AppaRao Puli28972062019-11-11 02:04:45 +0530569 intfPropsPair;
570 sdbusplus::message::object_path objPath;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700571
572 try
573 {
AppaRao Puli28972062019-11-11 02:04:45 +0530574 m.read(objPath, intfPropsPair); // Read in the object path
575 // that was just created
Vernon Mauery52ce6622019-05-22 09:19:46 -0700576 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700577 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700578 {
AppaRao Puli28972062019-11-11 02:04:45 +0530579 phosphor::logging::log<phosphor::logging::level::ERR>(
580 "Exception caught in reading created object path.");
581 return;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700582 }
583 // constructing response message
AppaRao Puli28972062019-11-11 02:04:45 +0530584 phosphor::logging::log<phosphor::logging::level::INFO>(
585 "New Interface Added.",
586 phosphor::logging::entry("OBJPATH=%s", objPath.str.c_str()));
James Feistfcd2d3a2020-05-28 10:38:15 -0700587 for (auto& interface : intfPropsPair)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700588 {
Vernon Mauery52ce6622019-05-22 09:19:46 -0700589 if (interface.first == "xyz.openbmc_project.Software.Activation")
590 {
AppaRao Puli28972062019-11-11 02:04:45 +0530591 // There are chances of getting two signals for
592 // InterfacesAdded. So cross check and discrad second instance.
593 if (fwUpdateMatchSignal == nullptr)
594 {
595 return;
596 }
597 // Found our interface, disable callbacks
598 fwUpdateMatchSignal = nullptr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700599
AppaRao Puli28972062019-11-11 02:04:45 +0530600 phosphor::logging::log<phosphor::logging::level::INFO>(
601 "Start activationStatusTimer for status.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700602 try
603 {
604 timer.stop();
AppaRao Puli28972062019-11-11 02:04:45 +0530605 activationStatusTimer.start(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700606 std::chrono::microseconds(3000000), true);
607 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700608 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700609 {
AppaRao Puli28972062019-11-11 02:04:45 +0530610 phosphor::logging::log<phosphor::logging::level::ERR>(
611 "Exception caught in start activationStatusTimer.",
612 phosphor::logging::entry("ERROR=%s", e.what()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700613 }
614
AppaRao Puli28972062019-11-11 02:04:45 +0530615 fwUpdateStatus.updateActivationPercent(objPath.str);
616 activateImage(objPath.str);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700617 }
618 }
619 };
620
621 // Adding matcher
AppaRao Puli28972062019-11-11 02:04:45 +0530622 fwUpdateMatchSignal = std::make_unique<sdbusplus::bus::match::match>(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700623 *getSdBus(),
Vernon Mauery52ce6622019-05-22 09:19:46 -0700624 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
625 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
626 callback);
627}
James Feistfcd2d3a2020-05-28 10:38:15 -0700628static bool startFirmwareUpdate(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700629{
AppaRao Puli28972062019-11-11 02:04:45 +0530630 // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
631 // the code gets to this point, the file should be transferred start the
632 // request (creating a new file in /tmp/images causes the update manager to
633 // check if it is ready for activation)
634 static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatchSignal;
635 postTransferCompleteHandler(fwUpdateMatchSignal);
636 std::filesystem::rename(
637 uri, "/tmp/images/" +
638 boost::uuids::to_string(boost::uuids::random_generator()()));
639 return true;
640}
Vernon Mauery52ce6622019-05-22 09:19:46 -0700641
James Feistfcd2d3a2020-05-28 10:38:15 -0700642static int transferImageFromFile(const std::string& uri, bool move = true)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700643{
644 std::error_code ec;
AppaRao Puli28972062019-11-11 02:04:45 +0530645 phosphor::logging::log<phosphor::logging::level::INFO>(
646 "Transfer Image From File.",
647 phosphor::logging::entry("URI=%s", uri.c_str()));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700648 if (move)
649 {
AppaRao Puli28972062019-11-11 02:04:45 +0530650 std::filesystem::rename(uri, firmwareBufferFile, ec);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700651 }
652 else
653 {
AppaRao Puli28972062019-11-11 02:04:45 +0530654 std::filesystem::copy(uri, firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -0700655 std::filesystem::copy_options::overwrite_existing,
656 ec);
657 }
AppaRao Puli28972062019-11-11 02:04:45 +0530658 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700659 {
660 MappedFile mappedfw(uri);
AppaRao Puli28972062019-11-11 02:04:45 +0530661 xferHashCheck->hash(
Vernon Mauery52ce6622019-05-22 09:19:46 -0700662 {mappedfw.data(), mappedfw.data() + mappedfw.size()});
663 }
664 if (ec.value())
665 {
AppaRao Puli28972062019-11-11 02:04:45 +0530666 phosphor::logging::log<phosphor::logging::level::ERR>(
667 "Image copy failed.");
Vernon Mauery52ce6622019-05-22 09:19:46 -0700668 }
669 return ec.value();
670}
671
672template <typename... ArgTypes>
James Feistfcd2d3a2020-05-28 10:38:15 -0700673static int executeCmd(const char* path, ArgTypes&&... tArgs)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700674{
James Feistfcd2d3a2020-05-28 10:38:15 -0700675 boost::process::child execProg(path, const_cast<char*>(tArgs)...);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700676 execProg.wait();
677 return execProg.exit_code();
678}
679
James Feistfcd2d3a2020-05-28 10:38:15 -0700680static int transferImageFromUsb(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700681{
682 int ret, sysret;
683 char fwpath[fwPathMaxLength];
AppaRao Puli28972062019-11-11 02:04:45 +0530684 phosphor::logging::log<phosphor::logging::level::INFO>(
685 "Transfer Image From USB.",
686 phosphor::logging::entry("URI=%s", uri.c_str()));
687 ret = executeCmd(usbCtrlPath, "mount", fwUpdateUsbVolImage,
688 fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700689 if (ret)
690 {
691 return ret;
692 }
693
AppaRao Puli28972062019-11-11 02:04:45 +0530694 std::string usb_path = std::string(fwUpdateMountPoint) + "/" + uri;
695 ret = transferImageFromFile(usb_path, false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700696
AppaRao Puli28972062019-11-11 02:04:45 +0530697 executeCmd(usbCtrlPath, "cleanup", fwUpdateUsbVolImage, fwUpdateMountPoint);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700698 return ret;
699}
700
James Feistfcd2d3a2020-05-28 10:38:15 -0700701static bool transferFirmwareFromUri(const std::string& uri)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700702{
AppaRao Puli28972062019-11-11 02:04:45 +0530703 static constexpr char fwUriFile[] = "file://";
704 static constexpr char fwUriUsb[] = "usb://";
705 phosphor::logging::log<phosphor::logging::level::INFO>(
706 "Transfer Image From URI.",
707 phosphor::logging::entry("URI=%s", uri.c_str()));
708 if (boost::algorithm::starts_with(uri, fwUriFile))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700709 {
AppaRao Puli28972062019-11-11 02:04:45 +0530710 std::string fname = uri.substr(sizeof(fwUriFile) - 1);
711 if (fname != firmwareBufferFile)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700712 {
AppaRao Puli28972062019-11-11 02:04:45 +0530713 return 0 == transferImageFromFile(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700714 }
715 return true;
716 }
AppaRao Puli28972062019-11-11 02:04:45 +0530717 if (boost::algorithm::starts_with(uri, fwUriUsb))
Vernon Mauery52ce6622019-05-22 09:19:46 -0700718 {
AppaRao Puli28972062019-11-11 02:04:45 +0530719 std::string fname = uri.substr(sizeof(fwUriUsb) - 1);
720 return 0 == transferImageFromUsb(fname);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700721 }
722 return false;
723}
724
725/* Get USB-mass-storage device status: inserted => true, ejected => false */
AppaRao Puli28972062019-11-11 02:04:45 +0530726static bool getUsbStatus()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700727{
AppaRao Puli28972062019-11-11 02:04:45 +0530728 std::filesystem::path usbDevPath =
729 std::filesystem::path("/sys/kernel/config/usb_gadget") /
730 fwUpdateUSBDevName;
731 return (std::filesystem::exists(usbDevPath) ? true : false);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700732}
733
734/* Insert the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530735static int attachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700736{
AppaRao Puli28972062019-11-11 02:04:45 +0530737 if (getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700738 {
739 return 1;
740 }
AppaRao Puli28972062019-11-11 02:04:45 +0530741 int ret = executeCmd(usbCtrlPath, "setup", fwUpdateUsbVolImage,
742 std::to_string(maxFirmwareImageSize / 1_MB).c_str());
Vernon Mauery52ce6622019-05-22 09:19:46 -0700743 if (!ret)
744 {
AppaRao Puli28972062019-11-11 02:04:45 +0530745 ret = executeCmd(usbCtrlPath, "insert", fwUpdateUSBDevName,
746 fwUpdateUsbVolImage);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700747 }
748 return ret;
749}
750
751/* Eject the USB-mass-storage device status: success => 0, failure => non-0 */
AppaRao Puli28972062019-11-11 02:04:45 +0530752static int detachUsbDevice()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700753{
AppaRao Puli28972062019-11-11 02:04:45 +0530754 if (!getUsbStatus())
Vernon Mauery52ce6622019-05-22 09:19:46 -0700755 {
756 return 1;
757 }
AppaRao Puli28972062019-11-11 02:04:45 +0530758 return executeCmd(usbCtrlPath, "eject", fwUpdateUSBDevName);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700759}
AppaRao Puli28972062019-11-11 02:04:45 +0530760static uint8_t getActiveBootImage(ipmi::Context::ptr ctx)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700761{
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800762 constexpr uint8_t undefinedImage = 0x00;
AppaRao Puli28972062019-11-11 02:04:45 +0530763 constexpr uint8_t primaryImage = 0x01;
764 constexpr uint8_t secondaryImage = 0x02;
James Feistfcd2d3a2020-05-28 10:38:15 -0700765 constexpr const char* secondaryFitImageStartAddr = "22480000";
AppaRao Puli28972062019-11-11 02:04:45 +0530766
767 uint8_t bootImage = primaryImage;
768 boost::system::error_code ec;
769 std::string value = ctx->bus->yield_method_call<std::string>(
770 ctx->yield, ec, "xyz.openbmc_project.U_Boot.Environment.Manager",
771 "/xyz/openbmc_project/u_boot/environment/mgr",
772 "xyz.openbmc_project.U_Boot.Environment.Manager", "Read", "bootcmd");
773 if (ec)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700774 {
AppaRao Puli28972062019-11-11 02:04:45 +0530775 phosphor::logging::log<phosphor::logging::level::ERR>(
776 "Failed to read the bootcmd value");
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800777 /* don't fail, just give back undefined until it is ready */
778 bootImage = undefinedImage;
AppaRao Puli28972062019-11-11 02:04:45 +0530779 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700780
AppaRao Puli28972062019-11-11 02:04:45 +0530781 /* cheking for secondary FitImage Address 22480000 */
Terry S. Duncane319ecf2020-02-10 15:59:55 -0800782 else if (value.find(secondaryFitImageStartAddr) != std::string::npos)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700783 {
AppaRao Puli28972062019-11-11 02:04:45 +0530784 bootImage = secondaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700785 }
786 else
787 {
AppaRao Puli28972062019-11-11 02:04:45 +0530788 bootImage = primaryImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700789 }
790
AppaRao Puli28972062019-11-11 02:04:45 +0530791 return bootImage;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700792}
793
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530794#ifdef INTEL_PFR_ENABLED
795using fwVersionInfoType = std::tuple<uint8_t, // ID Tag
796 uint8_t, // Major Version Number
797 uint8_t, // Minor Version Number
798 uint32_t, // Build Number
799 uint32_t, // Build Timestamp
800 uint32_t>; // Update Timestamp
801ipmi::RspType<uint8_t, std::vector<fwVersionInfoType>> ipmiGetFwVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700802{
Vernon Mauery52ce6622019-05-22 09:19:46 -0700803 // Byte 1 - Count (N) Number of devices data is being returned for.
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530804 // Bytes 2:16 - Device firmare information(fwVersionInfoType)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700805 // Bytes - 17:(15xN) - Repeat of 2 through 16
806
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530807 std::vector<fwVersionInfoType> fwVerInfoList;
808 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
James Feistfcd2d3a2020-05-28 10:38:15 -0700809 for (const auto& fwDev : fwVersionIdMap)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700810 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530811 std::string verStr;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700812 try
813 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530814 auto service = ipmi::getService(*busp, versionIntf, fwDev.second);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700815
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530816 ipmi::Value result = ipmi::getDbusProperty(
817 *busp, service, fwDev.second, versionIntf, "Version");
818 verStr = std::get<std::string>(result);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700819 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700820 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700821 {
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530822 phosphor::logging::log<phosphor::logging::level::INFO>(
823 "Failed to fetch Version property",
824 phosphor::logging::entry("ERROR=%s", e.what()),
825 phosphor::logging::entry("PATH=%s", fwDev.second),
826 phosphor::logging::entry("INTERFACE=%s", versionIntf));
827 continue;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700828 }
829
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530830 if (verStr.empty())
831 {
832 phosphor::logging::log<phosphor::logging::level::INFO>(
833 "Version is empty.",
834 phosphor::logging::entry("PATH=%s", fwDev.second),
835 phosphor::logging::entry("INTERFACE=%s", versionIntf));
836 continue;
837 }
838
839 // BMC Version format: <major>.<minor>-<build bum>-<build hash>
840 std::vector<std::string> splitVer;
841 boost::split(splitVer, verStr, boost::is_any_of(".-"));
842 if (splitVer.size() < 3)
843 {
844 phosphor::logging::log<phosphor::logging::level::INFO>(
845 "Invalid Version format.",
846 phosphor::logging::entry("Version=%s", verStr.c_str()),
847 phosphor::logging::entry("PATH=%s", fwDev.second));
848 continue;
849 }
850
851 uint8_t majorNum = 0;
852 uint8_t minorNum = 0;
853 uint32_t buildNum = 0;
854 try
855 {
856 majorNum = std::stoul(splitVer[0], nullptr, 16);
857 minorNum = std::stoul(splitVer[1], nullptr, 16);
858 buildNum = std::stoul(splitVer[2], nullptr, 16);
859 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700860 catch (const std::exception& e)
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530861 {
862 phosphor::logging::log<phosphor::logging::level::INFO>(
863 "Failed to convert stoul.",
864 phosphor::logging::entry("ERROR=%s", e.what()));
865 continue;
866 }
867
868 // Build Timestamp - Not supported.
869 // Update Timestamp - TODO: Need to check with CPLD team.
870 fwVerInfoList.emplace_back(
871 fwVersionInfoType(static_cast<uint8_t>(fwDev.first), majorNum,
872 minorNum, buildNum, 0, 0));
Vernon Mauery52ce6622019-05-22 09:19:46 -0700873 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700874
AppaRao Puli37fde6b2019-10-25 16:37:50 +0530875 return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700876}
AppaRao Puli28972062019-11-11 02:04:45 +0530877using fwSecurityVersionInfoType = std::tuple<uint8_t, // ID Tag
878 uint8_t, // BKC Version
879 uint8_t>; // SVN Version
880ipmi::RspType<uint8_t, std::vector<fwSecurityVersionInfoType>>
881 ipmiGetFwSecurityVersionInfo()
Vernon Mauery52ce6622019-05-22 09:19:46 -0700882{
AppaRao Puli28972062019-11-11 02:04:45 +0530883 // TODO: Need to add support.
884 return ipmi::responseInvalidCommand();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700885}
886
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530887ipmi::RspType<std::array<uint8_t, certKeyLen>,
888 std::optional<std::array<uint8_t, cskSignatureLen>>>
James Feistfcd2d3a2020-05-28 10:38:15 -0700889 ipmiGetFwRootCertData(const ipmi::Context::ptr& ctx, uint8_t certId)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700890{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +0530891 bool isIPMBChannel = false;
892
893 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
894 {
895 return ipmi::responseUnspecifiedError();
896 }
897 if (isIPMBChannel)
898 {
899 phosphor::logging::log<phosphor::logging::level::INFO>(
900 "Command not supported. Failed to get root certificate data.");
901 return ipmi::responseCommandNotAvailable();
902 }
903
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530904 size_t certKeyOffset = 0;
905 size_t cskSigOffset = 0;
906 std::string mtdDev;
Vernon Mauery52ce6622019-05-22 09:19:46 -0700907
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530908 switch (static_cast<FwGetRootCertDataTag>(certId))
909 {
910 case FwGetRootCertDataTag::activeRootKey:
911 {
912 mtdDev = bmcActivePfmMTDDev;
913 certKeyOffset = rootkeyOffsetInPfm;
914 break;
915 }
916 case FwGetRootCertDataTag::recoveryRootKey:
917 {
918 mtdDev = bmcRecoveryImgMTDDev;
919 certKeyOffset = pfmBaseOffsetInImage + rootkeyOffsetInPfm;
920 break;
921 }
922 case FwGetRootCertDataTag::activeCSK:
923 {
924 mtdDev = bmcActivePfmMTDDev;
925 certKeyOffset = cskKeyOffsetInPfm;
926 cskSigOffset = cskSignatureOffsetInPfm;
927 break;
928 }
929 case FwGetRootCertDataTag::recoveryCSK:
930 {
931 mtdDev = bmcRecoveryImgMTDDev;
932 certKeyOffset = pfmBaseOffsetInImage + cskKeyOffsetInPfm;
933 cskSigOffset = pfmBaseOffsetInImage + cskSignatureOffsetInPfm;
934 break;
935 }
936 default:
937 {
938 return ipmi::responseInvalidFieldRequest();
939 }
940 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700941
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530942 std::array<uint8_t, certKeyLen> certKey = {0};
Vernon Mauery52ce6622019-05-22 09:19:46 -0700943
Vernon Mauery52ce6622019-05-22 09:19:46 -0700944 try
945 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530946 SPIDev spiDev(mtdDev);
947 spiDev.spiReadData(certKeyOffset, certKeyLen, certKey.data());
948
949 if (cskSigOffset)
950 {
951 std::array<uint8_t, cskSignatureLen> cskSignature = {0};
952 spiDev.spiReadData(cskSigOffset, cskSignatureLen,
953 cskSignature.data());
954 return ipmi::responseSuccess(certKey, cskSignature);
955 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700956 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700957 catch (const std::exception& e)
Vernon Mauery52ce6622019-05-22 09:19:46 -0700958 {
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530959 phosphor::logging::log<phosphor::logging::level::ERR>(
960 "Exception caught in ipmiGetFwRootCertData",
961 phosphor::logging::entry("MSG=%s", e.what()));
962 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -0700963 }
Vernon Mauery52ce6622019-05-22 09:19:46 -0700964
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +0530965 return ipmi::responseSuccess(certKey, std::nullopt);
Vernon Mauery52ce6622019-05-22 09:19:46 -0700966}
AppaRao Puli28972062019-11-11 02:04:45 +0530967#endif // INTEL_PFR_ENABLED
968
969static constexpr uint8_t channelListSize = 3;
970/** @brief implements Maximum Firmware Transfer size command
971 * @parameter
972 * - none
973 * @returns IPMI completion code plus response data
974 * - count - channel count
975 * - channelList - channel list information
976 */
977ipmi::RspType<uint8_t, // channel count
978 std::array<std::tuple<uint8_t, uint32_t>,
979 channelListSize> // Channel List
980 >
981 ipmiFirmwareMaxTransferSize()
982{
983 constexpr size_t kcsMaxBufSize = 128;
984 constexpr size_t rmcpPlusMaxBufSize = 50 * 1024;
AppaRao Puli28972062019-11-11 02:04:45 +0530985 // Byte 1 - Count (N) Number of devices data is being returned for.
986 // Byte 2 - ID Tag 00 – reserved 01 – kcs 02 – rmcp+, 03 - ipmb
987 // Byte 3-6 - transfer size (little endian)
988 // Bytes - 7:(5xN) - Repeat of 2 through 6
989 constexpr std::array<std::tuple<uint8_t, uint32_t>, channelListSize>
990 channelList = {
991 {{static_cast<uint8_t>(ChannelIdTag::kcs), kcsMaxBufSize},
AppaRao Puli28972062019-11-11 02:04:45 +0530992 {static_cast<uint8_t>(ChannelIdTag::rmcpPlus),
993 rmcpPlusMaxBufSize}}};
994
995 return ipmi::responseSuccess(channelListSize, channelList);
996}
997
998ipmi::RspType<uint8_t, uint8_t>
999 ipmiGetBmcExecutionContext(ipmi::Context::ptr ctx)
1000{
1001 // Byte 1 - Current execution context
1002 // 0x10 - Linux OS, 0x11 - Bootloader, Forced-firmware updat mode
1003 // Byte 2 - Partition pointer
1004 // 0x01 - primary, 0x02 - secondary
1005 uint8_t partitionPtr = getActiveBootImage(ctx);
1006
1007 return ipmi::responseSuccess(
1008 static_cast<uint8_t>(BmcExecutionContext::linuxOs), partitionPtr);
1009}
AppaRao Puli28972062019-11-11 02:04:45 +05301010/** @brief Get Firmware Update Random Number
1011 *
1012 * This function generate the random number used for
1013 * setting the firmware update mode as authentication key.
1014 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301015 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301016 * @returns IPMI completion code along with
1017 * - random number
1018 **/
1019ipmi::RspType<std::array<uint8_t, fwRandomNumLength>>
James Feistfcd2d3a2020-05-28 10:38:15 -07001020 ipmiGetFwUpdateRandomNumber(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301021{
1022 phosphor::logging::log<phosphor::logging::level::INFO>(
1023 "Generate FW update random number");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301024 bool isIPMBChannel = false;
1025
1026 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1027 {
1028 return ipmi::responseUnspecifiedError();
1029 }
1030 if (isIPMBChannel)
1031 {
1032 phosphor::logging::log<phosphor::logging::level::INFO>(
1033 "Channel not supported. Failed to fetch FW update random number");
1034 return ipmi::responseCommandNotAvailable();
1035 }
AppaRao Puli28972062019-11-11 02:04:45 +05301036 std::random_device rd;
1037 std::default_random_engine gen(rd());
1038 std::uniform_int_distribution<> dist{0, 255};
1039
1040 fwRandomNumGenTs = std::chrono::steady_clock::now();
1041
1042 for (int i = 0; i < fwRandomNumLength; i++)
1043 {
1044 fwRandomNum[i] = dist(gen);
1045 }
1046
1047 return ipmi::responseSuccess(fwRandomNum);
1048}
1049
1050/** @brief Set Firmware Update Mode
1051 *
1052 * This function sets BMC into firmware update mode
1053 * after validating Random number obtained from the Get
1054 * Firmware Update Random Number command
1055 *
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301056 * @param[in] ctx - context of current session
1057 * @parameter randNum - Random number(token)
1058 * @returns IPMI completion code
AppaRao Puli28972062019-11-11 02:04:45 +05301059 **/
1060ipmi::RspType<>
James Feistfcd2d3a2020-05-28 10:38:15 -07001061 ipmiSetFirmwareUpdateMode(const ipmi::Context::ptr& ctx,
1062 std::array<uint8_t, fwRandomNumLength>& randNum)
AppaRao Puli28972062019-11-11 02:04:45 +05301063{
1064 phosphor::logging::log<phosphor::logging::level::INFO>(
1065 "Start FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301066
1067 bool isIPMBChannel = false;
1068
1069 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1070 {
1071 return ipmi::responseUnspecifiedError();
1072 }
1073 if (isIPMBChannel)
1074 {
1075 phosphor::logging::log<phosphor::logging::level::INFO>(
1076 "Channel not supported. Failed to set FW update mode");
1077 return ipmi::responseCommandNotAvailable();
1078 }
AppaRao Puli28972062019-11-11 02:04:45 +05301079 /* Firmware Update Random number is valid for 30 seconds only */
1080 auto timeElapsed = (std::chrono::steady_clock::now() - fwRandomNumGenTs);
1081 if (std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed)
1082 .count() > std::chrono::duration_cast<std::chrono::microseconds>(
1083 fwRandomNumExpirySeconds)
1084 .count())
1085 {
1086 phosphor::logging::log<phosphor::logging::level::INFO>(
1087 "Firmware update random number expired.");
1088 return ipmi::responseInvalidFieldRequest();
1089 }
1090
1091 /* Validate random number */
1092 for (int i = 0; i < fwRandomNumLength; i++)
1093 {
1094 if (fwRandomNum[i] != randNum[i])
1095 {
1096 phosphor::logging::log<phosphor::logging::level::INFO>(
1097 "Invalid random number specified.");
1098 return ipmi::responseInvalidFieldRequest();
1099 }
1100 }
1101
1102 try
1103 {
1104 if (getFirmwareUpdateMode())
1105 {
1106 phosphor::logging::log<phosphor::logging::level::INFO>(
1107 "Already firmware update is in progress.");
1108 return ipmi::responseBusy();
1109 }
1110 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001111 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301112 {
1113 return ipmi::responseUnspecifiedError();
1114 }
1115
1116 // FIXME? c++ doesn't off an option for exclusive file creation
James Feistfcd2d3a2020-05-28 10:38:15 -07001117 FILE* fp = fopen(firmwareBufferFile, "wx");
AppaRao Puli28972062019-11-11 02:04:45 +05301118 if (!fp)
1119 {
1120 phosphor::logging::log<phosphor::logging::level::INFO>(
1121 "Unable to open file.");
1122 return ipmi::responseUnspecifiedError();
1123 }
1124 fclose(fp);
1125
1126 try
1127 {
1128 setFirmwareUpdateMode(true);
1129 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001130 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301131 {
1132 unlink(firmwareBufferFile);
1133 return ipmi::responseUnspecifiedError();
1134 }
1135
1136 return ipmi::responseSuccess();
1137}
1138
1139/** @brief implements exit firmware update mode command
1140 * @param None
1141 *
1142 * @returns IPMI completion code
1143 */
James Feistfcd2d3a2020-05-28 10:38:15 -07001144ipmi::RspType<> ipmiExitFirmwareUpdateMode(const ipmi::Context::ptr& ctx)
AppaRao Puli28972062019-11-11 02:04:45 +05301145{
1146 phosphor::logging::log<phosphor::logging::level::INFO>(
1147 "Exit FW update mode");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301148 bool isIPMBChannel = false;
1149
1150 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1151 {
1152 return ipmi::responseUnspecifiedError();
1153 }
1154 if (isIPMBChannel)
1155 {
1156 phosphor::logging::log<phosphor::logging::level::INFO>(
1157 "Command not supported. Failed to exit firmware update mode");
1158 return ipmi::responseCommandNotAvailable();
1159 }
1160
AppaRao Puli28972062019-11-11 02:04:45 +05301161 switch (fwUpdateStatus.getState())
1162 {
1163 case FwUpdateStatusCache::fwStateInit:
1164 case FwUpdateStatusCache::fwStateIdle:
1165 return ipmi::responseInvalidFieldRequest();
1166 break;
1167 case FwUpdateStatusCache::fwStateDownload:
1168 case FwUpdateStatusCache::fwStateVerify:
1169 break;
1170 case FwUpdateStatusCache::fwStateProgram:
1171 break;
1172 case FwUpdateStatusCache::fwStateUpdateSuccess:
1173 case FwUpdateStatusCache::fwStateError:
1174 break;
1175 case FwUpdateStatusCache::fwStateAcCycleRequired:
1176 return ipmi::responseInvalidFieldRequest();
1177 break;
1178 }
1179 fwUpdateStatus.firmwareUpdateAbortState();
1180
1181 try
1182 {
1183 setFirmwareUpdateMode(false);
1184 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001185 catch (const std::exception& e)
AppaRao Puli28972062019-11-11 02:04:45 +05301186 {
1187 return ipmi::responseUnspecifiedError();
1188 }
1189
1190 return ipmi::responseSuccess();
1191}
1192
1193/** @brief implements Get/Set Firmware Update Control
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301194 * @param[in] ctx - context of current session
AppaRao Puli28972062019-11-11 02:04:45 +05301195 * @parameter
1196 * - Byte 1: Control Byte
1197 * - Byte 2: Firmware filename length (Optional)
1198 * - Byte 3:N: Firmware filename data (Optional)
1199 * @returns IPMI completion code plus response data
1200 * - Byte 2: Current control status
1201 **/
1202ipmi::RspType<bool, bool, bool, bool, uint4_t>
James Feistfcd2d3a2020-05-28 10:38:15 -07001203 ipmiGetSetFirmwareUpdateControl(const ipmi::Context::ptr& ctx,
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301204 const uint8_t controlReq,
James Feistfcd2d3a2020-05-28 10:38:15 -07001205 const std::optional<std::string>& fileName)
AppaRao Puli28972062019-11-11 02:04:45 +05301206{
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301207 bool isIPMBChannel = false;
1208
1209 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1210 {
1211 return ipmi::responseUnspecifiedError();
1212 }
1213 if (isIPMBChannel)
1214 {
1215 phosphor::logging::log<phosphor::logging::level::INFO>(
1216 "Channel not supported. Failed to get or set FW update control");
1217 return ipmi::responseCommandNotAvailable();
1218 }
1219
AppaRao Puli28972062019-11-11 02:04:45 +05301220 static std::string fwXferUriPath;
1221 static bool imageTransferStarted = false;
1222 static bool imageTransferCompleted = false;
1223 static bool imageTransferAborted = false;
1224
1225 if ((controlReq !=
1226 static_cast<uint8_t>(FwUpdateCtrlReq::setFirmwareFilename)) &&
1227 (fileName))
1228 {
1229 phosphor::logging::log<phosphor::logging::level::ERR>(
1230 "Invalid request field (Filename).");
1231 return ipmi::responseInvalidFieldRequest();
1232 }
1233
1234 static bool usbAttached = getUsbStatus();
1235
1236 switch (static_cast<FwUpdateCtrlReq>(controlReq))
1237 {
1238 case FwUpdateCtrlReq::getCurrentControlStatus:
1239 phosphor::logging::log<phosphor::logging::level::INFO>(
1240 "ipmiGetSetFirmwareUpdateControl: Get status");
1241 break;
1242 case FwUpdateCtrlReq::imageTransferStart:
1243 {
1244 phosphor::logging::log<phosphor::logging::level::INFO>(
1245 "ipmiGetSetFirmwareUpdateControl: Set transfer start");
1246 imageTransferStarted = true;
1247 // reset buffer to empty (truncate file)
1248 std::ofstream out(firmwareBufferFile,
1249 std::ofstream::binary | std::ofstream::trunc);
1250 fwXferUriPath = std::string("file://") + firmwareBufferFile;
1251 if (xferHashCheck)
1252 {
1253 xferHashCheck->clear();
1254 }
1255 // Setting state to download
1256 fwUpdateStatus.setState(
1257 static_cast<uint8_t>(FwUpdateStatusCache::fwStateDownload));
1258#ifdef INTEL_PFR_ENABLED
1259 imgLength = 0;
1260 imgType = 0;
1261 block0Mapped = false;
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301262#endif
AppaRao Puli28972062019-11-11 02:04:45 +05301263 }
1264 break;
1265 case FwUpdateCtrlReq::imageTransferComplete:
1266 {
1267 phosphor::logging::log<phosphor::logging::level::INFO>(
1268 "ipmiGetSetFirmwareUpdateControl: Set transfer complete.");
1269 if (usbAttached)
1270 {
1271 phosphor::logging::log<phosphor::logging::level::ERR>(
1272 "USB should be detached to perform this operation.");
1273 return ipmi::responseNotSupportedInPresentState();
1274 }
1275 // finish transfer based on URI
1276 if (!transferFirmwareFromUri(fwXferUriPath))
1277 {
1278 phosphor::logging::log<phosphor::logging::level::ERR>(
1279 "transferFirmwareFromUri failed.");
1280 return ipmi::responseUnspecifiedError();
1281 }
1282 // transfer complete
1283 if (xferHashCheck)
1284 {
1285 if (TransferHashCheck::HashCheck::sha2Success !=
1286 xferHashCheck->verify())
1287 {
1288 phosphor::logging::log<phosphor::logging::level::ERR>(
1289 "xferHashCheck failed.");
1290 return ipmi::responseUnspecifiedError();
1291 }
1292 }
1293 // Set state to verify and start the update
1294 fwUpdateStatus.setState(
1295 static_cast<uint8_t>(FwUpdateStatusCache::fwStateVerify));
1296 // start the request
1297 if (!startFirmwareUpdate(firmwareBufferFile))
1298 {
1299 phosphor::logging::log<phosphor::logging::level::ERR>(
1300 "startFirmwareUpdate failed.");
1301 return ipmi::responseUnspecifiedError();
1302 }
1303 imageTransferCompleted = true;
1304 }
1305 break;
1306 case FwUpdateCtrlReq::imageTransferAbort:
1307 phosphor::logging::log<phosphor::logging::level::INFO>(
1308 "ipmiGetSetFirmwareUpdateControl: Set transfer abort.");
1309 if (usbAttached)
1310 {
1311 if (detachUsbDevice())
1312 {
1313 phosphor::logging::log<phosphor::logging::level::ERR>(
1314 "Detach USB device failed.");
1315 return ipmi::responseUsbAttachOrDetachFailed();
1316 }
1317 usbAttached = false;
1318 }
1319 // During abort request reset the state to Init by cleaning update
1320 // file.
1321 fwUpdateStatus.firmwareUpdateAbortState();
1322 imageTransferAborted = true;
1323 break;
1324 case FwUpdateCtrlReq::setFirmwareFilename:
1325 phosphor::logging::log<phosphor::logging::level::INFO>(
1326 "ipmiGetSetFirmwareUpdateControl: Set filename.");
1327 if (!fileName || ((*fileName).length() == 0))
1328 {
1329 phosphor::logging::log<phosphor::logging::level::ERR>(
1330 "Invalid Filename specified.");
1331 return ipmi::responseInvalidFieldRequest();
1332 }
1333
1334 fwXferUriPath = *fileName;
1335 break;
1336 case FwUpdateCtrlReq::attachUsbDevice:
1337 phosphor::logging::log<phosphor::logging::level::INFO>(
1338 "ipmiGetSetFirmwareUpdateControl: Attach USB device.");
1339 if (usbAttached)
1340 {
1341 phosphor::logging::log<phosphor::logging::level::ERR>(
1342 "USB device is already attached.");
1343 return ipmi::responseInvalidFieldRequest();
1344 }
1345 if (attachUsbDevice())
1346 {
1347 phosphor::logging::log<phosphor::logging::level::ERR>(
1348 "Attach USB device failed.");
1349 return ipmi::responseUsbAttachOrDetachFailed();
1350 }
1351 usbAttached = true;
1352 break;
1353 case FwUpdateCtrlReq::detachUsbDevice:
1354 phosphor::logging::log<phosphor::logging::level::INFO>(
1355 "ipmiGetSetFirmwareUpdateControl: Detach USB device.");
1356 if (!usbAttached)
1357 {
1358 phosphor::logging::log<phosphor::logging::level::ERR>(
1359 "USB device is not attached.");
1360 return ipmi::responseInvalidFieldRequest();
1361 }
1362 if (detachUsbDevice())
1363 {
1364 phosphor::logging::log<phosphor::logging::level::ERR>(
1365 "Detach USB device failed.");
1366 return ipmi::responseUsbAttachOrDetachFailed();
1367 }
1368 usbAttached = false;
1369 break;
1370 default:
1371 phosphor::logging::log<phosphor::logging::level::ERR>(
1372 "Invalid control option specified.");
1373 return ipmi::responseInvalidFieldRequest();
1374 }
1375
1376 return ipmi::responseSuccess(imageTransferStarted, imageTransferCompleted,
1377 imageTransferAborted, usbAttached, uint4_t(0));
1378}
1379
1380/** @brief implements firmware get status command
1381 * @parameter
1382 * - none
1383 * @returns IPMI completion code plus response data
1384 * - status - processing status
1385 * - percentage - percentage completion
1386 * - check - channel integrity check status
1387 **/
1388ipmi::RspType<uint8_t, // status
1389 uint8_t, // percentage
1390 uint8_t // check
1391 >
1392 ipmiGetFirmwareUpdateStatus()
1393
1394{
1395 // Byte 1 - status (0=init, 1=idle, 2=download, 3=validate, 4=write,
1396 // 5=ready, f=error, 83=ac cycle required)
1397 // Byte 2 - percent
1398 // Byte 3 - integrity check status (0=none, 1=req, 2=sha2ok, e2=sha2fail)
1399 uint8_t status = fwUpdateStatus.getState();
1400 uint8_t percent = fwUpdateStatus.percent();
1401 uint8_t check = xferHashCheck ? xferHashCheck->status() : 0;
1402
1403 // Status code.
1404 return ipmi::responseSuccess(status, percent, check);
1405}
1406
1407ipmi::RspType<bool, bool, bool, uint5_t> ipmiSetFirmwareUpdateOptions(
James Feistfcd2d3a2020-05-28 10:38:15 -07001408 const ipmi::Context::ptr& ctx, bool noDowngradeMask, bool deferRestartMask,
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301409 bool sha2CheckMask, uint5_t reserved1, bool noDowngrade, bool deferRestart,
1410 bool sha2Check, uint5_t reserved2,
1411 std::optional<std::vector<uint8_t>> integrityCheckVal)
AppaRao Puli28972062019-11-11 02:04:45 +05301412{
1413 phosphor::logging::log<phosphor::logging::level::INFO>(
1414 "Set firmware update options.");
Rajashekar Gade Reddy5b1988b2019-12-18 19:17:26 +05301415 bool isIPMBChannel = false;
1416
1417 if (checkIPMBChannel(ctx, isIPMBChannel) != ipmi::ccSuccess)
1418 {
1419 return ipmi::responseUnspecifiedError();
1420 }
1421 if (isIPMBChannel)
1422 {
1423 phosphor::logging::log<phosphor::logging::level::INFO>(
1424 "Channel not supported. Failed to set firmware update options");
1425 return ipmi::responseCommandNotAvailable();
1426 }
AppaRao Puli28972062019-11-11 02:04:45 +05301427 bool noDowngradeState = fwUpdateStatus.getInhibitDowngrade();
1428 bool deferRestartState = fwUpdateStatus.getDeferRestart();
1429 bool sha2CheckState = xferHashCheck ? true : false;
1430
1431 if (noDowngradeMask && (noDowngradeState != noDowngrade))
1432 {
1433 fwUpdateStatus.setInhibitDowngrade(noDowngrade);
1434 noDowngradeState = noDowngrade;
1435 }
1436 if (deferRestartMask && (deferRestartState != deferRestart))
1437 {
1438 fwUpdateStatus.setDeferRestart(deferRestart);
1439 deferRestartState = deferRestart;
1440 }
1441 if (sha2CheckMask)
1442 {
1443 if (sha2Check)
1444 {
1445 auto hashSize = EVP_MD_size(EVP_sha256());
1446 if ((*integrityCheckVal).size() != hashSize)
1447 {
1448 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1449 "Invalid size of Hash specified.");
1450 return ipmi::responseInvalidFieldRequest();
1451 }
1452 xferHashCheck = std::make_shared<TransferHashCheck>();
1453 xferHashCheck->init(*integrityCheckVal);
1454 }
1455 else
1456 {
1457 // delete the xferHashCheck object
1458 xferHashCheck.reset();
1459 }
1460 sha2CheckState = sha2CheckMask;
1461 }
1462 return ipmi::responseSuccess(noDowngradeState, deferRestartState,
1463 sha2CheckState, reserved1);
1464}
Vernon Mauery52ce6622019-05-22 09:19:46 -07001465
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301466ipmi::RspType<uint32_t>
James Feistfcd2d3a2020-05-28 10:38:15 -07001467 ipmiFwImageWriteData(const std::vector<uint8_t>& writeData)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001468{
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301469 const uint8_t ccCmdNotSupportedInPresentState = 0xD5;
1470 size_t writeDataLen = writeData.size();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001471
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301472 if (!writeDataLen)
1473 {
1474 return ipmi::responseReqDataLenInvalid();
1475 }
1476
AppaRao Puli28972062019-11-11 02:04:45 +05301477 if (fwUpdateStatus.getState() != FwUpdateStatusCache::fwStateDownload)
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301478 {
AppaRao Puli28972062019-11-11 02:04:45 +05301479 phosphor::logging::log<phosphor::logging::level::ERR>(
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301480 "Invalid firmware update state.");
1481 return ipmi::response(ccCmdNotSupportedInPresentState);
1482 }
Vernon Mauery52ce6622019-05-22 09:19:46 -07001483
AppaRao Puli28972062019-11-11 02:04:45 +05301484 std::ofstream out(firmwareBufferFile,
Vernon Mauery52ce6622019-05-22 09:19:46 -07001485 std::ofstream::binary | std::ofstream::app);
1486 if (!out)
1487 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301488 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1489 "Error while opening file.");
1490 return ipmi::responseUnspecifiedError();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001491 }
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301492
1493 uint64_t fileDataLen = out.tellp();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301494
AppaRao Puli28972062019-11-11 02:04:45 +05301495 if ((fileDataLen + writeDataLen) > maxFirmwareImageSize)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001496 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301497 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1498 "Firmware image size exceeds the limit");
1499 return ipmi::responseInvalidFieldRequest();
Vernon Mauery52ce6622019-05-22 09:19:46 -07001500 }
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301501
James Feistfcd2d3a2020-05-28 10:38:15 -07001502 const char* data = reinterpret_cast<const char*>(writeData.data());
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301503 out.write(data, writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001504 out.close();
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301505
AppaRao Puli28972062019-11-11 02:04:45 +05301506 if (xferHashCheck)
Vernon Mauery52ce6622019-05-22 09:19:46 -07001507 {
AppaRao Puli28972062019-11-11 02:04:45 +05301508 xferHashCheck->hash(writeData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001509 }
1510
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301511#ifdef INTEL_PFR_ENABLED
1512 /* PFR image block 0 - As defined in HAS */
1513 struct PFRImageBlock0
1514 {
1515 uint32_t tag;
1516 uint32_t pcLength;
1517 uint32_t pcType;
1518 uint32_t reserved1;
1519 uint8_t hash256[32];
1520 uint8_t hash384[48];
1521 uint8_t reserved2[32];
1522 } __attribute__((packed));
1523
1524 /* Get the PFR block 0 data and read the uploaded image
1525 * information( Image type, length etc) */
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301526 if (((fileDataLen + writeDataLen) >= sizeof(PFRImageBlock0)) &&
1527 (!block0Mapped))
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301528 {
1529 struct PFRImageBlock0 block0Data = {0};
1530
AppaRao Puli28972062019-11-11 02:04:45 +05301531 std::ifstream inFile(firmwareBufferFile,
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301532 std::ios::binary | std::ios::in);
James Feistfcd2d3a2020-05-28 10:38:15 -07001533 inFile.read(reinterpret_cast<char*>(&block0Data), sizeof(block0Data));
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301534 inFile.close();
1535
1536 uint32_t magicNum = block0Data.tag;
1537
1538 /* Validate the magic number */
1539 if (magicNum != perBlock0MagicNum)
1540 {
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301541 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1542 "PFR image magic number not matched");
1543 return ipmi::responseInvalidFieldRequest();
Rajashekar Gade Reddydf5e3272019-09-05 18:10:53 +05301544 }
1545 // Note:imgLength, imgType and block0Mapped are in global scope, as
1546 // these are used in cascaded updates.
1547 imgLength = block0Data.pcLength;
1548 imgType = block0Data.pcType;
1549 block0Mapped = true;
1550 }
1551#endif // end of INTEL_PFR_ENABLED
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301552 return ipmi::responseSuccess(writeDataLen);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001553}
1554
AppaRao Puli28972062019-11-11 02:04:45 +05301555static void registerFirmwareFunctions()
Vernon Mauery52ce6622019-05-22 09:19:46 -07001556{
1557 // guarantee that we start with an already timed out timestamp
AppaRao Puli28972062019-11-11 02:04:45 +05301558 fwRandomNumGenTs =
1559 std::chrono::steady_clock::now() - fwRandomNumExpirySeconds;
1560 fwUpdateStatus.setState(
1561 static_cast<uint8_t>(FwUpdateStatusCache::fwStateInit));
Vernon Mauery52ce6622019-05-22 09:19:46 -07001562
AppaRao Puli28972062019-11-11 02:04:45 +05301563 unlink(firmwareBufferFile);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001564
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301565#ifdef INTEL_PFR_ENABLED
1566 // Following commands are supported only for PFR enabled platforms
1567 // CMD:0x20 - Get Firmware Version Information
AppaRao Puli28972062019-11-11 02:04:45 +05301568 // CMD:0x21 - Get Firmware Security Version Information
1569 // CMD:0x25 - Get Root Certificate Data
Vernon Mauery52ce6622019-05-22 09:19:46 -07001570
AppaRao Puli37fde6b2019-10-25 16:37:50 +05301571 // get firmware version information
1572 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1573 ipmi::firmware::cmdGetFwVersionInfo,
1574 ipmi::Privilege::Admin, ipmiGetFwVersionInfo);
AppaRao Puli28972062019-11-11 02:04:45 +05301575
Vernon Mauery52ce6622019-05-22 09:19:46 -07001576 // get firmware security version information
AppaRao Puli28972062019-11-11 02:04:45 +05301577 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1578 ipmi::firmware::cmdGetFwSecurityVersionInfo,
1579 ipmi::Privilege::Admin, ipmiGetFwSecurityVersionInfo);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001580
Vernon Mauery52ce6622019-05-22 09:19:46 -07001581 // get root certificate data
Rajashekar Gade Reddyc8864062019-10-15 16:52:30 +05301582 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1583 ipmi::firmware::cmdFwGetRootCertData,
1584 ipmi::Privilege::Admin, ipmiGetFwRootCertData);
1585#endif
Vernon Mauery52ce6622019-05-22 09:19:46 -07001586
AppaRao Puli28972062019-11-11 02:04:45 +05301587 // get firmware update channel information (max transfer sizes)
1588 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1589 ipmi::firmware::cmdGetFwUpdateChannelInfo,
1590 ipmi::Privilege::Admin, ipmiFirmwareMaxTransferSize);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001591
AppaRao Puli28972062019-11-11 02:04:45 +05301592 // get bmc execution context
1593 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1594 ipmi::firmware::cmdGetBmcExecutionContext,
1595 ipmi::Privilege::Admin, ipmiGetBmcExecutionContext);
1596
1597 // Get Firmware Update Random number
1598 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1599 ipmi::firmware::cmdGetFwUpdateRandomNumber,
1600 ipmi::Privilege::Admin, ipmiGetFwUpdateRandomNumber);
1601
1602 // Set Firmware Update Mode
1603 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1604 ipmi::firmware::cmdSetFirmwareUpdateMode,
AppaRao Puli4b3e1c72019-10-16 20:53:09 +05301605 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001606
AppaRao Puli28972062019-11-11 02:04:45 +05301607 // Exit Firmware Update Mode
anil kumar appanab57098a2019-05-28 16:22:33 +00001608 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
AppaRao Puli28972062019-11-11 02:04:45 +05301609 ipmi::firmware::cmdExitFirmwareUpdateMode,
1610 ipmi::Privilege::Admin, ipmiExitFirmwareUpdateMode);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001611
AppaRao Puli28972062019-11-11 02:04:45 +05301612 // Get/Set Firmware Update Control
1613 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1614 ipmi::firmware::cmdGetSetFwUpdateControl,
1615 ipmi::Privilege::Admin,
1616 ipmiGetSetFirmwareUpdateControl);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001617
AppaRao Puli28972062019-11-11 02:04:45 +05301618 // Get Firmware Update Status
1619 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1620 ipmi::firmware::cmdGetFirmwareUpdateStatus,
1621 ipmi::Privilege::Admin, ipmiGetFirmwareUpdateStatus);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001622
AppaRao Puli28972062019-11-11 02:04:45 +05301623 // Set Firmware Update Options
1624 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnFirmware,
1625 ipmi::firmware::cmdSetFirmwareUpdateOptions,
1626 ipmi::Privilege::Admin, ipmiSetFirmwareUpdateOptions);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001627 // write image data
Rajashekar Gade Reddy3ec26202019-10-29 14:10:00 +05301628 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnFirmware,
1629 ipmi::firmware::cmdFwImageWriteData,
1630 ipmi::Privilege::Admin, ipmiFwImageWriteData);
Vernon Mauery52ce6622019-05-22 09:19:46 -07001631 return;
1632}