1 /** 2 * Copyright © 2021 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 extern "C" { 18 #include <libpdbg.h> 19 } 20 21 #include "fapi_data_process.hpp" 22 #include "pel.hpp" 23 #include "sbe_ffdc_handler.hpp" 24 #include "temporary_file.hpp" 25 26 #include <ekb/hwpf/fapi2/include/return_code_defs.H> 27 #include <fmt/format.h> 28 #include <libekb.H> 29 30 #include <new> 31 #include <phosphor-logging/log.hpp> 32 33 namespace openpower 34 { 35 namespace pels 36 { 37 namespace sbe 38 { 39 40 using namespace phosphor::logging; 41 42 SbeFFDC::SbeFFDC(const AdditionalData& aData, const PelFFDC& files) 43 { 44 log<level::INFO>("SBE FFDC processing requested"); 45 46 // SRC6 field in the additional data contains Processor position 47 // associated to the SBE FFDC 48 //"[0:15] chip position" 49 auto src6 = aData.getValue("SRC6"); 50 if (src6 == std::nullopt) 51 { 52 log<level::ERR>("Fail to extract SRC6 data: failing to get proc index"); 53 return; 54 } 55 try 56 { 57 procPos = std::stoi((src6.value()).substr(0, 4)); 58 } 59 catch (const std::exception& err) 60 { 61 log<level::ERR>( 62 fmt::format("Conversion failure errormsg({})", err.what()).c_str()); 63 return; 64 } 65 66 if (files.empty()) 67 { 68 log<level::INFO>("SbeFFDC : No files found, skipping ffdc processing"); 69 return; 70 } 71 72 for (const auto& file : files) 73 { 74 if ((file.format == UserDataFormat::custom) && 75 (file.subType == sbeFFDCSubType)) 76 { 77 // Process SBE file. 78 parse(file.fd); 79 } 80 } 81 } 82 83 void SbeFFDC::parse(int fd) 84 { 85 log<level::INFO>( 86 fmt::format("SBE FFDC file fd:({}), parsing started", fd).c_str()); 87 88 uint32_t ffdcBufOffset = 0; 89 uint32_t pktCount = 0; 90 sbeFfdcPacketType ffdcPkt; 91 92 // get SBE FFDC data. 93 auto ffdcData = util::readFD(fd); 94 if (ffdcData.empty()) 95 { 96 log<level::ERR>( 97 fmt::format("Empty SBE FFDC file fd:({}), skipping", fd).c_str()); 98 return; 99 } 100 101 while ((ffdcBufOffset < ffdcData.size()) && (sbeMaxFfdcPackets != pktCount)) 102 { 103 // Next un-extracted FFDC Packet 104 fapiFfdcBufType* ffdc = 105 reinterpret_cast<fapiFfdcBufType*>(ffdcData.data() + ffdcBufOffset); 106 auto magicBytes = ntohs(ffdc->magic_bytes); 107 auto lenWords = ntohs(ffdc->lengthinWords); 108 auto fapiRc = ntohl(ffdc->fapiRc); 109 110 auto msg = fmt::format("FFDC magic: {} length in words:{} Fapirc:{}", 111 magicBytes, lenWords, fapiRc); 112 log<level::INFO>(msg.c_str()); 113 114 if (magicBytes != ffdcMagicCode) 115 { 116 log<level::ERR>("Invalid FFDC magic code in Header: Skipping "); 117 return; 118 } 119 ffdcPkt.fapiRc = fapiRc; 120 // Not interested in the first 2 words (these are not ffdc) 121 auto pktLenWords = lenWords - (2 * ffdcPkgOneWord); 122 ffdcPkt.ffdcLengthInWords = pktLenWords; 123 if (pktLenWords) 124 { 125 // Memory freeing will be taking care by ffdcPkt structure 126 // destructor 127 ffdcPkt.ffdcData = new uint32_t[pktLenWords]; 128 memcpy(ffdcPkt.ffdcData, 129 ((reinterpret_cast<uint32_t*>(ffdc)) + 130 (2 * ffdcPkgOneWord)), // skip first 2 words 131 (pktLenWords * sizeof(uint32_t))); 132 } 133 else 134 { 135 log<level::ERR>("FFDC packet size is zero skipping"); 136 return; 137 } 138 139 // SBE FFDC processing is not required for SBE Plat errors RCs. 140 // Plat errors processing is driven by SBE provided user data 141 // plugins, which need to link with PEL tool infrastructure. 142 if (ffdcPkt.fapiRc != fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA) 143 { 144 process(ffdcPkt); 145 } 146 ffdcBufOffset += ffdc->lengthinWords; 147 ++pktCount; 148 } 149 if (pktCount == sbeMaxFfdcPackets) 150 { 151 log<level::ERR>(fmt::format("Received more than the limit of ({})" 152 " FFDC packets, processing only ({})", 153 sbeMaxFfdcPackets, pktCount) 154 .c_str()); 155 } 156 } 157 158 void SbeFFDC::process(const sbeFfdcPacketType& ffdcPkt) 159 { 160 using json = nlohmann::json; 161 162 // formated FFDC data structure after FFDC packet processing 163 FFDC ffdc; 164 165 if (!pdbg_targets_init(NULL)) 166 { 167 log<level::ERR>("pdbg_targets_init failed, skipping ffdc processing"); 168 return; 169 } 170 171 if (libekb_init()) 172 { 173 log<level::ERR>("libekb_init failed, skipping ffdc processing"); 174 return; 175 } 176 177 try 178 { 179 // libekb provided wrapper function to convert SBE FFDC 180 // in to known ffdc structure. 181 libekb_get_sbe_ffdc(ffdc, ffdcPkt, procPos); 182 } 183 catch (...) 184 { 185 log<level::ERR>("libekb_get_sbe_ffdc failed, skipping ffdc processing"); 186 return; 187 } 188 189 // To store callouts details in json format as per pel expectation. 190 json pelJSONFmtCalloutDataList; 191 pelJSONFmtCalloutDataList = json::array(); 192 193 // To store other user data from FFDC. 194 openpower::pels::phal::FFDCData ffdcUserData; 195 196 // Get FFDC and required info to include in PEL 197 openpower::pels::phal::convertFAPItoPELformat( 198 ffdc, pelJSONFmtCalloutDataList, ffdcUserData); 199 200 // Get callout information and sore in to file. 201 auto calloutData = pelJSONFmtCalloutDataList.dump(); 202 util::TemporaryFile ffdcFile(calloutData.c_str(), calloutData.size()); 203 204 // Create json callout type pel FFDC file structre. 205 PelFFDCfile pf; 206 pf.format = openpower::pels::UserDataFormat::json; 207 pf.subType = openpower::pels::jsonCalloutSubtype; 208 pf.version = 0x01; 209 pf.fd = ffdcFile.getFd(); 210 ffdcFiles.push_back(pf); 211 212 // save the file path to delete the file after usage. 213 paths.push_back(ffdcFile.getPath()); 214 215 // Format ffdc user data and create new file. 216 std::string data; 217 for (auto& d : ffdcUserData) 218 { 219 data += d.first + " = " + d.second + "\n"; 220 } 221 util::TemporaryFile pelDataFile(data.c_str(), data.size()); 222 PelFFDCfile pdf; 223 pdf.format = openpower::pels::UserDataFormat::text; 224 pdf.version = 0x01; 225 pdf.fd = pelDataFile.getFd(); 226 ffdcFiles.push_back(pdf); 227 228 paths.push_back(pelDataFile.getPath()); 229 } 230 231 } // namespace sbe 232 } // namespace pels 233 } // namespace openpower 234