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