1 #include "inband_code_update.hpp"
2 
3 #include "oem_ibm_handler.hpp"
4 #include "xyz/openbmc_project/Common/error.hpp"
5 
6 #include <sdbusplus/server.hpp>
7 #include <xyz/openbmc_project/Dump/NewDump/server.hpp>
8 
9 #include <exception>
10 
11 namespace pldm
12 {
13 
14 namespace responder
15 {
16 using namespace oem_ibm_platform;
17 
18 std::string CodeUpdate::fetchCurrentBootSide()
19 {
20     return currBootSide;
21 }
22 
23 std::string CodeUpdate::fetchNextBootSide()
24 {
25     return nextBootSide;
26 }
27 
28 int CodeUpdate::setCurrentBootSide(const std::string& currSide)
29 {
30     currBootSide = currSide;
31     return PLDM_SUCCESS;
32 }
33 
34 int CodeUpdate::setNextBootSide(const std::string& nextSide)
35 {
36     nextBootSide = nextSide;
37     std::string objPath{};
38     if (nextBootSide == currBootSide)
39     {
40         objPath = runningVersion;
41     }
42     else
43     {
44         objPath = nonRunningVersion;
45     }
46     if (objPath.empty())
47     {
48         std::cerr << "no nonRunningVersion present \n";
49         return PLDM_PLATFORM_INVALID_STATE_VALUE;
50     }
51 
52     pldm::utils::DBusMapping dbusMapping{objPath, redundancyIntf, "Priority",
53                                          "uint8_t"};
54     uint8_t val = 0;
55     pldm::utils::PropertyValue value = static_cast<uint8_t>(val);
56     try
57     {
58         dBusIntf->setDbusProperty(dbusMapping, value);
59     }
60     catch (const std::exception& e)
61     {
62         std::cerr << "failed to set the next boot side to " << objPath.c_str()
63                   << " ERROR=" << e.what() << "\n";
64         return PLDM_ERROR;
65     }
66     return PLDM_SUCCESS;
67 }
68 
69 void CodeUpdate::setVersions()
70 {
71     static constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
72     static constexpr auto functionalObjPath =
73         "/xyz/openbmc_project/software/functional";
74     static constexpr auto activeObjPath =
75         "/xyz/openbmc_project/software/active";
76     static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
77 
78     auto& bus = dBusIntf->getBus();
79 
80     try
81     {
82         auto method = bus.new_method_call(mapperService, functionalObjPath,
83                                           propIntf, "Get");
84         method.append("xyz.openbmc_project.Association", "endpoints");
85         std::variant<std::vector<std::string>> paths;
86 
87         auto reply = bus.call(method);
88         reply.read(paths);
89 
90         runningVersion = std::get<std::vector<std::string>>(paths)[0];
91 
92         auto method1 =
93             bus.new_method_call(mapperService, activeObjPath, propIntf, "Get");
94         method1.append("xyz.openbmc_project.Association", "endpoints");
95 
96         auto reply1 = bus.call(method1);
97         reply1.read(paths);
98         for (const auto& path : std::get<std::vector<std::string>>(paths))
99         {
100             if (path != runningVersion)
101             {
102                 nonRunningVersion = path;
103                 break;
104             }
105         }
106     }
107     catch (const std::exception& e)
108     {
109         std::cerr << "failed to make a d-bus call to Object Mapper "
110                      "Association, ERROR="
111                   << e.what() << "\n";
112         return;
113     }
114 
115     using namespace sdbusplus::bus::match::rules;
116     captureNextBootSideChange.push_back(
117         std::make_unique<sdbusplus::bus::match::match>(
118             pldm::utils::DBusHandler::getBus(),
119             propertiesChanged(runningVersion, redundancyIntf),
120             [this](sdbusplus::message::message& msg) {
121                 DbusChangedProps props;
122                 std::string iface;
123                 msg.read(iface, props);
124                 processPriorityChangeNotification(props);
125             }));
126     fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
127         pldm::utils::DBusHandler::getBus(),
128         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
129         "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
130         [this](sdbusplus::message::message& msg) {
131             DBusInterfaceAdded interfaces;
132             sdbusplus::message::object_path path;
133             msg.read(path, interfaces);
134             for (auto& interface : interfaces)
135             {
136                 if (interface.first ==
137                     "xyz.openbmc_project.Software.Activation")
138                 {
139                     newImageId = path.str;
140                     break;
141                 }
142             }
143         });
144 }
145 
146 void CodeUpdate::processPriorityChangeNotification(
147     const DbusChangedProps& chProperties)
148 {
149     static constexpr auto propName = "Priority";
150     const auto it = chProperties.find(propName);
151     if (it == chProperties.end())
152     {
153         return;
154     }
155     uint8_t newVal = std::get<uint8_t>(it->second);
156     nextBootSide = (newVal == 0) ? currBootSide
157                                  : ((currBootSide == Tside) ? Pside : Tside);
158 }
159 
160 void CodeUpdate::setOemPlatformHandler(
161     pldm::responder::oem_platform::Handler* handler)
162 {
163     oemPlatformHandler = handler;
164 }
165 
166 uint8_t fetchBootSide(uint16_t entityInstance, CodeUpdate* codeUpdate)
167 {
168     uint8_t sensorOpState = tSideNum;
169 
170     if (entityInstance == 0)
171     {
172         auto currSide = codeUpdate->fetchCurrentBootSide();
173         if (currSide == Pside)
174         {
175             sensorOpState = pSideNum;
176         }
177     }
178     else if (entityInstance == 1)
179     {
180         auto nextSide = codeUpdate->fetchNextBootSide();
181         if (nextSide == Pside)
182         {
183             sensorOpState = pSideNum;
184         }
185     }
186     else
187     {
188         sensorOpState = PLDM_SENSOR_UNKNOWN;
189     }
190 
191     return sensorOpState;
192 }
193 
194 int setBootSide(uint16_t entityInstance, uint8_t currState,
195                 const std::vector<set_effecter_state_field>& stateField,
196                 CodeUpdate* codeUpdate)
197 {
198     int rc = PLDM_SUCCESS;
199     auto side = (stateField[currState].effecter_state == pSideNum) ? "P" : "T";
200 
201     if (entityInstance == 0)
202     {
203         rc = codeUpdate->setCurrentBootSide(side);
204     }
205     else if (entityInstance == 1)
206     {
207         rc = codeUpdate->setNextBootSide(side);
208     }
209     else
210     {
211         rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
212     }
213     return rc;
214 }
215 
216 } // namespace responder
217 } // namespace pldm
218