140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 38d2f868cSEd Tanous #pragma once 48d2f868cSEd Tanous 5d7857201SEd Tanous #include "bmcweb_config.h" 6d7857201SEd Tanous 78d2f868cSEd Tanous #include "app.hpp" 8d7857201SEd Tanous #include "async_resp.hpp" 9deae6a78SEd Tanous #include "dbus_utility.hpp" 10d7857201SEd Tanous #include "error_messages.hpp" 118d2f868cSEd Tanous #include "generated/enums/log_service.hpp" 12d7857201SEd Tanous #include "http_request.hpp" 13d7857201SEd Tanous #include "http_utility.hpp" 14d7857201SEd Tanous #include "logging.hpp" 158d2f868cSEd Tanous #include "query.hpp" 16d7857201SEd Tanous #include "registries.hpp" 178d2f868cSEd Tanous #include "registries/privilege_registry.hpp" 18d7857201SEd Tanous #include "str_utility.hpp" 19d7857201SEd Tanous #include "utility.hpp" 20*08fad5d9SCorey Ethington #include "utils/etag_utils.hpp" 21d7857201SEd Tanous #include "utils/hex_utils.hpp" 22d7857201SEd Tanous #include "utils/query_param.hpp" 238d2f868cSEd Tanous #include "utils/time_utils.hpp" 248d2f868cSEd Tanous 25d7857201SEd Tanous #include <asm-generic/errno.h> 26d7857201SEd Tanous 27d7857201SEd Tanous #include <boost/beast/http/field.hpp> 28d7857201SEd Tanous #include <boost/beast/http/status.hpp> 29d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 30d7857201SEd Tanous #include <boost/container/flat_map.hpp> 31d7857201SEd Tanous #include <boost/url/format.hpp> 32d7857201SEd Tanous 33d7857201SEd Tanous #include <algorithm> 34d7857201SEd Tanous #include <array> 35d7857201SEd Tanous #include <charconv> 36d7857201SEd Tanous #include <cstddef> 378d2f868cSEd Tanous #include <cstdint> 38d7857201SEd Tanous #include <format> 39d7857201SEd Tanous #include <functional> 40d7857201SEd Tanous #include <iomanip> 41d7857201SEd Tanous #include <ios> 428d2f868cSEd Tanous #include <memory> 43d7857201SEd Tanous #include <sstream> 44d7857201SEd Tanous #include <string> 458d2f868cSEd Tanous #include <string_view> 46d7857201SEd Tanous #include <system_error> 47d7857201SEd 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); 99*08fad5d9SCorey Ethington 100*08fad5d9SCorey Ethington etag_utils::setEtagOmitDateTimeHandler(asyncResp); 1018d2f868cSEd Tanous } 1028d2f868cSEd Tanous 10334fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesPost( 10434fe470aSEd Tanous App& app, const crow::Request& req, 1058d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10634fe470aSEd Tanous const std::string& systemName) 10734fe470aSEd Tanous { 1088d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1098d2f868cSEd Tanous { 1108d2f868cSEd Tanous return; 1118d2f868cSEd Tanous } 1128d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1138d2f868cSEd Tanous { 1148d2f868cSEd Tanous // Option currently returns no systems. TBD 1158d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1168d2f868cSEd Tanous systemName); 1178d2f868cSEd Tanous return; 1188d2f868cSEd Tanous } 1198d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 1208d2f868cSEd Tanous { 1218d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1228d2f868cSEd Tanous systemName); 1238d2f868cSEd Tanous return; 1248d2f868cSEd Tanous } 1258d2f868cSEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 1268d2f868cSEd Tanous 1278d2f868cSEd Tanous // Make call to post-code service to request clear all 128177612aaSEd Tanous dbus::utility::async_method_call( 129177612aaSEd Tanous asyncResp, 1308d2f868cSEd Tanous [asyncResp](const boost::system::error_code& ec) { 1318d2f868cSEd Tanous if (ec) 1328d2f868cSEd Tanous { 1338d2f868cSEd Tanous // TODO Handle for specific error code 13434fe470aSEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 1358d2f868cSEd Tanous ec); 13634fe470aSEd Tanous asyncResp->res.result( 13734fe470aSEd Tanous boost::beast::http::status::internal_server_error); 1388d2f868cSEd Tanous messages::internalError(asyncResp->res); 1398d2f868cSEd Tanous return; 1408d2f868cSEd Tanous } 1418d2f868cSEd Tanous messages::success(asyncResp->res); 1428d2f868cSEd Tanous }, 1438d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 1448d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 1458d2f868cSEd Tanous "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 1468d2f868cSEd Tanous } 1478d2f868cSEd Tanous 1488d2f868cSEd Tanous /** 1498d2f868cSEd Tanous * @brief Parse post code ID and get the current value and index value 1508d2f868cSEd Tanous * eg: postCodeID=B1-2, currentValue=1, index=2 1518d2f868cSEd Tanous * 1528d2f868cSEd Tanous * @param[in] postCodeID Post Code ID 1538d2f868cSEd Tanous * @param[out] currentValue Current value 1548d2f868cSEd Tanous * @param[out] index Index value 1558d2f868cSEd Tanous * 1568d2f868cSEd Tanous * @return bool true if the parsing is successful, false the parsing fails 1578d2f868cSEd Tanous */ 1588d2f868cSEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 1598d2f868cSEd Tanous uint16_t& index) 1608d2f868cSEd Tanous { 1618d2f868cSEd Tanous std::vector<std::string> split; 1628d2f868cSEd Tanous bmcweb::split(split, postCodeID, '-'); 1638d2f868cSEd Tanous if (split.size() != 2) 1648d2f868cSEd Tanous { 1658d2f868cSEd Tanous return false; 1668d2f868cSEd Tanous } 1678d2f868cSEd Tanous std::string_view postCodeNumber = split[0]; 1688d2f868cSEd Tanous if (postCodeNumber.size() < 2) 1698d2f868cSEd Tanous { 1708d2f868cSEd Tanous return false; 1718d2f868cSEd Tanous } 1728d2f868cSEd Tanous if (postCodeNumber[0] != 'B') 1738d2f868cSEd Tanous { 1748d2f868cSEd Tanous return false; 1758d2f868cSEd Tanous } 1768d2f868cSEd Tanous postCodeNumber.remove_prefix(1); 1778d2f868cSEd Tanous auto [ptrIndex, ecIndex] = 1788d2f868cSEd Tanous std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index); 1798d2f868cSEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 1808d2f868cSEd Tanous { 1818d2f868cSEd Tanous return false; 1828d2f868cSEd Tanous } 1838d2f868cSEd Tanous 1848d2f868cSEd Tanous std::string_view postCodeIndex = split[1]; 1858d2f868cSEd Tanous 1868d2f868cSEd Tanous auto [ptrValue, ecValue] = std::from_chars( 1878d2f868cSEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 1888d2f868cSEd Tanous 1898d2f868cSEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 1908d2f868cSEd Tanous } 1918d2f868cSEd Tanous 1928d2f868cSEd Tanous static bool fillPostCodeEntry( 1938d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1948d2f868cSEd Tanous const boost::container::flat_map< 1956a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>>& 1966a42dc61SPotin Lai postcode, 1978d2f868cSEd Tanous const uint16_t bootIndex, const uint64_t codeIndex = 0, 1988d2f868cSEd Tanous const uint64_t skip = 0, const uint64_t top = 0) 1998d2f868cSEd Tanous { 2008d2f868cSEd Tanous // Get the Message from the MessageRegistry 2018d2f868cSEd Tanous const registries::Message* message = 2028d2f868cSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 2038d2f868cSEd Tanous if (message == nullptr) 2048d2f868cSEd Tanous { 2058d2f868cSEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 2068d2f868cSEd Tanous return false; 2078d2f868cSEd Tanous } 2088d2f868cSEd Tanous uint64_t currentCodeIndex = 0; 2098d2f868cSEd Tanous uint64_t firstCodeTimeUs = 0; 2106a42dc61SPotin Lai for (const std::pair<uint64_t, std::tuple<std::vector<uint8_t>, 2116a42dc61SPotin Lai std::vector<uint8_t>>>& code : 2126a42dc61SPotin Lai postcode) 2138d2f868cSEd Tanous { 2148d2f868cSEd Tanous currentCodeIndex++; 2158d2f868cSEd Tanous std::string postcodeEntryID = 2168d2f868cSEd Tanous "B" + std::to_string(bootIndex) + "-" + 2178d2f868cSEd Tanous std::to_string(currentCodeIndex); // 1 based index in EntryID string 2188d2f868cSEd Tanous 2198d2f868cSEd Tanous uint64_t usecSinceEpoch = code.first; 2208d2f868cSEd Tanous uint64_t usTimeOffset = 0; 2218d2f868cSEd Tanous 2228d2f868cSEd Tanous if (1 == currentCodeIndex) 2238d2f868cSEd Tanous { // already incremented 2248d2f868cSEd Tanous firstCodeTimeUs = code.first; 2258d2f868cSEd Tanous } 2268d2f868cSEd Tanous else 2278d2f868cSEd Tanous { 2288d2f868cSEd Tanous usTimeOffset = code.first - firstCodeTimeUs; 2298d2f868cSEd Tanous } 2308d2f868cSEd Tanous 2318d2f868cSEd Tanous // skip if no specific codeIndex is specified and currentCodeIndex does 2328d2f868cSEd Tanous // not fall between top and skip 2338d2f868cSEd Tanous if ((codeIndex == 0) && 2348d2f868cSEd Tanous (currentCodeIndex <= skip || currentCodeIndex > top)) 2358d2f868cSEd Tanous { 2368d2f868cSEd Tanous continue; 2378d2f868cSEd Tanous } 2388d2f868cSEd Tanous 2398d2f868cSEd Tanous // skip if a specific codeIndex is specified and does not match the 2408d2f868cSEd Tanous // currentIndex 2418d2f868cSEd Tanous if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 2428d2f868cSEd Tanous { 2438d2f868cSEd Tanous // This is done for simplicity. 1st entry is needed to calculate 2448d2f868cSEd Tanous // time offset. To improve efficiency, one can get to the entry 2458d2f868cSEd Tanous // directly (possibly with flatmap's nth method) 2468d2f868cSEd Tanous continue; 2478d2f868cSEd Tanous } 2488d2f868cSEd Tanous 2498d2f868cSEd Tanous // currentCodeIndex is within top and skip or equal to specified code 2508d2f868cSEd Tanous // index 2518d2f868cSEd Tanous 2528d2f868cSEd Tanous // Get the Created time from the timestamp 2538d2f868cSEd Tanous std::string entryTimeStr; 2548d2f868cSEd Tanous entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 2558d2f868cSEd Tanous 2568d2f868cSEd Tanous // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 2578d2f868cSEd Tanous std::ostringstream timeOffsetStr; 2588d2f868cSEd Tanous // Set Fixed -Point Notation 2598d2f868cSEd Tanous timeOffsetStr << std::fixed; 2608d2f868cSEd Tanous // Set precision to 4 digits 2618d2f868cSEd Tanous timeOffsetStr << std::setprecision(4); 2628d2f868cSEd Tanous // Add double to stream 2638d2f868cSEd Tanous timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 2648d2f868cSEd Tanous 2658d2f868cSEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 2668d2f868cSEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 2676a42dc61SPotin Lai std::string hexCodeStr = 2686a42dc61SPotin Lai "0x" + bytesToHexString(std::get<0>(code.second)); 2698d2f868cSEd Tanous 2708d2f868cSEd Tanous std::array<std::string_view, 3> messageArgs = { 2718d2f868cSEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 2728d2f868cSEd Tanous 2738d2f868cSEd Tanous std::string msg = 2748d2f868cSEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 2758d2f868cSEd Tanous if (msg.empty()) 2768d2f868cSEd Tanous { 2778d2f868cSEd Tanous messages::internalError(asyncResp->res); 2788d2f868cSEd Tanous return false; 2798d2f868cSEd Tanous } 2808d2f868cSEd Tanous 2818d2f868cSEd Tanous // Get Severity template from message registry 2828d2f868cSEd Tanous std::string severity; 2838d2f868cSEd Tanous if (message != nullptr) 2848d2f868cSEd Tanous { 2858d2f868cSEd Tanous severity = message->messageSeverity; 2868d2f868cSEd Tanous } 2878d2f868cSEd Tanous 2888d2f868cSEd Tanous // Format entry 2898d2f868cSEd Tanous nlohmann::json::object_t bmcLogEntry; 2908d2f868cSEd Tanous bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2918d2f868cSEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 2928d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 2938d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 2948d2f868cSEd Tanous bmcLogEntry["Name"] = "POST Code Log Entry"; 2958d2f868cSEd Tanous bmcLogEntry["Id"] = postcodeEntryID; 2968d2f868cSEd Tanous bmcLogEntry["Message"] = std::move(msg); 2978d2f868cSEd Tanous bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 2988d2f868cSEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 2998d2f868cSEd Tanous bmcLogEntry["EntryType"] = "Event"; 3008d2f868cSEd Tanous bmcLogEntry["Severity"] = std::move(severity); 3018d2f868cSEd Tanous bmcLogEntry["Created"] = entryTimeStr; 3026a42dc61SPotin Lai if (!std::get<1>(code.second).empty()) 3038d2f868cSEd Tanous { 3048d2f868cSEd Tanous bmcLogEntry["AdditionalDataURI"] = 3058d2f868cSEd Tanous std::format( 3068d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 3078d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3088d2f868cSEd Tanous postcodeEntryID + "/attachment"; 3098d2f868cSEd Tanous } 3108d2f868cSEd Tanous 3118d2f868cSEd Tanous // codeIndex is only specified when querying single entry, return only 3128d2f868cSEd Tanous // that entry in this case 3138d2f868cSEd Tanous if (codeIndex != 0) 3148d2f868cSEd Tanous { 3158d2f868cSEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 3168d2f868cSEd Tanous return true; 3178d2f868cSEd Tanous } 3188d2f868cSEd Tanous 3198d2f868cSEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 3208d2f868cSEd Tanous logEntryArray.emplace_back(std::move(bmcLogEntry)); 3218d2f868cSEd Tanous } 3228d2f868cSEd Tanous 3238d2f868cSEd Tanous // Return value is always false when querying multiple entries 3248d2f868cSEd Tanous return false; 3258d2f868cSEd Tanous } 3268d2f868cSEd Tanous 327504af5a0SPatrick Williams inline void getPostCodeForEntry( 328504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3298d2f868cSEd Tanous const std::string& entryId) 3308d2f868cSEd Tanous { 3318d2f868cSEd Tanous uint16_t bootIndex = 0; 3328d2f868cSEd Tanous uint64_t codeIndex = 0; 3338d2f868cSEd Tanous if (!parsePostCode(entryId, codeIndex, bootIndex)) 3348d2f868cSEd Tanous { 3358d2f868cSEd Tanous // Requested ID was not found 3368d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3378d2f868cSEd Tanous return; 3388d2f868cSEd Tanous } 3398d2f868cSEd Tanous 3408d2f868cSEd Tanous if (bootIndex == 0 || codeIndex == 0) 3418d2f868cSEd Tanous { 3428d2f868cSEd Tanous // 0 is an invalid index 3438d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3448d2f868cSEd Tanous return; 3458d2f868cSEd Tanous } 3468d2f868cSEd Tanous 347177612aaSEd Tanous dbus::utility::async_method_call( 348177612aaSEd Tanous asyncResp, 3498d2f868cSEd Tanous [asyncResp, entryId, bootIndex, 3508d2f868cSEd Tanous codeIndex](const boost::system::error_code& ec, 3518d2f868cSEd Tanous const boost::container::flat_map< 3526a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, 3536a42dc61SPotin Lai std::vector<uint8_t>>>& postcode) { 3548d2f868cSEd Tanous if (ec) 3558d2f868cSEd Tanous { 3568d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3578d2f868cSEd Tanous messages::internalError(asyncResp->res); 3588d2f868cSEd Tanous return; 3598d2f868cSEd Tanous } 3608d2f868cSEd Tanous 3618d2f868cSEd Tanous if (postcode.empty()) 3628d2f868cSEd Tanous { 3638d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3648d2f868cSEd Tanous return; 3658d2f868cSEd Tanous } 3668d2f868cSEd Tanous 3678d2f868cSEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 3688d2f868cSEd Tanous { 3698d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3708d2f868cSEd Tanous return; 3718d2f868cSEd Tanous } 3728d2f868cSEd Tanous }, 3738d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 3748d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 3758d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3768d2f868cSEd Tanous bootIndex); 3778d2f868cSEd Tanous } 3788d2f868cSEd Tanous 379504af5a0SPatrick Williams inline void getPostCodeForBoot( 380504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3818d2f868cSEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3828d2f868cSEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3838d2f868cSEd Tanous { 384177612aaSEd Tanous dbus::utility::async_method_call( 385177612aaSEd Tanous asyncResp, 3868d2f868cSEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 3878d2f868cSEd Tanous top](const boost::system::error_code& ec, 3888d2f868cSEd Tanous const boost::container::flat_map< 3896a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, 3906a42dc61SPotin Lai std::vector<uint8_t>>>& postcode) { 3918d2f868cSEd Tanous if (ec) 3928d2f868cSEd Tanous { 3938d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3948d2f868cSEd Tanous messages::internalError(asyncResp->res); 3958d2f868cSEd Tanous return; 3968d2f868cSEd Tanous } 3978d2f868cSEd Tanous 3988d2f868cSEd Tanous uint64_t endCount = entryCount; 3998d2f868cSEd Tanous if (!postcode.empty()) 4008d2f868cSEd Tanous { 4018d2f868cSEd Tanous endCount = entryCount + postcode.size(); 4028d2f868cSEd Tanous if (skip < endCount && (top + skip) > entryCount) 4038d2f868cSEd Tanous { 4048d2f868cSEd Tanous uint64_t thisBootSkip = 4058d2f868cSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 4068d2f868cSEd Tanous entryCount; 4078d2f868cSEd Tanous uint64_t thisBootTop = 4088d2f868cSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 4098d2f868cSEd Tanous entryCount; 4108d2f868cSEd Tanous 4118d2f868cSEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4128d2f868cSEd Tanous thisBootSkip, thisBootTop); 4138d2f868cSEd Tanous } 4148d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4158d2f868cSEd Tanous } 4168d2f868cSEd Tanous 4178d2f868cSEd Tanous // continue to previous bootIndex 4188d2f868cSEd Tanous if (bootIndex < bootCount) 4198d2f868cSEd Tanous { 4208d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 4218d2f868cSEd Tanous static_cast<uint16_t>(bootIndex + 1), 4228d2f868cSEd Tanous bootCount, endCount, skip, top); 4238d2f868cSEd Tanous } 4248d2f868cSEd Tanous else if (skip + top < endCount) 4258d2f868cSEd Tanous { 4268d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 4278d2f868cSEd Tanous std::format( 4288d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 4298d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 4308d2f868cSEd Tanous std::to_string(skip + top); 4318d2f868cSEd Tanous } 4328d2f868cSEd Tanous }, 4338d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 4348d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 4358d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4368d2f868cSEd Tanous bootIndex); 4378d2f868cSEd Tanous } 4388d2f868cSEd Tanous 439504af5a0SPatrick Williams inline void getCurrentBootNumber( 440504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, size_t skip, 441504af5a0SPatrick Williams size_t top) 4428d2f868cSEd Tanous { 4438d2f868cSEd Tanous uint64_t entryCount = 0; 444deae6a78SEd Tanous dbus::utility::getProperty<uint16_t>( 4458d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 4468d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 4478d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4488d2f868cSEd Tanous [asyncResp, entryCount, skip, 4498d2f868cSEd Tanous top](const boost::system::error_code& ec, const uint16_t bootCount) { 4508d2f868cSEd Tanous if (ec) 4518d2f868cSEd Tanous { 4528d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4538d2f868cSEd Tanous messages::internalError(asyncResp->res); 4548d2f868cSEd Tanous return; 4558d2f868cSEd Tanous } 4568d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 4578d2f868cSEd Tanous }); 4588d2f868cSEd Tanous } 4598d2f868cSEd Tanous 46034fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesGet( 46134fe470aSEd Tanous App& app, const crow::Request& req, 4628d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 46334fe470aSEd Tanous const std::string& systemName) 46434fe470aSEd Tanous { 4658d2f868cSEd Tanous query_param::QueryCapabilities capabilities = { 4668d2f868cSEd Tanous .canDelegateTop = true, 4678d2f868cSEd Tanous .canDelegateSkip = true, 4688d2f868cSEd Tanous }; 4698d2f868cSEd Tanous query_param::Query delegatedQuery; 47034fe470aSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 47134fe470aSEd Tanous delegatedQuery, capabilities)) 4728d2f868cSEd Tanous { 4738d2f868cSEd Tanous return; 4748d2f868cSEd Tanous } 4758d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 4768d2f868cSEd Tanous { 4778d2f868cSEd Tanous // Option currently returns no systems. TBD 4788d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4798d2f868cSEd Tanous systemName); 4808d2f868cSEd Tanous return; 4818d2f868cSEd Tanous } 4828d2f868cSEd Tanous 4838d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 4848d2f868cSEd Tanous { 4858d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4868d2f868cSEd Tanous systemName); 4878d2f868cSEd Tanous return; 4888d2f868cSEd Tanous } 4898d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 4908d2f868cSEd Tanous "#LogEntryCollection.LogEntryCollection"; 49134fe470aSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 49234fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 4938d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 4948d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4958d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = 4968d2f868cSEd Tanous "Collection of POST Code Log Entries"; 4978d2f868cSEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4988d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 4998d2f868cSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 50034fe470aSEd Tanous size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 5018d2f868cSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 5028d2f868cSEd Tanous } 5038d2f868cSEd Tanous 50434fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet( 50534fe470aSEd Tanous App& app, const crow::Request& req, 5068d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 50734fe470aSEd Tanous const std::string& systemName, const std::string& postCodeID) 50834fe470aSEd Tanous { 5098d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5108d2f868cSEd Tanous { 5118d2f868cSEd Tanous return; 5128d2f868cSEd Tanous } 5138d2f868cSEd Tanous if (!http_helpers::isContentTypeAllowed( 5148d2f868cSEd Tanous req.getHeaderValue("Accept"), 5158d2f868cSEd Tanous http_helpers::ContentType::OctetStream, true)) 5168d2f868cSEd Tanous { 5178d2f868cSEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 5188d2f868cSEd Tanous return; 5198d2f868cSEd Tanous } 5208d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5218d2f868cSEd Tanous { 5228d2f868cSEd Tanous // Option currently returns no systems. TBD 5238d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5248d2f868cSEd Tanous systemName); 5258d2f868cSEd Tanous return; 5268d2f868cSEd Tanous } 5278d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 5288d2f868cSEd Tanous { 5298d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5308d2f868cSEd Tanous systemName); 5318d2f868cSEd Tanous return; 5328d2f868cSEd Tanous } 5338d2f868cSEd Tanous 5348d2f868cSEd Tanous uint64_t currentValue = 0; 5358d2f868cSEd Tanous uint16_t index = 0; 5368d2f868cSEd Tanous if (!parsePostCode(postCodeID, currentValue, index)) 5378d2f868cSEd Tanous { 53834fe470aSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 5398d2f868cSEd Tanous return; 5408d2f868cSEd Tanous } 5418d2f868cSEd Tanous 542177612aaSEd Tanous dbus::utility::async_method_call( 543177612aaSEd Tanous asyncResp, 5448d2f868cSEd Tanous [asyncResp, postCodeID, currentValue]( 5458d2f868cSEd Tanous const boost::system::error_code& ec, 5466a42dc61SPotin Lai const std::vector<std::tuple<std::vector<uint8_t>, 5476a42dc61SPotin Lai std::vector<uint8_t>>>& postcodes) { 5488d2f868cSEd Tanous if (ec.value() == EBADR) 5498d2f868cSEd Tanous { 5508d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5518d2f868cSEd Tanous postCodeID); 5528d2f868cSEd Tanous return; 5538d2f868cSEd Tanous } 5548d2f868cSEd Tanous if (ec) 5558d2f868cSEd Tanous { 5568d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 5578d2f868cSEd Tanous messages::internalError(asyncResp->res); 5588d2f868cSEd Tanous return; 5598d2f868cSEd Tanous } 5608d2f868cSEd Tanous 5618d2f868cSEd Tanous size_t value = static_cast<size_t>(currentValue) - 1; 56234fe470aSEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 5638d2f868cSEd Tanous { 5648d2f868cSEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 5658d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5668d2f868cSEd Tanous postCodeID); 5678d2f868cSEd Tanous return; 5688d2f868cSEd Tanous } 5698d2f868cSEd Tanous 5708d2f868cSEd Tanous const auto& [tID, c] = postcodes[value]; 5718d2f868cSEd Tanous if (c.empty()) 5728d2f868cSEd Tanous { 5738d2f868cSEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 5748d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5758d2f868cSEd Tanous postCodeID); 5768d2f868cSEd Tanous return; 5778d2f868cSEd Tanous } 5788d2f868cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 5798d2f868cSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 5808d2f868cSEd Tanous std::string_view strData(d, c.size()); 5818d2f868cSEd Tanous 58234fe470aSEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 5838d2f868cSEd Tanous "application/octet-stream"); 5848d2f868cSEd Tanous asyncResp->res.addHeader( 58534fe470aSEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 5868d2f868cSEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 5878d2f868cSEd Tanous }, 5888d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 5898d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 59034fe470aSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 5918d2f868cSEd Tanous } 5928d2f868cSEd Tanous 59334fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryGet( 59434fe470aSEd Tanous App& app, const crow::Request& req, 5958d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 59634fe470aSEd Tanous const std::string& systemName, const std::string& targetID) 59734fe470aSEd Tanous { 5988d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5998d2f868cSEd Tanous { 6008d2f868cSEd Tanous return; 6018d2f868cSEd Tanous } 6028d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6038d2f868cSEd Tanous { 6048d2f868cSEd Tanous // Option currently returns no systems. TBD 6058d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6068d2f868cSEd Tanous systemName); 6078d2f868cSEd Tanous return; 6088d2f868cSEd Tanous } 6098d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 6108d2f868cSEd Tanous { 6118d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6128d2f868cSEd Tanous systemName); 6138d2f868cSEd Tanous return; 6148d2f868cSEd Tanous } 6158d2f868cSEd Tanous 6168d2f868cSEd Tanous getPostCodeForEntry(asyncResp, targetID); 6178d2f868cSEd Tanous } 6188d2f868cSEd Tanous 6198d2f868cSEd Tanous inline void requestRoutesSystemsLogServicesPostCode(App& app) 6208d2f868cSEd Tanous { 62134fe470aSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 62234fe470aSEd Tanous .privileges(redfish::privileges::getLogService) 62334fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 62434fe470aSEd Tanous handleSystemsLogServicesPostCodesGet, std::ref(app))); 62534fe470aSEd Tanous 62634fe470aSEd Tanous BMCWEB_ROUTE( 62734fe470aSEd Tanous app, 62834fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 629fff6a4d3SAbhishek Patel .privileges(redfish::privileges:: 630fff6a4d3SAbhishek Patel postLogServiceSubOverComputerSystemLogServiceCollection) 63134fe470aSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 63234fe470aSEd Tanous handleSystemsLogServicesPostCodesPost, std::ref(app))); 63334fe470aSEd Tanous 63434fe470aSEd Tanous BMCWEB_ROUTE(app, 63534fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 63634fe470aSEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 63734fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 63834fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesGet, std::ref(app))); 63934fe470aSEd Tanous 64034fe470aSEd Tanous BMCWEB_ROUTE( 64134fe470aSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 64234fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 64334fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 64434fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app))); 64534fe470aSEd Tanous 64634fe470aSEd Tanous BMCWEB_ROUTE( 64734fe470aSEd Tanous app, 64834fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 64934fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 65034fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 65134fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet, 65234fe470aSEd Tanous std::ref(app))); 6538d2f868cSEd Tanous } 6548d2f868cSEd Tanous } // namespace redfish 655