xref: /openbmc/fb-ipmi-oem/src/biccommands.cpp (revision 05d0ce93)
1 /*
2  * Copyright (c)  2018 Intel Corporation.
3  * Copyright (c)  2018-present Facebook.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <ipmid/api.hpp>
19 #include <ipmid/api-types.hpp>
20 
21 #include <commandutils.hpp>
22 #include <biccommands.hpp>
23 #include <phosphor-logging/log.hpp>
24 
25 #include <vector>
26 #include <variant>
27 #include <iostream>
28 
29 namespace ipmi
30 {
31 
32 int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
33                std::vector<uint8_t>&);
34 
35 using namespace phosphor::logging;
36 
37 #ifdef BIC_ENABLED
38 static void registerBICFunctions() __attribute__((constructor));
39 #endif
40 
41 extern message::Response::ptr executeIpmiCommand(message::Request::ptr);
42 
43 int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
44                std::vector<uint8_t>&);
45 
46 //----------------------------------------------------------------------
47 // ipmiOemBicHandler (IPMI/Section - ) (CMD_OEM_BIC_INFO)
48 // This Function will handle BIC request for netfn=0x38 and cmd=1
49 // send the response back to the sender.
50 //----------------------------------------------------------------------
51 
52 ipmi::RspType<IanaType, uint8_t, uint2_t, uint6_t, uint8_t, uint8_t,
53               ipmi::message::Payload>
54     ipmiOemBicHandler(ipmi::Context::ptr ctx, IanaType reqIana,
55                       uint8_t interface, uint2_t lun, uint6_t netFnReq,
56                       uint8_t cmdReq, SecureBuffer data)
57 {
58 
59     ipmi::message::Response::ptr res;
60 
61     // Updating the correct netfn and cmd in the ipmi Context
62     ctx->netFn = ((uint8_t)netFnReq);
63     ctx->cmd = cmdReq;
64 
65     // creating ipmi message request for calling executeIpmiCommand function
66     auto req = std::make_shared<ipmi::message::Request>(ctx, std::move(data));
67 
68     // Calling executeIpmiCommand request function
69     res = ipmi::executeIpmiCommand(req);
70 
71     // sending the response with headers and payload
72     return ipmi::responseSuccess(reqIana, interface, lun, ++netFnReq, cmdReq,
73                                  res->cc, res->payload);
74 }
75 
76 //----------------------------------------------------------------------
77 // ipmiOemPostCodeHandler (CMD_OEM_BIC_POST_BUFFER_INFO)
78 // This Function will handle BIC incomming postcode from multi-host for
79 // netfn=0x38 and cmd=0x08 send the response back to the sender.
80 //----------------------------------------------------------------------
81 
82 ipmi::RspType<IanaType> ipmiOemPostCodeHandler(ipmi::Context::ptr ctx,
83                                                IanaType reqIana,
84                                                uint8_t dataLen,
85                                                std::vector<uint8_t> data)
86 {
87     // creating bus connection
88     auto conn = getSdBus();
89 
90     using postcode_t = std::tuple<uint64_t, std::vector<uint8_t>>;
91 
92     std::string dbusObjStr = dbusObj + std::to_string((ctx->hostIdx + 1));
93 
94     for (unsigned int index = 0; index < dataLen; index++)
95     {
96         uint64_t primaryPostCode = static_cast<uint64_t>(data[index]);
97         auto postCode = postcode_t(primaryPostCode, {});
98 
99         try
100         {
101             auto method = conn->new_method_call(
102                 "xyz.openbmc_project.State.Boot.Raw", dbusObjStr.c_str(),
103                 "org.freedesktop.DBus.Properties", "Set");
104 
105             // Adding paramters to method call
106             method.append(dbusService, "Value",
107                           std::variant<postcode_t>(postCode));
108 
109             // Invoke method call function
110             auto reply = conn->call(method);
111         }
112 
113         catch (std::exception& e)
114         {
115             phosphor::logging::log<phosphor::logging::level::ERR>(
116                 "post code handler error\n");
117 
118             // sending the Error response
119             return ipmi::responseResponseError();
120         }
121     }
122 
123     return ipmi::responseSuccess(reqIana);
124 }
125 
126 //----------------------------------------------------------------------
127 // ipmiOemGetBicGpioState (CMD_OEM_GET_BIC_GPIO_STATE)
128 // This Function will handle BIC GPIO stats for
129 // netfn=0x38 and cmd=0x03 send the response back to the sender.
130 //----------------------------------------------------------------------
131 
132 ipmi::RspType<IanaType, std::vector<uint8_t>>
133     ipmiOemGetBicGpioState(ipmi::Context::ptr ctx, std::vector<uint8_t> reqIana)
134 {
135     std::vector<uint8_t> respData;
136 
137     if (std::equal(reqIana.begin(), reqIana.end(), iana.begin()) == false)
138     {
139         phosphor::logging::log<phosphor::logging::level::ERR>(
140             "Invalid IANA number");
141         return ipmi::responseInvalidFieldRequest();
142     }
143 
144     uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
145 
146     if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqIana, respData))
147     {
148         return ipmi::responseUnspecifiedError();
149     }
150 
151     std::vector<uint8_t> gpioState;
152     IanaType respIana;
153 
154     auto r =
155         std::ranges::copy_n(respData.begin(), iana.size(), respIana.begin()).in;
156     std::copy(r, respData.end(), std::back_inserter(gpioState));
157 
158     return ipmi::responseSuccess(respIana, gpioState);
159 }
160 
161 //----------------------------------------------------------------------
162 // ipmiOemSetHostPowerState (CMD_OEM_SET_HOST_POWER_STATE)
163 // This Function will handle BIC incomming IPMI request for
164 // setting host current state for netfn=0x38 and cmd=0x0C
165 // send the response back to the sender.
166 //----------------------------------------------------------------------
167 
168 ipmi::RspType<IanaType> ipmiOemSetHostPowerState(ipmi::Context::ptr ctx,
169                                                  IanaType reqIana,
170                                                  uint8_t status)
171 {
172     std::string targetUnit;
173 
174     switch (static_cast<HostPowerState>(status))
175     {
176         case HostPowerState::HOST_POWER_ON:
177             targetUnit = "obmc-host-startmin@.target";
178             break;
179         case HostPowerState::HOST_POWER_OFF:
180             targetUnit = "obmc-host-stop@.target";
181             break;
182         default:
183             phosphor::logging::log<phosphor::logging::level::ERR>(
184                 "IPMI ipmiOemHostPowerStatus power status error");
185             return ipmi::responseUnspecifiedError();
186     }
187 
188     int mousePos = targetUnit.find('@');
189     targetUnit.insert(mousePos + 1, std::to_string(ctx->hostIdx + 1));
190 
191     auto conn = getSdBus();
192     auto method = conn->new_method_call(systemdService, systemdObjPath,
193                                         systemdInterface, "StartUnit");
194     method.append(targetUnit);
195     method.append("replace");
196 
197     try
198     {
199         conn->call_noreply(method);
200     }
201     catch (const sdbusplus::exception::SdBusError& e)
202     {
203         phosphor::logging::log<phosphor::logging::level::ERR>(
204             "IPMI ipmiOemHostPowerStatus Failed in call method",
205             phosphor::logging::entry("ERROR=%s", e.what()));
206         return ipmi::responseUnspecifiedError();
207     }
208 
209     return ipmi::responseSuccess(reqIana);
210 }
211 
212 //----------------------------------------------------------------------
213 // ipmiOemGetBiosFlashSize (CMD_OEM_GET_FLASH_SIZE)
214 // This Function will return the bios flash size
215 // netfn=0x38 and cmd=0x19 send the response back to the sender.
216 //----------------------------------------------------------------------
217 
218 ipmi::RspType<IanaType, flashSize>
219     ipmiOemGetBiosFlashSize(ipmi::Context::ptr ctx, IanaType ianaReq,
220                             uint8_t target)
221 {
222     if (iana != ianaReq)
223     {
224         phosphor::logging::log<phosphor::logging::level::ERR>(
225             "Invalid IANA ID length received");
226         return ipmi::responseReqDataLenInvalid();
227     }
228 
229     std::vector<uint8_t> respData;
230     uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
231     std::vector<uint8_t> reqData(ianaReq.begin(), ianaReq.end());
232     reqData.emplace_back(target);
233 
234     if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
235     {
236         return ipmi::responseUnspecifiedError();
237     }
238 
239     if (respData.size() != flashSizeRespLen)
240     {
241         phosphor::logging::log<phosphor::logging::level::ERR>(
242             "Invalid Response Data length received");
243         return ipmi::responseReqDataLenInvalid();
244     }
245 
246     IanaType ianaResp;
247     std::copy_n(respData.begin(), ianaResp.size(), ianaResp.begin());
248 
249     if (iana != ianaResp)
250     {
251         phosphor::logging::log<phosphor::logging::level::ERR>(
252             "Invalid IANA ID received");
253         return ipmi::responseInvalidCommand();
254     }
255 
256     flashSize flashResp;
257     std::vector<uint8_t>::iterator respDataIter = respData.begin();
258     std::advance(respDataIter, ianaResp.size());
259     std::copy_n(respDataIter, flashResp.size(), flashResp.begin());
260 
261     // sending the success response.
262     return ipmi::responseSuccess(ianaResp, flashResp);
263 }
264 
265 [[maybe_unused]] static void registerBICFunctions(void)
266 {
267 
268     phosphor::logging::log<phosphor::logging::level::INFO>(
269         "Registering BIC commands");
270 
271     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
272                           static_cast<Cmd>(fb_bic_cmds::CMD_OEM_BIC_INFO),
273                           ipmi::Privilege::User, ipmiOemBicHandler);
274     ipmi::registerHandler(
275         ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
276         static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SEND_POST_BUFFER_TO_BMC),
277         ipmi::Privilege::User, ipmiOemPostCodeHandler);
278     ipmi::registerHandler(
279         ipmi::prioOemBase, ipmi::netFnOemFive,
280         static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_BIC_GPIO_STATE),
281         ipmi::Privilege::User, ipmiOemGetBicGpioState);
282     ipmi::registerHandler(
283         ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
284         static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SET_HOST_POWER_STATE),
285         ipmi::Privilege::User, ipmiOemSetHostPowerState);
286     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
287                           static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_FLASH_SIZE),
288                           ipmi::Privilege::User, ipmiOemGetBiosFlashSize);
289     return;
290 }
291 
292 } // namespace ipmi
293