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