xref: /openbmc/fb-ipmi-oem/src/appcommands.cpp (revision 666a4d95)
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.h>
19 
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <nlohmann/json.hpp>
24 #include <commandutils.hpp>
25 #include <iostream>
26 #include <iomanip>
27 #include <sstream>
28 #include <fstream>
29 #include <phosphor-logging/log.hpp>
30 #include <sdbusplus/message/types.hpp>
31 #include <appcommands.hpp>
32 
33 namespace ipmi
34 {
35 
36 static void registerAPPFunctions() __attribute__((constructor));
37 static constexpr size_t GUID_SIZE = 16;
38 // TODO Make offset and location runtime configurable to ensure we
39 // can make each define their own locations.
40 static constexpr off_t OFFSET_SYS_GUID = 0x17F0;
41 static constexpr off_t OFFSET_DEV_GUID = 0x1800;
42 static constexpr const char *FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom";
43 
44 // TODO: Need to store this info after identifying proper storage
45 static uint8_t globEna = 0x09;
46 static SysInfoParam sysInfoParams;
47 nlohmann::json appData;
48 
49 void printGUID(uint8_t *guid, off_t offset)
50 {
51     std::cout << "Read GUID from offset : " << offset << " :\n";
52     for (int i = 0; i < GUID_SIZE; i++)
53     {
54         int data = guid[i];
55         std::cout << std::hex << data << " ";
56     }
57     std::cout << std::endl;
58 }
59 
60 int getGUID(off_t offset, uint8_t *guid)
61 {
62     int fd = -1;
63     ssize_t bytes_rd;
64     int ret = 0;
65 
66     errno = 0;
67 
68     // Check if file is present
69     if (access(FRU_EEPROM, F_OK) == -1)
70     {
71         std::cerr << "Unable to access: " << FRU_EEPROM << std::endl;
72         return errno;
73     }
74 
75     // Open the file
76     fd = open(FRU_EEPROM, O_RDONLY);
77     if (fd == -1)
78     {
79         std::cerr << "Unable to open: " << FRU_EEPROM << std::endl;
80         return errno;
81     }
82 
83     // seek to the offset
84     lseek(fd, offset, SEEK_SET);
85 
86     // Read bytes from location
87     bytes_rd = read(fd, guid, GUID_SIZE);
88     if (bytes_rd != GUID_SIZE)
89     {
90         phosphor::logging::log<phosphor::logging::level::ERR>(
91             "GUID read data from EEPROM failed");
92         ret = errno;
93     }
94     else
95     {
96         printGUID(guid, offset);
97     }
98     close(fd);
99     return ret;
100 }
101 
102 int getSystemGUID(uint8_t *guid)
103 {
104     return getGUID(OFFSET_SYS_GUID, guid);
105 }
106 
107 int getDeviceGUID(uint8_t *guid)
108 {
109     return getGUID(OFFSET_DEV_GUID, guid);
110 }
111 
112 //----------------------------------------------------------------------
113 // Get Self Test Results (IPMI/Section 20.4) (CMD_APP_GET_SELFTEST_RESULTS)
114 //----------------------------------------------------------------------
115 ipmi_ret_t ipmiAppGetSTResults(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
116                                ipmi_request_t request, ipmi_response_t response,
117                                ipmi_data_len_t data_len, ipmi_context_t context)
118 {
119     uint8_t *res = reinterpret_cast<uint8_t *>(response);
120 
121     // TODO: Following data needs to be updated based on self-test results
122     *res++ = 0x55; // Self-Test result
123     *res++ = 0x00; // Extra error info in case of failure
124 
125     *data_len = 2;
126 
127     return IPMI_CC_OK;
128 }
129 
130 //----------------------------------------------------------------------
131 // Manufacturing Test On (IPMI/Section 20.5) (CMD_APP_MFR_TEST_ON)
132 //----------------------------------------------------------------------
133 ipmi_ret_t ipmiAppMfrTestOn(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
134                             ipmi_request_t request, ipmi_response_t response,
135                             ipmi_data_len_t data_len, ipmi_context_t context)
136 {
137     uint8_t *req = reinterpret_cast<uint8_t *>(request);
138     std::string mfrTest = "sled-cycle";
139 
140     if (!memcmp(req, mfrTest.data(), mfrTest.length()) &&
141         (*data_len == mfrTest.length()))
142     {
143         /* sled-cycle the BMC */
144         system("/usr/sbin/power-util mb sled-cycle");
145     }
146     else
147     {
148         return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
149     }
150 
151     *data_len = 0;
152 
153     return IPMI_CC_OK;
154 }
155 
156 //----------------------------------------------------------------------
157 // Get Device GUID (CMD_APP_GET_DEV_GUID)
158 //----------------------------------------------------------------------
159 ipmi_ret_t ipmiAppGetDevGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
160                              ipmi_request_t request, ipmi_response_t response,
161                              ipmi_data_len_t data_len, ipmi_context_t context)
162 {
163     uint8_t *res = reinterpret_cast<uint8_t *>(response);
164 
165     if (getDeviceGUID(res))
166     {
167         return IPMI_CC_UNSPECIFIED_ERROR;
168     }
169     *data_len = GUID_SIZE;
170 
171     return IPMI_CC_OK;
172 }
173 
174 //----------------------------------------------------------------------
175 // Set Global Enables (CMD_APP_SET_GLOBAL_ENABLES)
176 //----------------------------------------------------------------------
177 ipmi_ret_t ipmiAppSetGlobalEnables(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
178                                    ipmi_request_t request,
179                                    ipmi_response_t response,
180                                    ipmi_data_len_t data_len,
181                                    ipmi_context_t context)
182 {
183     uint8_t *req = reinterpret_cast<uint8_t *>(request);
184 
185     globEna = *req;
186     *data_len = 0;
187 
188     return IPMI_CC_OK;
189 }
190 
191 //----------------------------------------------------------------------
192 // Get Global Enables (CMD_APP_GET_GLOBAL_ENABLES)
193 //----------------------------------------------------------------------
194 ipmi_ret_t ipmiAppGetGlobalEnables(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195                                    ipmi_request_t request,
196                                    ipmi_response_t response,
197                                    ipmi_data_len_t data_len,
198                                    ipmi_context_t context)
199 {
200     uint8_t *res = reinterpret_cast<uint8_t *>(response);
201 
202     *data_len = 1;
203     *res++ = globEna;
204 
205     return IPMI_CC_OK;
206 }
207 
208 //----------------------------------------------------------------------
209 // Clear Message flags (IPMI/Section 22.3) (CMD_APP_CLEAR_MESSAGE_FLAGS)
210 //----------------------------------------------------------------------
211 ipmi_ret_t ipmiAppClearMsgFlags(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
212                                 ipmi_request_t request,
213                                 ipmi_response_t response,
214                                 ipmi_data_len_t data_len,
215                                 ipmi_context_t context)
216 {
217     // Do Nothing and just return success
218     *data_len = 0;
219 
220     return IPMI_CC_OK;
221 }
222 
223 //----------------------------------------------------------------------
224 // Get System GUID (CMD_APP_GET_SYS_GUID)
225 //----------------------------------------------------------------------
226 ipmi_ret_t ipmiAppGetSysGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
227                              ipmi_request_t request, ipmi_response_t response,
228                              ipmi_data_len_t data_len, ipmi_context_t context)
229 {
230     uint8_t *res = reinterpret_cast<uint8_t *>(response);
231     if (getSystemGUID(res))
232     {
233         return IPMI_CC_UNSPECIFIED_ERROR;
234     }
235     *data_len = GUID_SIZE;
236     return IPMI_CC_OK;
237 }
238 
239 //----------------------------------------------------------------------
240 // Platform specific functions for storing app data
241 //----------------------------------------------------------------------
242 
243 void flush_app_data()
244 {
245     std::ofstream file(JSON_DATA_FILE);
246     file << appData;
247     return;
248 }
249 
250 static int platSetSysFWVer(uint8_t *ver)
251 {
252     std::stringstream ss;
253     int i;
254 
255     /* TODO: implement byte 1: Set selector
256      * byte 2: encodeing, currently only supported
257      * ASCII which is value 0, UTF and unicode are
258      * not supported yet.
259      */
260     if (ver[1] & 0x0f)
261         return -1;
262 
263     for (i = 3; i < 3 + ver[2]; i++)
264     {
265         ss << (char)ver[i];
266     }
267 
268     appData[KEY_SYSFW_VER] = ss.str();
269     flush_app_data();
270 
271     return 0;
272 }
273 
274 static int platGetSysFWVer(uint8_t *ver)
275 {
276     std::string str = appData[KEY_SYSFW_VER].get<std::string>();
277     int len;
278 
279     *ver++ = 0; // byte 1: Set selector not supported
280     *ver++ = 0; // byte 2: Only ASCII supported
281 
282     len = str.length();
283     *ver++ = len;
284     memcpy(ver, str.data(), len);
285 
286     return (len + 3);
287 }
288 
289 //----------------------------------------------------------------------
290 // Set Sys Info Params (IPMI/Sec 22.14a) (CMD_APP_SET_SYS_INFO_PARAMS)
291 //----------------------------------------------------------------------
292 ipmi_ret_t ipmiAppSetSysInfoParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
293                                    ipmi_request_t request,
294                                    ipmi_response_t response,
295                                    ipmi_data_len_t data_len,
296                                    ipmi_context_t context)
297 {
298     uint8_t *req = reinterpret_cast<uint8_t *>(request);
299 
300     uint8_t param = req[0];
301     uint8_t req_len = *data_len;
302 
303     *data_len = 0;
304 
305     switch (param)
306     {
307         case SYS_INFO_PARAM_SET_IN_PROG:
308             sysInfoParams.set_in_prog = req[1];
309             break;
310         case SYS_INFO_PARAM_SYSFW_VER:
311             memcpy(sysInfoParams.sysfw_ver, &req[1], SIZE_SYSFW_VER);
312             if (platSetSysFWVer(sysInfoParams.sysfw_ver))
313                 return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
314             break;
315         case SYS_INFO_PARAM_SYS_NAME:
316             memcpy(sysInfoParams.sys_name, &req[1], SIZE_SYS_NAME);
317             break;
318         case SYS_INFO_PARAM_PRI_OS_NAME:
319             memcpy(sysInfoParams.pri_os_name, &req[1], SIZE_OS_NAME);
320             break;
321         case SYS_INFO_PARAM_PRESENT_OS_NAME:
322             memcpy(sysInfoParams.present_os_name, &req[1], SIZE_OS_NAME);
323             break;
324         case SYS_INFO_PARAM_PRESENT_OS_VER:
325             memcpy(sysInfoParams.present_os_ver, &req[1], SIZE_OS_VER);
326             break;
327         case SYS_INFO_PARAM_BMC_URL:
328             memcpy(sysInfoParams.bmc_url, &req[1], SIZE_BMC_URL);
329             break;
330         case SYS_INFO_PARAM_OS_HV_URL:
331             memcpy(sysInfoParams.os_hv_url, &req[1], SIZE_OS_HV_URL);
332             break;
333         case SYS_INFO_PARAM_BIOS_CURRENT_BOOT_LIST:
334             memcpy(sysInfoParams.bios_current_boot_list, &req[1], req_len);
335             appData[KEY_BIOS_BOOT_LEN] = req_len;
336             flush_app_data();
337             break;
338         case SYS_INFO_PARAM_BIOS_FIXED_BOOT_DEVICE:
339             if (SIZE_BIOS_FIXED_BOOT_DEVICE != req_len)
340                 break;
341             memcpy(sysInfoParams.bios_fixed_boot_device, &req[1],
342                    SIZE_BIOS_FIXED_BOOT_DEVICE);
343             break;
344         case SYS_INFO_PARAM_BIOS_RSTR_DFLT_SETTING:
345             if (SIZE_BIOS_RSTR_DFLT_SETTING != req_len)
346                 break;
347             memcpy(sysInfoParams.bios_rstr_dflt_setting, &req[1],
348                    SIZE_BIOS_RSTR_DFLT_SETTING);
349             break;
350         case SYS_INFO_PARAM_LAST_BOOT_TIME:
351             if (SIZE_LAST_BOOT_TIME != req_len)
352                 break;
353             memcpy(sysInfoParams.last_boot_time, &req[1], SIZE_LAST_BOOT_TIME);
354             break;
355         default:
356             return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
357             break;
358     }
359 
360     return IPMI_CC_OK;
361 }
362 
363 //----------------------------------------------------------------------
364 // Get Sys Info Params (IPMI/Sec 22.14b) (CMD_APP_GET_SYS_INFO_PARAMS)
365 //----------------------------------------------------------------------
366 ipmi_ret_t ipmiAppGetSysInfoParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
367                                    ipmi_request_t request,
368                                    ipmi_response_t response,
369                                    ipmi_data_len_t data_len,
370                                    ipmi_context_t context)
371 {
372     uint8_t *req = reinterpret_cast<uint8_t *>(request);
373     uint8_t *res = reinterpret_cast<uint8_t *>(response);
374 
375     uint8_t param = req[1];
376     uint8_t len;
377 
378     *res++ = 1; // Parameter revision
379     *data_len = 1;
380 
381     switch (param)
382     {
383         case SYS_INFO_PARAM_SET_IN_PROG:
384             *res++ = sysInfoParams.set_in_prog;
385             *data_len += 1;
386             break;
387         case SYS_INFO_PARAM_SYSFW_VER:
388             if ((len = platGetSysFWVer(res)) < 0)
389                 return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
390             *data_len += SIZE_SYSFW_VER;
391             break;
392         case SYS_INFO_PARAM_SYS_NAME:
393             memcpy(res, sysInfoParams.sys_name, SIZE_SYS_NAME);
394             *data_len += SIZE_SYS_NAME;
395             break;
396         case SYS_INFO_PARAM_PRI_OS_NAME:
397             memcpy(res, sysInfoParams.pri_os_name, SIZE_OS_NAME);
398             *data_len += SIZE_OS_NAME;
399             break;
400         case SYS_INFO_PARAM_PRESENT_OS_NAME:
401             memcpy(res, sysInfoParams.present_os_name, SIZE_OS_NAME);
402             *data_len += SIZE_OS_NAME;
403             break;
404         case SYS_INFO_PARAM_PRESENT_OS_VER:
405             memcpy(res, sysInfoParams.present_os_ver, SIZE_OS_VER);
406             *data_len += SIZE_OS_VER;
407             break;
408         case SYS_INFO_PARAM_BMC_URL:
409             memcpy(res, sysInfoParams.bmc_url, SIZE_BMC_URL);
410             *data_len += SIZE_BMC_URL;
411             break;
412         case SYS_INFO_PARAM_OS_HV_URL:
413             memcpy(res, sysInfoParams.os_hv_url, SIZE_OS_HV_URL);
414             *data_len += SIZE_OS_HV_URL;
415             break;
416         case SYS_INFO_PARAM_BIOS_CURRENT_BOOT_LIST:
417             len = appData[KEY_BIOS_BOOT_LEN].get<uint8_t>();
418             memcpy(res, sysInfoParams.bios_current_boot_list, len);
419             *data_len += len;
420             break;
421         case SYS_INFO_PARAM_BIOS_FIXED_BOOT_DEVICE:
422             memcpy(res, sysInfoParams.bios_fixed_boot_device,
423                    SIZE_BIOS_FIXED_BOOT_DEVICE);
424             *data_len += SIZE_BIOS_FIXED_BOOT_DEVICE;
425             break;
426         case SYS_INFO_PARAM_BIOS_RSTR_DFLT_SETTING:
427             memcpy(res, sysInfoParams.bios_rstr_dflt_setting,
428                    SIZE_BIOS_RSTR_DFLT_SETTING);
429             *data_len += SIZE_BIOS_RSTR_DFLT_SETTING;
430             break;
431         case SYS_INFO_PARAM_LAST_BOOT_TIME:
432             memcpy(res, sysInfoParams.last_boot_time, SIZE_LAST_BOOT_TIME);
433             *data_len += SIZE_LAST_BOOT_TIME;
434             break;
435         default:
436             return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
437             break;
438     }
439     return IPMI_CC_OK;
440 }
441 
442 void registerAPPFunctions()
443 {
444     /* Get App data stored in json file */
445     std::ifstream file(JSON_DATA_FILE);
446     if (file)
447         file >> appData;
448 
449     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_GET_SELFTEST_RESULTS, NULL,
450                          ipmiAppGetSTResults,
451                          PRIVILEGE_USER); // Get Self Test Results
452     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_MFR_TEST_ON, NULL,
453                          ipmiAppMfrTestOn,
454                          PRIVILEGE_USER); // Manufacturing Test On
455     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_GET_DEV_GUID, NULL,
456                          ipmiAppGetDevGUID,
457                          PRIVILEGE_USER); // Get Device GUID
458     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_SET_GLOBAL_ENABLES, NULL,
459                          ipmiAppSetGlobalEnables,
460                          PRIVILEGE_USER); // Set Global Enables
461     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_GET_GLOBAL_ENABLES, NULL,
462                          ipmiAppGetGlobalEnables,
463                          PRIVILEGE_USER); // Get Global Enables
464     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_CLEAR_MESSAGE_FLAGS, NULL,
465                          ipmiAppClearMsgFlags,
466                          PRIVILEGE_USER); // Clear Message flags
467     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_GET_SYS_GUID, NULL,
468                          ipmiAppGetSysGUID,
469                          PRIVILEGE_USER); // Get System GUID
470     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_SET_SYS_INFO_PARAMS, NULL,
471                          ipmiAppSetSysInfoParams,
472                          PRIVILEGE_USER); // Set Sys Info Params
473     ipmiPrintAndRegister(NETFUN_APP, CMD_APP_GET_SYS_INFO_PARAMS, NULL,
474                          ipmiAppGetSysInfoParams,
475                          PRIVILEGE_USER); // Get Sys Info Params
476     return;
477 }
478 
479 } // namespace ipmi
480