blob: 93e137b01a6311d8bd5860ffd08c08808a1920b1 [file] [log] [blame]
Sampa Misraaea5dde2020-08-31 08:33:47 -05001#include "inband_code_update.hpp"
2
Sagar Srinivas78a225a2020-08-27 00:52:20 -05003#include "libpldm/entity.h"
4
5#include "libpldmresponder/pdr.hpp"
Sampa Misraaea5dde2020-08-31 08:33:47 -05006#include "oem_ibm_handler.hpp"
7#include "xyz/openbmc_project/Common/error.hpp"
8
Adriana Kobylak727f7382020-09-01 14:38:25 -05009#include <arpa/inet.h>
10
Sampa Misraaea5dde2020-08-31 08:33:47 -050011#include <sdbusplus/server.hpp>
12#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
13
14#include <exception>
Adriana Kobylak727f7382020-09-01 14:38:25 -050015#include <fstream>
Sampa Misraaea5dde2020-08-31 08:33:47 -050016
17namespace pldm
18{
Sampa Misraaea5dde2020-08-31 08:33:47 -050019namespace responder
20{
21using namespace oem_ibm_platform;
22
Adriana Kobylakfa810d72020-10-16 16:27:28 -050023/** @brief Directory where the lid files without a header are stored */
24auto lidDirPath = fs::path(LID_STAGING_DIR) / "lid";
25
Adriana Kobylaka1f158c2020-11-09 12:47:29 -060026/** @brief Directory where the image files are stored as they are built */
27auto imageDirPath = fs::path(LID_STAGING_DIR) / "image";
28
29/** @brief The file name of the code update tarball */
30constexpr auto tarImageName = "image.tar";
31
32/** @brief The path to the code update tarball file */
33auto tarImagePath = fs::path(imageDirPath) / tarImageName;
34
Sampa Misraaea5dde2020-08-31 08:33:47 -050035std::string CodeUpdate::fetchCurrentBootSide()
36{
37 return currBootSide;
38}
39
40std::string CodeUpdate::fetchNextBootSide()
41{
42 return nextBootSide;
43}
44
45int CodeUpdate::setCurrentBootSide(const std::string& currSide)
46{
47 currBootSide = currSide;
48 return PLDM_SUCCESS;
49}
50
51int CodeUpdate::setNextBootSide(const std::string& nextSide)
52{
53 nextBootSide = nextSide;
54 std::string objPath{};
55 if (nextBootSide == currBootSide)
56 {
57 objPath = runningVersion;
58 }
59 else
60 {
61 objPath = nonRunningVersion;
62 }
63 if (objPath.empty())
64 {
65 std::cerr << "no nonRunningVersion present \n";
66 return PLDM_PLATFORM_INVALID_STATE_VALUE;
67 }
68
69 pldm::utils::DBusMapping dbusMapping{objPath, redundancyIntf, "Priority",
70 "uint8_t"};
71 uint8_t val = 0;
72 pldm::utils::PropertyValue value = static_cast<uint8_t>(val);
73 try
74 {
75 dBusIntf->setDbusProperty(dbusMapping, value);
76 }
77 catch (const std::exception& e)
78 {
79 std::cerr << "failed to set the next boot side to " << objPath.c_str()
80 << " ERROR=" << e.what() << "\n";
81 return PLDM_ERROR;
82 }
83 return PLDM_SUCCESS;
84}
85
86void CodeUpdate::setVersions()
87{
88 static constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
89 static constexpr auto functionalObjPath =
90 "/xyz/openbmc_project/software/functional";
91 static constexpr auto activeObjPath =
92 "/xyz/openbmc_project/software/active";
93 static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
94
95 auto& bus = dBusIntf->getBus();
Sampa Misraaea5dde2020-08-31 08:33:47 -050096 try
97 {
98 auto method = bus.new_method_call(mapperService, functionalObjPath,
99 propIntf, "Get");
100 method.append("xyz.openbmc_project.Association", "endpoints");
101 std::variant<std::vector<std::string>> paths;
102
103 auto reply = bus.call(method);
104 reply.read(paths);
105
106 runningVersion = std::get<std::vector<std::string>>(paths)[0];
107
108 auto method1 =
109 bus.new_method_call(mapperService, activeObjPath, propIntf, "Get");
110 method1.append("xyz.openbmc_project.Association", "endpoints");
111
112 auto reply1 = bus.call(method1);
113 reply1.read(paths);
114 for (const auto& path : std::get<std::vector<std::string>>(paths))
115 {
116 if (path != runningVersion)
117 {
118 nonRunningVersion = path;
119 break;
120 }
121 }
122 }
123 catch (const std::exception& e)
124 {
125 std::cerr << "failed to make a d-bus call to Object Mapper "
126 "Association, ERROR="
127 << e.what() << "\n";
128 return;
129 }
130
131 using namespace sdbusplus::bus::match::rules;
132 captureNextBootSideChange.push_back(
133 std::make_unique<sdbusplus::bus::match::match>(
134 pldm::utils::DBusHandler::getBus(),
135 propertiesChanged(runningVersion, redundancyIntf),
136 [this](sdbusplus::message::message& msg) {
137 DbusChangedProps props;
138 std::string iface;
139 msg.read(iface, props);
140 processPriorityChangeNotification(props);
141 }));
142 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
143 pldm::utils::DBusHandler::getBus(),
144 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
145 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
146 [this](sdbusplus::message::message& msg) {
147 DBusInterfaceAdded interfaces;
148 sdbusplus::message::object_path path;
149 msg.read(path, interfaces);
150 for (auto& interface : interfaces)
151 {
152 if (interface.first ==
153 "xyz.openbmc_project.Software.Activation")
154 {
155 newImageId = path.str;
156 break;
157 }
158 }
159 });
160}
161
162void CodeUpdate::processPriorityChangeNotification(
163 const DbusChangedProps& chProperties)
164{
165 static constexpr auto propName = "Priority";
166 const auto it = chProperties.find(propName);
167 if (it == chProperties.end())
168 {
169 return;
170 }
171 uint8_t newVal = std::get<uint8_t>(it->second);
172 nextBootSide = (newVal == 0) ? currBootSide
173 : ((currBootSide == Tside) ? Pside : Tside);
174}
175
176void CodeUpdate::setOemPlatformHandler(
177 pldm::responder::oem_platform::Handler* handler)
178{
179 oemPlatformHandler = handler;
180}
181
182uint8_t fetchBootSide(uint16_t entityInstance, CodeUpdate* codeUpdate)
183{
184 uint8_t sensorOpState = tSideNum;
Sampa Misraaea5dde2020-08-31 08:33:47 -0500185 if (entityInstance == 0)
186 {
187 auto currSide = codeUpdate->fetchCurrentBootSide();
188 if (currSide == Pside)
189 {
190 sensorOpState = pSideNum;
191 }
192 }
193 else if (entityInstance == 1)
194 {
195 auto nextSide = codeUpdate->fetchNextBootSide();
196 if (nextSide == Pside)
197 {
198 sensorOpState = pSideNum;
199 }
200 }
201 else
202 {
203 sensorOpState = PLDM_SENSOR_UNKNOWN;
204 }
205
206 return sensorOpState;
207}
208
209int setBootSide(uint16_t entityInstance, uint8_t currState,
210 const std::vector<set_effecter_state_field>& stateField,
211 CodeUpdate* codeUpdate)
212{
213 int rc = PLDM_SUCCESS;
214 auto side = (stateField[currState].effecter_state == pSideNum) ? "P" : "T";
215
216 if (entityInstance == 0)
217 {
218 rc = codeUpdate->setCurrentBootSide(side);
219 }
220 else if (entityInstance == 1)
221 {
222 rc = codeUpdate->setNextBootSide(side);
223 }
224 else
225 {
226 rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
227 }
228 return rc;
229}
230
Adriana Kobylak727f7382020-09-01 14:38:25 -0500231int processCodeUpdateLid(const std::string& filePath)
232{
233 struct LidHeader
234 {
235 uint16_t magicNumber;
Adriana Kobylak86d14182020-10-16 16:11:08 -0500236 uint16_t headerVersion;
237 uint32_t lidNumber;
238 uint32_t lidDate;
239 uint16_t lidTime;
240 uint16_t lidClass;
241 uint32_t lidCrc;
242 uint32_t lidSize;
243 uint32_t headerSize;
Adriana Kobylak727f7382020-09-01 14:38:25 -0500244 };
245 LidHeader header;
246
247 std::ifstream ifs(filePath, std::ios::in | std::ios::binary);
248 if (!ifs)
249 {
250 std::cerr << "ifstream open error: " << filePath << "\n";
251 return PLDM_ERROR;
252 }
253 ifs.seekg(0);
254 ifs.read(reinterpret_cast<char*>(&header), sizeof(header));
Adriana Kobylak727f7382020-09-01 14:38:25 -0500255
Adriana Kobylak86d14182020-10-16 16:11:08 -0500256 // File size should be the value of lid size minus the header size
257 auto fileSize = fs::file_size(filePath);
258 fileSize -= htonl(header.headerSize);
259 if (fileSize < htonl(header.lidSize))
260 {
261 // File is not completely written yet
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500262 ifs.close();
Adriana Kobylak86d14182020-10-16 16:11:08 -0500263 return PLDM_SUCCESS;
264 }
265
Adriana Kobylak727f7382020-09-01 14:38:25 -0500266 constexpr auto magicNumber = 0x0222;
267 if (htons(header.magicNumber) != magicNumber)
268 {
269 std::cerr << "Invalid magic number: " << filePath << "\n";
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500270 ifs.close();
Adriana Kobylak727f7382020-09-01 14:38:25 -0500271 return PLDM_ERROR;
272 }
273
Adriana Kobylaka1f158c2020-11-09 12:47:29 -0600274 fs::create_directories(imageDirPath);
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500275 fs::create_directories(lidDirPath);
276
Adriana Kobylaka1f158c2020-11-09 12:47:29 -0600277 constexpr auto bmcClass = 0x2000;
278 if (htons(header.lidClass) == bmcClass)
279 {
280 // Skip the header and concatenate the BMC LIDs into a tar file
281 std::ofstream ofs(tarImagePath,
282 std::ios::out | std::ios::binary | std::ios::app);
283 ifs.seekg(htonl(header.headerSize));
284 ofs << ifs.rdbuf();
285 ofs.flush();
286 ofs.close();
287 }
288 else
289 {
290 std::stringstream lidFileName;
291 lidFileName << std::hex << htonl(header.lidNumber) << ".lid";
292 auto lidNoHeaderPath = fs::path(lidDirPath) / lidFileName.str();
293 std::ofstream ofs(lidNoHeaderPath,
294 std::ios::out | std::ios::binary | std::ios::trunc);
295 ifs.seekg(htonl(header.headerSize));
296 ofs << ifs.rdbuf();
297 ofs.flush();
298 ofs.close();
299 }
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500300
301 ifs.close();
302 fs::remove(filePath);
Adriana Kobylak727f7382020-09-01 14:38:25 -0500303 return PLDM_SUCCESS;
304}
305
Sampa Misraaea5dde2020-08-31 08:33:47 -0500306} // namespace responder
307} // namespace pldm