blob: ed3f6f83800216dead1eca5f40b04f2f4681e447 [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)
153// This Function will handle BIC incomming 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
Bonnie Lo25b79bf2022-12-16 15:41:48 +0800157ipmi::RspType<IanaType> ipmiOemPostCodeHandler(ipmi::Context::ptr ctx,
158 IanaType reqIana,
159 uint8_t dataLen,
160 std::vector<uint8_t> data)
Kumar Thangavelad049242020-08-31 22:27:33 +0530161{
162 // creating bus connection
163 auto conn = getSdBus();
164
Delphine CC Chiu14ddea52023-06-06 09:43:44 +0800165 auto hostId = findHost(ctx->hostIdx);
166 if (!hostId)
167 {
168 lg2::error("Invalid Host Id received");
169 return ipmi::responseInvalidCommand();
170 }
171 dimmLoopPatternDetection(*hostId, data);
172
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800173 using postcode_t = std::tuple<uint64_t, std::vector<uint8_t>>;
Manojkiran Edac723d6a2021-03-11 14:53:32 +0530174
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800175 std::string dbusObjStr = dbusObj + std::to_string((ctx->hostIdx + 1));
176
177 for (unsigned int index = 0; index < dataLen; index++)
178 {
179 uint64_t primaryPostCode = static_cast<uint64_t>(data[index]);
Kumar Thangavel0fcfbee2021-04-16 12:38:20 +0530180 auto postCode = postcode_t(primaryPostCode, {});
Kumar Thangavelad049242020-08-31 22:27:33 +0530181
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800182 try
183 {
184 auto method = conn->new_method_call(
185 "xyz.openbmc_project.State.Boot.Raw", dbusObjStr.c_str(),
186 "org.freedesktop.DBus.Properties", "Set");
Kumar Thangavelad049242020-08-31 22:27:33 +0530187
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800188 // Adding paramters to method call
189 method.append(dbusService, "Value",
190 std::variant<postcode_t>(postCode));
Kumar Thangavelad049242020-08-31 22:27:33 +0530191
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800192 // Invoke method call function
193 auto reply = conn->call(method);
194 }
Kumar Thangavelad049242020-08-31 22:27:33 +0530195
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800196 catch (std::exception& e)
197 {
198 phosphor::logging::log<phosphor::logging::level::ERR>(
199 "post code handler error\n");
Kumar Thangavelad049242020-08-31 22:27:33 +0530200
Bonnie Lod8ef7b32022-10-24 16:42:42 +0800201 // sending the Error response
202 return ipmi::responseResponseError();
203 }
Kumar Thangavelad049242020-08-31 22:27:33 +0530204 }
Kumar Thangavelad049242020-08-31 22:27:33 +0530205
Bonnie Lo25b79bf2022-12-16 15:41:48 +0800206 return ipmi::responseSuccess(reqIana);
207}
208
209//----------------------------------------------------------------------
210// ipmiOemGetBicGpioState (CMD_OEM_GET_BIC_GPIO_STATE)
211// This Function will handle BIC GPIO stats for
212// netfn=0x38 and cmd=0x03 send the response back to the sender.
213//----------------------------------------------------------------------
214
215ipmi::RspType<IanaType, std::vector<uint8_t>>
216 ipmiOemGetBicGpioState(ipmi::Context::ptr ctx, std::vector<uint8_t> reqIana)
217{
218 std::vector<uint8_t> respData;
219
220 if (std::equal(reqIana.begin(), reqIana.end(), iana.begin()) == false)
221 {
222 phosphor::logging::log<phosphor::logging::level::ERR>(
223 "Invalid IANA number");
224 return ipmi::responseInvalidFieldRequest();
225 }
226
227 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
228
229 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqIana, respData))
230 {
231 return ipmi::responseUnspecifiedError();
232 }
233
234 std::vector<uint8_t> gpioState;
235 IanaType respIana;
236
237 auto r =
238 std::ranges::copy_n(respData.begin(), iana.size(), respIana.begin()).in;
239 std::copy(r, respData.end(), std::back_inserter(gpioState));
240
241 return ipmi::responseSuccess(respIana, gpioState);
Kumar Thangavelad049242020-08-31 22:27:33 +0530242}
243
Bonnie Lo41027b92022-12-16 16:21:08 +0800244//----------------------------------------------------------------------
245// ipmiOemSetHostPowerState (CMD_OEM_SET_HOST_POWER_STATE)
246// This Function will handle BIC incomming IPMI request for
247// setting host current state for netfn=0x38 and cmd=0x0C
248// send the response back to the sender.
249//----------------------------------------------------------------------
250
251ipmi::RspType<IanaType> ipmiOemSetHostPowerState(ipmi::Context::ptr ctx,
252 IanaType reqIana,
253 uint8_t status)
254{
255 std::string targetUnit;
256
257 switch (static_cast<HostPowerState>(status))
258 {
259 case HostPowerState::HOST_POWER_ON:
260 targetUnit = "obmc-host-startmin@.target";
261 break;
262 case HostPowerState::HOST_POWER_OFF:
263 targetUnit = "obmc-host-stop@.target";
264 break;
265 default:
266 phosphor::logging::log<phosphor::logging::level::ERR>(
267 "IPMI ipmiOemHostPowerStatus power status error");
268 return ipmi::responseUnspecifiedError();
269 }
270
271 int mousePos = targetUnit.find('@');
272 targetUnit.insert(mousePos + 1, std::to_string(ctx->hostIdx + 1));
273
274 auto conn = getSdBus();
275 auto method = conn->new_method_call(systemdService, systemdObjPath,
276 systemdInterface, "StartUnit");
277 method.append(targetUnit);
278 method.append("replace");
279
280 try
281 {
282 conn->call_noreply(method);
283 }
284 catch (const sdbusplus::exception::SdBusError& e)
285 {
286 phosphor::logging::log<phosphor::logging::level::ERR>(
287 "IPMI ipmiOemHostPowerStatus Failed in call method",
288 phosphor::logging::entry("ERROR=%s", e.what()));
289 return ipmi::responseUnspecifiedError();
290 }
291
292 return ipmi::responseSuccess(reqIana);
293}
294
Kumar Thangavel05d0ce92022-11-17 17:53:57 +0530295//----------------------------------------------------------------------
296// ipmiOemGetBiosFlashSize (CMD_OEM_GET_FLASH_SIZE)
297// This Function will return the bios flash size
298// netfn=0x38 and cmd=0x19 send the response back to the sender.
299//----------------------------------------------------------------------
300
301ipmi::RspType<IanaType, flashSize>
302 ipmiOemGetBiosFlashSize(ipmi::Context::ptr ctx, IanaType ianaReq,
303 uint8_t target)
304{
305 if (iana != ianaReq)
306 {
307 phosphor::logging::log<phosphor::logging::level::ERR>(
308 "Invalid IANA ID length received");
309 return ipmi::responseReqDataLenInvalid();
310 }
311
312 std::vector<uint8_t> respData;
313 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
314 std::vector<uint8_t> reqData(ianaReq.begin(), ianaReq.end());
315 reqData.emplace_back(target);
316
317 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
318 {
319 return ipmi::responseUnspecifiedError();
320 }
321
322 if (respData.size() != flashSizeRespLen)
323 {
324 phosphor::logging::log<phosphor::logging::level::ERR>(
325 "Invalid Response Data length received");
326 return ipmi::responseReqDataLenInvalid();
327 }
328
329 IanaType ianaResp;
330 std::copy_n(respData.begin(), ianaResp.size(), ianaResp.begin());
331
332 if (iana != ianaResp)
333 {
334 phosphor::logging::log<phosphor::logging::level::ERR>(
335 "Invalid IANA ID received");
336 return ipmi::responseInvalidCommand();
337 }
338
339 flashSize flashResp;
340 std::vector<uint8_t>::iterator respDataIter = respData.begin();
341 std::advance(respDataIter, ianaResp.size());
342 std::copy_n(respDataIter, flashResp.size(), flashResp.begin());
343
344 // sending the success response.
345 return ipmi::responseSuccess(ianaResp, flashResp);
346}
347
Jayashree Dhanapal6c931e42022-12-05 13:09:24 +0530348//----------------------------------------------------------------------
349// ipmiOemClearCmos (CMD_OEM_CLEAR_CMOS)
350// This Function will clear the CMOS.
351// netfn=0x38 and cmd=0x25
352//----------------------------------------------------------------------
353ipmi::RspType<IanaType> ipmiOemClearCmos(ipmi::Context::ptr ctx,
354 IanaType ianaReq)
355{
356 if (iana != ianaReq)
357 {
358 phosphor::logging::log<phosphor::logging::level::ERR>(
359 "Invalid request of IANA ID length received");
360 return ipmi::responseReqDataLenInvalid();
361 }
362
363 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
364
365 std::vector<uint8_t> respData;
366 std::vector<uint8_t> reqData(ianaReq.begin(), ianaReq.end());
367
368 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
369 {
370 return ipmi::responseUnspecifiedError();
371 }
372
373 if (respData.size() != iana.size())
374 {
375 return ipmi::responseReqDataLenInvalid();
376 }
377
378 IanaType resp;
379 std::copy_n(respData.begin(), resp.size(), resp.begin());
380
381 if (iana != resp)
382 {
383 phosphor::logging::log<phosphor::logging::level::ERR>(
384 "Invalid response of IANA ID received");
385 return ipmi::responseUnspecifiedError();
386 }
387
388 // sending the success response.
389 return ipmi::responseSuccess(resp);
390}
391
Willy Tue39f9392022-06-15 13:24:20 -0700392[[maybe_unused]] static void registerBICFunctions(void)
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +0530393{
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +0530394 phosphor::logging::log<phosphor::logging::level::INFO>(
395 "Registering BIC commands");
396
397 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
Bonnie Lo25b79bf2022-12-16 15:41:48 +0800398 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_BIC_INFO),
399 ipmi::Privilege::User, ipmiOemBicHandler);
400 ipmi::registerHandler(
401 ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
402 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SEND_POST_BUFFER_TO_BMC),
403 ipmi::Privilege::User, ipmiOemPostCodeHandler);
404 ipmi::registerHandler(
Delphine CC Chiu14ddea52023-06-06 09:43:44 +0800405 ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
406 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_1S_4BYTE_POST_BUF),
407 ipmi::Privilege::User, ipmiOemPostCodeHandler);
408 ipmi::registerHandler(
Bonnie Lo25b79bf2022-12-16 15:41:48 +0800409 ipmi::prioOemBase, ipmi::netFnOemFive,
410 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_BIC_GPIO_STATE),
411 ipmi::Privilege::User, ipmiOemGetBicGpioState);
Bonnie Lo41027b92022-12-16 16:21:08 +0800412 ipmi::registerHandler(
413 ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
414 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SET_HOST_POWER_STATE),
415 ipmi::Privilege::User, ipmiOemSetHostPowerState);
Kumar Thangavel05d0ce92022-11-17 17:53:57 +0530416 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
417 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_FLASH_SIZE),
418 ipmi::Privilege::User, ipmiOemGetBiosFlashSize);
Jayashree Dhanapal6c931e42022-12-05 13:09:24 +0530419 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
420 static_cast<Cmd>(fb_bic_cmds::CMD_OEM_CLEAR_CMOS),
421 ipmi::Privilege::User, ipmiOemClearCmos);
Kumar Thangavel41ad4ff2020-06-11 10:31:07 +0530422 return;
423}
424
425} // namespace ipmi