blob: 6da886efca9f58eb2c684ad24c8c30de48d93387 [file] [log] [blame]
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +05301/*
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
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053018#include <biccommands.hpp>
Patrick Williams2405ae92023-05-10 07:50:09 -050019#include <commandutils.hpp>
20#include <ipmid/api-types.hpp>
21#include <ipmid/api.hpp>
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053022#include <phosphor-logging/log.hpp>
Delphine CC Chiu14ddea52023-06-06 09:43:44 +080023#include <types.hpp>
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053024
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053025#include <iostream>
Patrick Williams2405ae92023-05-10 07:50:09 -050026#include <variant>
27#include <vector>
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053028
29namespace ipmi
30{
31
Kumar Thangavel05d0ce92022-11-17 17:53:57 +053032int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
33 std::vector<uint8_t>&);
34
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053035using namespace phosphor::logging;
36
Patrick Williams58c1ca22021-04-22 12:29:35 -050037#ifdef BIC_ENABLED
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053038static void registerBICFunctions() __attribute__((constructor));
Patrick Williams58c1ca22021-04-22 12:29:35 -050039#endif
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053040
41extern message::Response::ptr executeIpmiCommand(message::Request::ptr);
42
Bonnie Lo25b79bf2022-12-16 15:41:48 +080043int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
44 std::vector<uint8_t>&);
45
Delphine CC Chiu14ddea52023-06-06 09:43:44 +080046constexpr std::array<uint8_t, 2> amdDimmLoopPrefix = {0xDD, 0xEE};
47
48namespace dimm
49{
50std::unordered_map<hostId, dimmLoop> dimmLoops;
51} // namespace dimm
52
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053053//----------------------------------------------------------------------
54// ipmiOemBicHandler (IPMI/Section - ) (CMD_OEM_BIC_INFO)
55// This Function will handle BIC request for netfn=0x38 and cmd=1
56// send the response back to the sender.
57//----------------------------------------------------------------------
58
Bonnie Lo25b79bf2022-12-16 15:41:48 +080059ipmi::RspType<IanaType, uint8_t, uint2_t, uint6_t, uint8_t, uint8_t,
60 ipmi::message::Payload>
61 ipmiOemBicHandler(ipmi::Context::ptr ctx, IanaType reqIana,
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053062 uint8_t interface, uint2_t lun, uint6_t netFnReq,
Patrick Williams485f9b32021-09-03 16:14:47 -050063 uint8_t cmdReq, SecureBuffer data)
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053064{
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053065 ipmi::message::Response::ptr res;
66
67 // Updating the correct netfn and cmd in the ipmi Context
68 ctx->netFn = ((uint8_t)netFnReq);
69 ctx->cmd = cmdReq;
70
71 // creating ipmi message request for calling executeIpmiCommand function
Patrick Williams485f9b32021-09-03 16:14:47 -050072 auto req = std::make_shared<ipmi::message::Request>(ctx, std::move(data));
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053073
74 // Calling executeIpmiCommand request function
75 res = ipmi::executeIpmiCommand(req);
76
77 // sending the response with headers and payload
Bonnie Lo25b79bf2022-12-16 15:41:48 +080078 return ipmi::responseSuccess(reqIana, interface, lun, ++netFnReq, cmdReq,
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +053079 res->cc, res->payload);
80}
81
Delphine CC Chiu14ddea52023-06-06 09:43:44 +080082void dimmLoopPatternDetection(size_t hostId, std::vector<uint8_t> data)
83{
84 if constexpr (postCodeSize != amdFourBytesPostCode)
85 {
86 return;
87 }
88
89 if (data.size() != amdFourBytesPostCode)
90 {
91 return;
92 }
93
94 /*
95 Reference from Meta_BIOS_Requirement_Spec_v0.80
96 For AMD platform, the POST code looping pattern format should be:
97 (each group has 4 bytes)
98 ●Group #0: [DDEE0000]
99 ●Group #1: [DDEE] + Total Error Count
100 ●Group #2: [DDEE] + Number of Error DIMM
101 ●Group #3: [DDEE] + Dimm location
102 ●Group #4: [DDEE] + major code
103 ●Group #5: [DDEE] + minor code
104 */
105 std::array<uint8_t, 2> prefix = {data[3], data[2]};
106
107 if (prefix != amdDimmLoopPrefix)
108 {
109 // Clear all the post code stored before.
110 if (dimm::dimmLoops[hostId].startDetect)
111 {
112 dimm::dimmLoops[hostId].totalErrorCount = 0;
113 dimm::dimmLoops[hostId].postCode.clear();
114
115 dimm::dimmLoops[hostId].startDetect = false;
116 }
117 return;
118 }
119
120 // Which means it already got the dimm loop, stop checking again.
121 if (dimm::dimmLoops[hostId].gotPattern)
122 {
123 return;
124 }
125
126 constexpr std::array<uint8_t, 4> anchorTag = {0x0, 0x0, 0xEE, 0xDD};
127 if (std::ranges::equal(anchorTag, data))
128 {
129 dimm::dimmLoops[hostId].startDetect = true;
130 }
131 if (dimm::dimmLoops[hostId].startDetect)
132 {
133 // The second one is error count
134 if (dimm::dimmLoops[hostId].postCode.size() % 6 == 1)
135 {
136 dimm::dimmLoops[hostId].totalErrorCount = (data[1] << 8) | data[0];
137 }
138
139 dimm::dimmLoops[hostId].postCode.push_back(data);
140
141 // Is the last element of dimmloop then stop to detect
142 if (dimm::dimmLoops[hostId].postCode.size() ==
143 (dimm::dimmLoops[hostId].totalErrorCount * 6))
144 {
145 // Gets whole pattern success
146 dimm::dimmLoops[hostId].gotPattern = true;
147 }
148 }
149}
150
Kumar Thangavelad049242020-08-31 22:27:33 +0530151//----------------------------------------------------------------------
152// ipmiOemPostCodeHandler (CMD_OEM_BIC_POST_BUFFER_INFO)
Manojkiran Eda519530b2024-06-17 11:46:15 +0530153// This Function will handle BIC incoming postcode from multi-host for
Delphine CC Chiu14ddea52023-06-06 09:43:44 +0800154// netfn=0x38 and cmd=0x08 or 0x33 send the response back to the sender.
Kumar Thangavelad049242020-08-31 22:27:33 +0530155//----------------------------------------------------------------------
156
Patrick Williams010dee02024-08-16 15:19:44 -0400157ipmi::RspType<IanaType>
158 ipmiOemPostCodeHandler(ipmi::Context::ptr ctx, IanaType reqIana,
159 uint8_t dataLen, std::vector<uint8_t> data)
Kumar Thangavelad049242020-08-31 22:27:33 +0530160{
161 // creating bus connection
162 auto conn = getSdBus();
163
Delphine CC Chiu14ddea52023-06-06 09:43:44 +0800164 auto hostId = findHost(ctx->hostIdx);
165 if (!hostId)
166 {
167 lg2::error("Invalid Host Id received");
168 return ipmi::responseInvalidCommand();
169 }
170 dimmLoopPatternDetection(*hostId, data);
171
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800172 using postcode_t = std::tuple<uint64_t, std::vector<uint8_t>>;
Manojkiran Edac723d6a2021-03-11 14:53:32 +0530173
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800174 std::string dbusObjStr = dbusObj + std::to_string((ctx->hostIdx + 1));
175
176 for (unsigned int index = 0; index < dataLen; index++)
177 {
178 uint64_t primaryPostCode = static_cast<uint64_t>(data[index]);
Kumar Thangavel0fcfbee2021-04-16 12:38:20 +0530179 auto postCode = postcode_t(primaryPostCode, {});
Kumar Thangavelad049242020-08-31 22:27:33 +0530180
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800181 try
182 {
183 auto method = conn->new_method_call(
184 "xyz.openbmc_project.State.Boot.Raw", dbusObjStr.c_str(),
185 "org.freedesktop.DBus.Properties", "Set");
Kumar Thangavelad049242020-08-31 22:27:33 +0530186
Manojkiran Eda519530b2024-06-17 11:46:15 +0530187 // Adding parameters to method call
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800188 method.append(dbusService, "Value",
189 std::variant<postcode_t>(postCode));
Kumar Thangavelad049242020-08-31 22:27:33 +0530190
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800191 // Invoke method call function
192 auto reply = conn->call(method);
193 }
Kumar Thangavelad049242020-08-31 22:27:33 +0530194
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800195 catch (std::exception& e)
196 {
197 phosphor::logging::log<phosphor::logging::level::ERR>(
198 "post code handler error\n");
Kumar Thangavelad049242020-08-31 22:27:33 +0530199
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800200 // sending the Error response
201 return ipmi::responseResponseError();
202 }
Kumar Thangavelad049242020-08-31 22:27:33 +0530203 }
Kumar Thangavelad049242020-08-31 22:27:33 +0530204
Bonnie Lo25b79bf2022-12-16 15:41:48 +0800205 return ipmi::responseSuccess(reqIana);
206}
207
208//----------------------------------------------------------------------
209// ipmiOemGetBicGpioState (CMD_OEM_GET_BIC_GPIO_STATE)
210// This Function will handle BIC GPIO stats for
211// netfn=0x38 and cmd=0x03 send the response back to the sender.
212//----------------------------------------------------------------------
213
214ipmi::RspType<IanaType, std::vector<uint8_t>>
215 ipmiOemGetBicGpioState(ipmi::Context::ptr ctx, std::vector<uint8_t> reqIana)
216{
217 std::vector<uint8_t> respData;
218
219 if (std::equal(reqIana.begin(), reqIana.end(), iana.begin()) == false)
220 {
221 phosphor::logging::log<phosphor::logging::level::ERR>(
222 "Invalid IANA number");
223 return ipmi::responseInvalidFieldRequest();
224 }
225
226 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
227
228 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqIana, respData))
229 {
230 return ipmi::responseUnspecifiedError();
231 }
232
233 std::vector<uint8_t> gpioState;
234 IanaType respIana;
235
236 auto r =
237 std::ranges::copy_n(respData.begin(), iana.size(), respIana.begin()).in;
238 std::copy(r, respData.end(), std::back_inserter(gpioState));
239
240 return ipmi::responseSuccess(respIana, gpioState);
Kumar Thangavelad049242020-08-31 22:27:33 +0530241}
242
Bonnie Lo41027b92022-12-16 16:21:08 +0800243//----------------------------------------------------------------------
244// ipmiOemSetHostPowerState (CMD_OEM_SET_HOST_POWER_STATE)
Manojkiran Eda519530b2024-06-17 11:46:15 +0530245// This Function will handle BIC incoming IPMI request for
Bonnie Lo41027b92022-12-16 16:21:08 +0800246// setting host current state for netfn=0x38 and cmd=0x0C
247// send the response back to the sender.
248//----------------------------------------------------------------------
249
Patrick Williams010dee02024-08-16 15:19:44 -0400250ipmi::RspType<IanaType> ipmiOemSetHostPowerState(
251 ipmi::Context::ptr ctx, IanaType reqIana, uint8_t status)
Bonnie Lo41027b92022-12-16 16:21:08 +0800252{
253 std::string targetUnit;
254
255 switch (static_cast<HostPowerState>(status))
256 {
257 case HostPowerState::HOST_POWER_ON:
258 targetUnit = "obmc-host-startmin@.target";
259 break;
260 case HostPowerState::HOST_POWER_OFF:
261 targetUnit = "obmc-host-stop@.target";
262 break;
263 default:
264 phosphor::logging::log<phosphor::logging::level::ERR>(
265 "IPMI ipmiOemHostPowerStatus power status error");
266 return ipmi::responseUnspecifiedError();
267 }
268
269 int mousePos = targetUnit.find('@');
270 targetUnit.insert(mousePos + 1, std::to_string(ctx->hostIdx + 1));
271
272 auto conn = getSdBus();
273 auto method = conn->new_method_call(systemdService, systemdObjPath,
274 systemdInterface, "StartUnit");
275 method.append(targetUnit);
276 method.append("replace");
277
278 try
279 {
280 conn->call_noreply(method);
281 }
282 catch (const sdbusplus::exception::SdBusError& e)
283 {
284 phosphor::logging::log<phosphor::logging::level::ERR>(
285 "IPMI ipmiOemHostPowerStatus Failed in call method",
286 phosphor::logging::entry("ERROR=%s", e.what()));
287 return ipmi::responseUnspecifiedError();
288 }
289
290 return ipmi::responseSuccess(reqIana);
291}
292
Kumar Thangavel05d0ce92022-11-17 17:53:57 +0530293//----------------------------------------------------------------------
294// ipmiOemGetBiosFlashSize (CMD_OEM_GET_FLASH_SIZE)
295// This Function will return the bios flash size
296// netfn=0x38 and cmd=0x19 send the response back to the sender.
297//----------------------------------------------------------------------
298
Patrick Williams010dee02024-08-16 15:19:44 -0400299ipmi::RspType<IanaType, flashSize> ipmiOemGetBiosFlashSize(
300 ipmi::Context::ptr ctx, IanaType ianaReq, uint8_t target)
Kumar Thangavel05d0ce92022-11-17 17:53:57 +0530301{
302 if (iana != ianaReq)
303 {
304 phosphor::logging::log<phosphor::logging::level::ERR>(
305 "Invalid IANA ID length received");
306 return ipmi::responseReqDataLenInvalid();
307 }
308
309 std::vector<uint8_t> respData;
310 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
311 std::vector<uint8_t> reqData(ianaReq.begin(), ianaReq.end());
312 reqData.emplace_back(target);
313
314 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
315 {
316 return ipmi::responseUnspecifiedError();
317 }
318
319 if (respData.size() != flashSizeRespLen)
320 {
321 phosphor::logging::log<phosphor::logging::level::ERR>(
322 "Invalid Response Data length received");
323 return ipmi::responseReqDataLenInvalid();
324 }
325
326 IanaType ianaResp;
327 std::copy_n(respData.begin(), ianaResp.size(), ianaResp.begin());
328
329 if (iana != ianaResp)
330 {
331 phosphor::logging::log<phosphor::logging::level::ERR>(
332 "Invalid IANA ID received");
333 return ipmi::responseInvalidCommand();
334 }
335
336 flashSize flashResp;
337 std::vector<uint8_t>::iterator respDataIter = respData.begin();
338 std::advance(respDataIter, ianaResp.size());
339 std::copy_n(respDataIter, flashResp.size(), flashResp.begin());
340
341 // sending the success response.
342 return ipmi::responseSuccess(ianaResp, flashResp);
343}
344
Jayashree Dhanapal6c931e42022-12-05 13:09:24 +0530345//----------------------------------------------------------------------
346// ipmiOemClearCmos (CMD_OEM_CLEAR_CMOS)
347// This Function will clear the CMOS.
348// netfn=0x38 and cmd=0x25
349//----------------------------------------------------------------------
350ipmi::RspType<IanaType> ipmiOemClearCmos(ipmi::Context::ptr ctx,
351 IanaType ianaReq)
352{
353 if (iana != ianaReq)
354 {
355 phosphor::logging::log<phosphor::logging::level::ERR>(
356 "Invalid request of IANA ID length received");
357 return ipmi::responseReqDataLenInvalid();
358 }
359
360 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
361
362 std::vector<uint8_t> respData;
363 std::vector<uint8_t> reqData(ianaReq.begin(), ianaReq.end());
364
365 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
366 {
367 return ipmi::responseUnspecifiedError();
368 }
369
370 if (respData.size() != iana.size())
371 {
372 return ipmi::responseReqDataLenInvalid();
373 }
374
375 IanaType resp;
376 std::copy_n(respData.begin(), resp.size(), resp.begin());
377
378 if (iana != resp)
379 {
380 phosphor::logging::log<phosphor::logging::level::ERR>(
381 "Invalid response of IANA ID received");
382 return ipmi::responseUnspecifiedError();
383 }
384
385 // sending the success response.
386 return ipmi::responseSuccess(resp);
387}
388
Willy Tue39f9392022-06-15 13:24:20 -0700389[[maybe_unused]] static void registerBICFunctions(void)
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +0530390{
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +0530391 phosphor::logging::log<phosphor::logging::level::INFO>(
392 "Registering BIC commands");
393
394 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
Bonnie Lo25b79bf2022-12-16 15:41:48 +0800395 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_BIC_INFO),
396 ipmi::Privilege::User, ipmiOemBicHandler);
397 ipmi::registerHandler(
398 ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
399 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SEND_POST_BUFFER_TO_BMC),
400 ipmi::Privilege::User, ipmiOemPostCodeHandler);
401 ipmi::registerHandler(
Delphine CC Chiu14ddea52023-06-06 09:43:44 +0800402 ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
403 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_1S_4BYTE_POST_BUF),
404 ipmi::Privilege::User, ipmiOemPostCodeHandler);
405 ipmi::registerHandler(
Bonnie Lo25b79bf2022-12-16 15:41:48 +0800406 ipmi::prioOemBase, ipmi::netFnOemFive,
407 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_BIC_GPIO_STATE),
408 ipmi::Privilege::User, ipmiOemGetBicGpioState);
Bonnie Lo41027b92022-12-16 16:21:08 +0800409 ipmi::registerHandler(
410 ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
411 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SET_HOST_POWER_STATE),
412 ipmi::Privilege::User, ipmiOemSetHostPowerState);
Kumar Thangavel05d0ce92022-11-17 17:53:57 +0530413 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
414 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_FLASH_SIZE),
415 ipmi::Privilege::User, ipmiOemGetBiosFlashSize);
Jayashree Dhanapal6c931e42022-12-05 13:09:24 +0530416 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
417 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_CLEAR_CMOS),
418 ipmi::Privilege::User, ipmiOemClearCmos);
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +0530419 return;
420}
421
422} // namespace ipmi