140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 38d2f868cSEd Tanous #pragma once 48d2f868cSEd Tanous 5*d7857201SEd Tanous #include "bmcweb_config.h" 6*d7857201SEd Tanous 78d2f868cSEd Tanous #include "app.hpp" 8*d7857201SEd Tanous #include "async_resp.hpp" 9*d7857201SEd Tanous #include "dbus_singleton.hpp" 10deae6a78SEd Tanous #include "dbus_utility.hpp" 11*d7857201SEd Tanous #include "error_messages.hpp" 128d2f868cSEd Tanous #include "generated/enums/log_service.hpp" 13*d7857201SEd Tanous #include "http_request.hpp" 14*d7857201SEd Tanous #include "http_utility.hpp" 15*d7857201SEd Tanous #include "logging.hpp" 168d2f868cSEd Tanous #include "query.hpp" 17*d7857201SEd Tanous #include "registries.hpp" 188d2f868cSEd Tanous #include "registries/privilege_registry.hpp" 19*d7857201SEd Tanous #include "str_utility.hpp" 20*d7857201SEd Tanous #include "utility.hpp" 21*d7857201SEd Tanous #include "utils/hex_utils.hpp" 22*d7857201SEd Tanous #include "utils/query_param.hpp" 238d2f868cSEd Tanous #include "utils/time_utils.hpp" 248d2f868cSEd Tanous 25*d7857201SEd Tanous #include <asm-generic/errno.h> 26*d7857201SEd Tanous 27*d7857201SEd Tanous #include <boost/beast/http/field.hpp> 28*d7857201SEd Tanous #include <boost/beast/http/status.hpp> 29*d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 30*d7857201SEd Tanous #include <boost/container/flat_map.hpp> 31*d7857201SEd Tanous #include <boost/url/format.hpp> 32*d7857201SEd Tanous 33*d7857201SEd Tanous #include <algorithm> 34*d7857201SEd Tanous #include <array> 35*d7857201SEd Tanous #include <charconv> 36*d7857201SEd Tanous #include <cstddef> 378d2f868cSEd Tanous #include <cstdint> 38*d7857201SEd Tanous #include <format> 39*d7857201SEd Tanous #include <functional> 40*d7857201SEd Tanous #include <iomanip> 41*d7857201SEd Tanous #include <ios> 428d2f868cSEd Tanous #include <memory> 43*d7857201SEd Tanous #include <sstream> 44*d7857201SEd Tanous #include <string> 458d2f868cSEd Tanous #include <string_view> 46*d7857201SEd Tanous #include <system_error> 47*d7857201SEd Tanous #include <tuple> 488d2f868cSEd Tanous #include <utility> 498d2f868cSEd Tanous #include <vector> 508d2f868cSEd Tanous 518d2f868cSEd Tanous namespace redfish 528d2f868cSEd Tanous { 5334fe470aSEd Tanous 5434fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesGet( 5534fe470aSEd Tanous App& app, const crow::Request& req, 568d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5734fe470aSEd Tanous const std::string& systemName) 5834fe470aSEd Tanous { 598d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 608d2f868cSEd Tanous { 618d2f868cSEd Tanous return; 628d2f868cSEd Tanous } 638d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 648d2f868cSEd Tanous { 658d2f868cSEd Tanous // Option currently returns no systems. TBD 668d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 678d2f868cSEd Tanous systemName); 688d2f868cSEd Tanous return; 698d2f868cSEd Tanous } 708d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 718d2f868cSEd Tanous { 728d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 738d2f868cSEd Tanous systemName); 748d2f868cSEd Tanous return; 758d2f868cSEd Tanous } 768d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 778d2f868cSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes", 788d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 7934fe470aSEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 808d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 818d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 828d2f868cSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 838d2f868cSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 848d2f868cSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 8534fe470aSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 8634fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 878d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 888d2f868cSEd Tanous 898d2f868cSEd Tanous std::pair<std::string, std::string> redfishDateTimeOffset = 908d2f868cSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 918d2f868cSEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 928d2f868cSEd Tanous asyncResp->res.jsonValue["DateTimeLocalOffset"] = 938d2f868cSEd Tanous redfishDateTimeOffset.second; 948d2f868cSEd Tanous 9534fe470aSEd Tanous asyncResp->res 9634fe470aSEd Tanous .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = std::format( 978d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog", 988d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 998d2f868cSEd Tanous } 1008d2f868cSEd Tanous 10134fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesPost( 10234fe470aSEd Tanous App& app, const crow::Request& req, 1038d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10434fe470aSEd Tanous const std::string& systemName) 10534fe470aSEd Tanous { 1068d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1078d2f868cSEd Tanous { 1088d2f868cSEd Tanous return; 1098d2f868cSEd Tanous } 1108d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1118d2f868cSEd Tanous { 1128d2f868cSEd Tanous // Option currently returns no systems. TBD 1138d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1148d2f868cSEd Tanous systemName); 1158d2f868cSEd Tanous return; 1168d2f868cSEd Tanous } 1178d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 1188d2f868cSEd Tanous { 1198d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1208d2f868cSEd Tanous systemName); 1218d2f868cSEd Tanous return; 1228d2f868cSEd Tanous } 1238d2f868cSEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 1248d2f868cSEd Tanous 1258d2f868cSEd Tanous // Make call to post-code service to request clear all 1268d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 1278d2f868cSEd Tanous [asyncResp](const boost::system::error_code& ec) { 1288d2f868cSEd Tanous if (ec) 1298d2f868cSEd Tanous { 1308d2f868cSEd Tanous // TODO Handle for specific error code 13134fe470aSEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 1328d2f868cSEd Tanous ec); 13334fe470aSEd Tanous asyncResp->res.result( 13434fe470aSEd Tanous boost::beast::http::status::internal_server_error); 1358d2f868cSEd Tanous messages::internalError(asyncResp->res); 1368d2f868cSEd Tanous return; 1378d2f868cSEd Tanous } 1388d2f868cSEd Tanous messages::success(asyncResp->res); 1398d2f868cSEd Tanous }, 1408d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 1418d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 1428d2f868cSEd Tanous "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 1438d2f868cSEd Tanous } 1448d2f868cSEd Tanous 1458d2f868cSEd Tanous /** 1468d2f868cSEd Tanous * @brief Parse post code ID and get the current value and index value 1478d2f868cSEd Tanous * eg: postCodeID=B1-2, currentValue=1, index=2 1488d2f868cSEd Tanous * 1498d2f868cSEd Tanous * @param[in] postCodeID Post Code ID 1508d2f868cSEd Tanous * @param[out] currentValue Current value 1518d2f868cSEd Tanous * @param[out] index Index value 1528d2f868cSEd Tanous * 1538d2f868cSEd Tanous * @return bool true if the parsing is successful, false the parsing fails 1548d2f868cSEd Tanous */ 1558d2f868cSEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 1568d2f868cSEd Tanous uint16_t& index) 1578d2f868cSEd Tanous { 1588d2f868cSEd Tanous std::vector<std::string> split; 1598d2f868cSEd Tanous bmcweb::split(split, postCodeID, '-'); 1608d2f868cSEd Tanous if (split.size() != 2) 1618d2f868cSEd Tanous { 1628d2f868cSEd Tanous return false; 1638d2f868cSEd Tanous } 1648d2f868cSEd Tanous std::string_view postCodeNumber = split[0]; 1658d2f868cSEd Tanous if (postCodeNumber.size() < 2) 1668d2f868cSEd Tanous { 1678d2f868cSEd Tanous return false; 1688d2f868cSEd Tanous } 1698d2f868cSEd Tanous if (postCodeNumber[0] != 'B') 1708d2f868cSEd Tanous { 1718d2f868cSEd Tanous return false; 1728d2f868cSEd Tanous } 1738d2f868cSEd Tanous postCodeNumber.remove_prefix(1); 1748d2f868cSEd Tanous auto [ptrIndex, ecIndex] = 1758d2f868cSEd Tanous std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index); 1768d2f868cSEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 1778d2f868cSEd Tanous { 1788d2f868cSEd Tanous return false; 1798d2f868cSEd Tanous } 1808d2f868cSEd Tanous 1818d2f868cSEd Tanous std::string_view postCodeIndex = split[1]; 1828d2f868cSEd Tanous 1838d2f868cSEd Tanous auto [ptrValue, ecValue] = std::from_chars( 1848d2f868cSEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 1858d2f868cSEd Tanous 1868d2f868cSEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 1878d2f868cSEd Tanous } 1888d2f868cSEd Tanous 1898d2f868cSEd Tanous static bool fillPostCodeEntry( 1908d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1918d2f868cSEd Tanous const boost::container::flat_map< 1926a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>>& 1936a42dc61SPotin Lai postcode, 1948d2f868cSEd Tanous const uint16_t bootIndex, const uint64_t codeIndex = 0, 1958d2f868cSEd Tanous const uint64_t skip = 0, const uint64_t top = 0) 1968d2f868cSEd Tanous { 1978d2f868cSEd Tanous // Get the Message from the MessageRegistry 1988d2f868cSEd Tanous const registries::Message* message = 1998d2f868cSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 2008d2f868cSEd Tanous if (message == nullptr) 2018d2f868cSEd Tanous { 2028d2f868cSEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 2038d2f868cSEd Tanous return false; 2048d2f868cSEd Tanous } 2058d2f868cSEd Tanous uint64_t currentCodeIndex = 0; 2068d2f868cSEd Tanous uint64_t firstCodeTimeUs = 0; 2076a42dc61SPotin Lai for (const std::pair<uint64_t, std::tuple<std::vector<uint8_t>, 2086a42dc61SPotin Lai std::vector<uint8_t>>>& code : 2096a42dc61SPotin Lai postcode) 2108d2f868cSEd Tanous { 2118d2f868cSEd Tanous currentCodeIndex++; 2128d2f868cSEd Tanous std::string postcodeEntryID = 2138d2f868cSEd Tanous "B" + std::to_string(bootIndex) + "-" + 2148d2f868cSEd Tanous std::to_string(currentCodeIndex); // 1 based index in EntryID string 2158d2f868cSEd Tanous 2168d2f868cSEd Tanous uint64_t usecSinceEpoch = code.first; 2178d2f868cSEd Tanous uint64_t usTimeOffset = 0; 2188d2f868cSEd Tanous 2198d2f868cSEd Tanous if (1 == currentCodeIndex) 2208d2f868cSEd Tanous { // already incremented 2218d2f868cSEd Tanous firstCodeTimeUs = code.first; 2228d2f868cSEd Tanous } 2238d2f868cSEd Tanous else 2248d2f868cSEd Tanous { 2258d2f868cSEd Tanous usTimeOffset = code.first - firstCodeTimeUs; 2268d2f868cSEd Tanous } 2278d2f868cSEd Tanous 2288d2f868cSEd Tanous // skip if no specific codeIndex is specified and currentCodeIndex does 2298d2f868cSEd Tanous // not fall between top and skip 2308d2f868cSEd Tanous if ((codeIndex == 0) && 2318d2f868cSEd Tanous (currentCodeIndex <= skip || currentCodeIndex > top)) 2328d2f868cSEd Tanous { 2338d2f868cSEd Tanous continue; 2348d2f868cSEd Tanous } 2358d2f868cSEd Tanous 2368d2f868cSEd Tanous // skip if a specific codeIndex is specified and does not match the 2378d2f868cSEd Tanous // currentIndex 2388d2f868cSEd Tanous if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 2398d2f868cSEd Tanous { 2408d2f868cSEd Tanous // This is done for simplicity. 1st entry is needed to calculate 2418d2f868cSEd Tanous // time offset. To improve efficiency, one can get to the entry 2428d2f868cSEd Tanous // directly (possibly with flatmap's nth method) 2438d2f868cSEd Tanous continue; 2448d2f868cSEd Tanous } 2458d2f868cSEd Tanous 2468d2f868cSEd Tanous // currentCodeIndex is within top and skip or equal to specified code 2478d2f868cSEd Tanous // index 2488d2f868cSEd Tanous 2498d2f868cSEd Tanous // Get the Created time from the timestamp 2508d2f868cSEd Tanous std::string entryTimeStr; 2518d2f868cSEd Tanous entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 2528d2f868cSEd Tanous 2538d2f868cSEd Tanous // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 2548d2f868cSEd Tanous std::ostringstream timeOffsetStr; 2558d2f868cSEd Tanous // Set Fixed -Point Notation 2568d2f868cSEd Tanous timeOffsetStr << std::fixed; 2578d2f868cSEd Tanous // Set precision to 4 digits 2588d2f868cSEd Tanous timeOffsetStr << std::setprecision(4); 2598d2f868cSEd Tanous // Add double to stream 2608d2f868cSEd Tanous timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 2618d2f868cSEd Tanous 2628d2f868cSEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 2638d2f868cSEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 2646a42dc61SPotin Lai std::string hexCodeStr = 2656a42dc61SPotin Lai "0x" + bytesToHexString(std::get<0>(code.second)); 2668d2f868cSEd Tanous 2678d2f868cSEd Tanous std::array<std::string_view, 3> messageArgs = { 2688d2f868cSEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 2698d2f868cSEd Tanous 2708d2f868cSEd Tanous std::string msg = 2718d2f868cSEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 2728d2f868cSEd Tanous if (msg.empty()) 2738d2f868cSEd Tanous { 2748d2f868cSEd Tanous messages::internalError(asyncResp->res); 2758d2f868cSEd Tanous return false; 2768d2f868cSEd Tanous } 2778d2f868cSEd Tanous 2788d2f868cSEd Tanous // Get Severity template from message registry 2798d2f868cSEd Tanous std::string severity; 2808d2f868cSEd Tanous if (message != nullptr) 2818d2f868cSEd Tanous { 2828d2f868cSEd Tanous severity = message->messageSeverity; 2838d2f868cSEd Tanous } 2848d2f868cSEd Tanous 2858d2f868cSEd Tanous // Format entry 2868d2f868cSEd Tanous nlohmann::json::object_t bmcLogEntry; 2878d2f868cSEd Tanous bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2888d2f868cSEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 2898d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 2908d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 2918d2f868cSEd Tanous bmcLogEntry["Name"] = "POST Code Log Entry"; 2928d2f868cSEd Tanous bmcLogEntry["Id"] = postcodeEntryID; 2938d2f868cSEd Tanous bmcLogEntry["Message"] = std::move(msg); 2948d2f868cSEd Tanous bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 2958d2f868cSEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 2968d2f868cSEd Tanous bmcLogEntry["EntryType"] = "Event"; 2978d2f868cSEd Tanous bmcLogEntry["Severity"] = std::move(severity); 2988d2f868cSEd Tanous bmcLogEntry["Created"] = entryTimeStr; 2996a42dc61SPotin Lai if (!std::get<1>(code.second).empty()) 3008d2f868cSEd Tanous { 3018d2f868cSEd Tanous bmcLogEntry["AdditionalDataURI"] = 3028d2f868cSEd Tanous std::format( 3038d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 3048d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3058d2f868cSEd Tanous postcodeEntryID + "/attachment"; 3068d2f868cSEd Tanous } 3078d2f868cSEd Tanous 3088d2f868cSEd Tanous // codeIndex is only specified when querying single entry, return only 3098d2f868cSEd Tanous // that entry in this case 3108d2f868cSEd Tanous if (codeIndex != 0) 3118d2f868cSEd Tanous { 3128d2f868cSEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 3138d2f868cSEd Tanous return true; 3148d2f868cSEd Tanous } 3158d2f868cSEd Tanous 3168d2f868cSEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 3178d2f868cSEd Tanous logEntryArray.emplace_back(std::move(bmcLogEntry)); 3188d2f868cSEd Tanous } 3198d2f868cSEd Tanous 3208d2f868cSEd Tanous // Return value is always false when querying multiple entries 3218d2f868cSEd Tanous return false; 3228d2f868cSEd Tanous } 3238d2f868cSEd Tanous 32434fe470aSEd Tanous inline void 3258d2f868cSEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3268d2f868cSEd Tanous const std::string& entryId) 3278d2f868cSEd Tanous { 3288d2f868cSEd Tanous uint16_t bootIndex = 0; 3298d2f868cSEd Tanous uint64_t codeIndex = 0; 3308d2f868cSEd Tanous if (!parsePostCode(entryId, codeIndex, bootIndex)) 3318d2f868cSEd Tanous { 3328d2f868cSEd Tanous // Requested ID was not found 3338d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3348d2f868cSEd Tanous return; 3358d2f868cSEd Tanous } 3368d2f868cSEd Tanous 3378d2f868cSEd Tanous if (bootIndex == 0 || codeIndex == 0) 3388d2f868cSEd Tanous { 3398d2f868cSEd Tanous // 0 is an invalid index 3408d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3418d2f868cSEd Tanous return; 3428d2f868cSEd Tanous } 3438d2f868cSEd Tanous 3448d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 3458d2f868cSEd Tanous [asyncResp, entryId, bootIndex, 3468d2f868cSEd Tanous codeIndex](const boost::system::error_code& ec, 3478d2f868cSEd Tanous const boost::container::flat_map< 3486a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, 3496a42dc61SPotin Lai std::vector<uint8_t>>>& postcode) { 3508d2f868cSEd Tanous if (ec) 3518d2f868cSEd Tanous { 3528d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3538d2f868cSEd Tanous messages::internalError(asyncResp->res); 3548d2f868cSEd Tanous return; 3558d2f868cSEd Tanous } 3568d2f868cSEd Tanous 3578d2f868cSEd Tanous if (postcode.empty()) 3588d2f868cSEd Tanous { 3598d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3608d2f868cSEd Tanous return; 3618d2f868cSEd Tanous } 3628d2f868cSEd Tanous 3638d2f868cSEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 3648d2f868cSEd Tanous { 3658d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3668d2f868cSEd Tanous return; 3678d2f868cSEd Tanous } 3688d2f868cSEd Tanous }, 3698d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 3708d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 3718d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3728d2f868cSEd Tanous bootIndex); 3738d2f868cSEd Tanous } 3748d2f868cSEd Tanous 37534fe470aSEd Tanous inline void 3768d2f868cSEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3778d2f868cSEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3788d2f868cSEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3798d2f868cSEd Tanous { 3808d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 3818d2f868cSEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 3828d2f868cSEd Tanous top](const boost::system::error_code& ec, 3838d2f868cSEd Tanous const boost::container::flat_map< 3846a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, 3856a42dc61SPotin Lai std::vector<uint8_t>>>& postcode) { 3868d2f868cSEd Tanous if (ec) 3878d2f868cSEd Tanous { 3888d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3898d2f868cSEd Tanous messages::internalError(asyncResp->res); 3908d2f868cSEd Tanous return; 3918d2f868cSEd Tanous } 3928d2f868cSEd Tanous 3938d2f868cSEd Tanous uint64_t endCount = entryCount; 3948d2f868cSEd Tanous if (!postcode.empty()) 3958d2f868cSEd Tanous { 3968d2f868cSEd Tanous endCount = entryCount + postcode.size(); 3978d2f868cSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3988d2f868cSEd Tanous { 3998d2f868cSEd Tanous uint64_t thisBootSkip = 4008d2f868cSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 4018d2f868cSEd Tanous entryCount; 4028d2f868cSEd Tanous uint64_t thisBootTop = 4038d2f868cSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 4048d2f868cSEd Tanous entryCount; 4058d2f868cSEd Tanous 4068d2f868cSEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4078d2f868cSEd Tanous thisBootSkip, thisBootTop); 4088d2f868cSEd Tanous } 4098d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4108d2f868cSEd Tanous } 4118d2f868cSEd Tanous 4128d2f868cSEd Tanous // continue to previous bootIndex 4138d2f868cSEd Tanous if (bootIndex < bootCount) 4148d2f868cSEd Tanous { 4158d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 4168d2f868cSEd Tanous static_cast<uint16_t>(bootIndex + 1), 4178d2f868cSEd Tanous bootCount, endCount, skip, top); 4188d2f868cSEd Tanous } 4198d2f868cSEd Tanous else if (skip + top < endCount) 4208d2f868cSEd Tanous { 4218d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 4228d2f868cSEd Tanous std::format( 4238d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 4248d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 4258d2f868cSEd Tanous std::to_string(skip + top); 4268d2f868cSEd Tanous } 4278d2f868cSEd Tanous }, 4288d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 4298d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 4308d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4318d2f868cSEd Tanous bootIndex); 4328d2f868cSEd Tanous } 4338d2f868cSEd Tanous 43434fe470aSEd Tanous inline void 4358d2f868cSEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4368d2f868cSEd Tanous size_t skip, size_t top) 4378d2f868cSEd Tanous { 4388d2f868cSEd Tanous uint64_t entryCount = 0; 439deae6a78SEd Tanous dbus::utility::getProperty<uint16_t>( 4408d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 4418d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 4428d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4438d2f868cSEd Tanous [asyncResp, entryCount, skip, 4448d2f868cSEd Tanous top](const boost::system::error_code& ec, const uint16_t bootCount) { 4458d2f868cSEd Tanous if (ec) 4468d2f868cSEd Tanous { 4478d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4488d2f868cSEd Tanous messages::internalError(asyncResp->res); 4498d2f868cSEd Tanous return; 4508d2f868cSEd Tanous } 4518d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 4528d2f868cSEd Tanous }); 4538d2f868cSEd Tanous } 4548d2f868cSEd Tanous 45534fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesGet( 45634fe470aSEd Tanous App& app, const crow::Request& req, 4578d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 45834fe470aSEd Tanous const std::string& systemName) 45934fe470aSEd Tanous { 4608d2f868cSEd Tanous query_param::QueryCapabilities capabilities = { 4618d2f868cSEd Tanous .canDelegateTop = true, 4628d2f868cSEd Tanous .canDelegateSkip = true, 4638d2f868cSEd Tanous }; 4648d2f868cSEd Tanous query_param::Query delegatedQuery; 46534fe470aSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 46634fe470aSEd Tanous delegatedQuery, capabilities)) 4678d2f868cSEd Tanous { 4688d2f868cSEd Tanous return; 4698d2f868cSEd Tanous } 4708d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 4718d2f868cSEd Tanous { 4728d2f868cSEd Tanous // Option currently returns no systems. TBD 4738d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4748d2f868cSEd Tanous systemName); 4758d2f868cSEd Tanous return; 4768d2f868cSEd Tanous } 4778d2f868cSEd Tanous 4788d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 4798d2f868cSEd Tanous { 4808d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4818d2f868cSEd Tanous systemName); 4828d2f868cSEd Tanous return; 4838d2f868cSEd Tanous } 4848d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 4858d2f868cSEd Tanous "#LogEntryCollection.LogEntryCollection"; 48634fe470aSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 48734fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 4888d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 4898d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4908d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = 4918d2f868cSEd Tanous "Collection of POST Code Log Entries"; 4928d2f868cSEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4938d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 4948d2f868cSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 49534fe470aSEd Tanous size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 4968d2f868cSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 4978d2f868cSEd Tanous } 4988d2f868cSEd Tanous 49934fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet( 50034fe470aSEd Tanous App& app, const crow::Request& req, 5018d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 50234fe470aSEd Tanous const std::string& systemName, const std::string& postCodeID) 50334fe470aSEd Tanous { 5048d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5058d2f868cSEd Tanous { 5068d2f868cSEd Tanous return; 5078d2f868cSEd Tanous } 5088d2f868cSEd Tanous if (!http_helpers::isContentTypeAllowed( 5098d2f868cSEd Tanous req.getHeaderValue("Accept"), 5108d2f868cSEd Tanous http_helpers::ContentType::OctetStream, true)) 5118d2f868cSEd Tanous { 5128d2f868cSEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 5138d2f868cSEd Tanous return; 5148d2f868cSEd Tanous } 5158d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5168d2f868cSEd Tanous { 5178d2f868cSEd Tanous // Option currently returns no systems. TBD 5188d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5198d2f868cSEd Tanous systemName); 5208d2f868cSEd Tanous return; 5218d2f868cSEd Tanous } 5228d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 5238d2f868cSEd Tanous { 5248d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5258d2f868cSEd Tanous systemName); 5268d2f868cSEd Tanous return; 5278d2f868cSEd Tanous } 5288d2f868cSEd Tanous 5298d2f868cSEd Tanous uint64_t currentValue = 0; 5308d2f868cSEd Tanous uint16_t index = 0; 5318d2f868cSEd Tanous if (!parsePostCode(postCodeID, currentValue, index)) 5328d2f868cSEd Tanous { 53334fe470aSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 5348d2f868cSEd Tanous return; 5358d2f868cSEd Tanous } 5368d2f868cSEd Tanous 5378d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 5388d2f868cSEd Tanous [asyncResp, postCodeID, currentValue]( 5398d2f868cSEd Tanous const boost::system::error_code& ec, 5406a42dc61SPotin Lai const std::vector<std::tuple<std::vector<uint8_t>, 5416a42dc61SPotin Lai std::vector<uint8_t>>>& postcodes) { 5428d2f868cSEd Tanous if (ec.value() == EBADR) 5438d2f868cSEd Tanous { 5448d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5458d2f868cSEd Tanous postCodeID); 5468d2f868cSEd Tanous return; 5478d2f868cSEd Tanous } 5488d2f868cSEd Tanous if (ec) 5498d2f868cSEd Tanous { 5508d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 5518d2f868cSEd Tanous messages::internalError(asyncResp->res); 5528d2f868cSEd Tanous return; 5538d2f868cSEd Tanous } 5548d2f868cSEd Tanous 5558d2f868cSEd Tanous size_t value = static_cast<size_t>(currentValue) - 1; 55634fe470aSEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 5578d2f868cSEd Tanous { 5588d2f868cSEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 5598d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5608d2f868cSEd Tanous postCodeID); 5618d2f868cSEd Tanous return; 5628d2f868cSEd Tanous } 5638d2f868cSEd Tanous 5648d2f868cSEd Tanous const auto& [tID, c] = postcodes[value]; 5658d2f868cSEd Tanous if (c.empty()) 5668d2f868cSEd Tanous { 5678d2f868cSEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 5688d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5698d2f868cSEd Tanous postCodeID); 5708d2f868cSEd Tanous return; 5718d2f868cSEd Tanous } 5728d2f868cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 5738d2f868cSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 5748d2f868cSEd Tanous std::string_view strData(d, c.size()); 5758d2f868cSEd Tanous 57634fe470aSEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 5778d2f868cSEd Tanous "application/octet-stream"); 5788d2f868cSEd Tanous asyncResp->res.addHeader( 57934fe470aSEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 5808d2f868cSEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 5818d2f868cSEd Tanous }, 5828d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 5838d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 58434fe470aSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 5858d2f868cSEd Tanous } 5868d2f868cSEd Tanous 58734fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryGet( 58834fe470aSEd Tanous App& app, const crow::Request& req, 5898d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 59034fe470aSEd Tanous const std::string& systemName, const std::string& targetID) 59134fe470aSEd Tanous { 5928d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5938d2f868cSEd Tanous { 5948d2f868cSEd Tanous return; 5958d2f868cSEd Tanous } 5968d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5978d2f868cSEd Tanous { 5988d2f868cSEd Tanous // Option currently returns no systems. TBD 5998d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6008d2f868cSEd Tanous systemName); 6018d2f868cSEd Tanous return; 6028d2f868cSEd Tanous } 6038d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 6048d2f868cSEd Tanous { 6058d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6068d2f868cSEd Tanous systemName); 6078d2f868cSEd Tanous return; 6088d2f868cSEd Tanous } 6098d2f868cSEd Tanous 6108d2f868cSEd Tanous getPostCodeForEntry(asyncResp, targetID); 6118d2f868cSEd Tanous } 6128d2f868cSEd Tanous 6138d2f868cSEd Tanous inline void requestRoutesSystemsLogServicesPostCode(App& app) 6148d2f868cSEd Tanous { 61534fe470aSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 61634fe470aSEd Tanous .privileges(redfish::privileges::getLogService) 61734fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 61834fe470aSEd Tanous handleSystemsLogServicesPostCodesGet, std::ref(app))); 61934fe470aSEd Tanous 62034fe470aSEd Tanous BMCWEB_ROUTE( 62134fe470aSEd Tanous app, 62234fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 6239d62d126SGunnar Mills // The following privilege is correct; we need "SubordinateOverrides" 6249d62d126SGunnar Mills // before we can automate it. 62534fe470aSEd Tanous .privileges({{"ConfigureComponents"}}) 62634fe470aSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 62734fe470aSEd Tanous handleSystemsLogServicesPostCodesPost, std::ref(app))); 62834fe470aSEd Tanous 62934fe470aSEd Tanous BMCWEB_ROUTE(app, 63034fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 63134fe470aSEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 63234fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 63334fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesGet, std::ref(app))); 63434fe470aSEd Tanous 63534fe470aSEd Tanous BMCWEB_ROUTE( 63634fe470aSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 63734fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 63834fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 63934fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app))); 64034fe470aSEd Tanous 64134fe470aSEd Tanous BMCWEB_ROUTE( 64234fe470aSEd Tanous app, 64334fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 64434fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 64534fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 64634fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet, 64734fe470aSEd Tanous std::ref(app))); 6488d2f868cSEd Tanous } 6498d2f868cSEd Tanous } // namespace redfish 650