1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 38d2f868cSEd Tanous #pragma once 48d2f868cSEd Tanous 58d2f868cSEd Tanous #include "app.hpp" 6deae6a78SEd Tanous #include "dbus_utility.hpp" 78d2f868cSEd Tanous #include "generated/enums/log_service.hpp" 88d2f868cSEd Tanous #include "query.hpp" 98d2f868cSEd Tanous #include "registries/openbmc_message_registry.hpp" 108d2f868cSEd Tanous #include "registries/privilege_registry.hpp" 118d2f868cSEd Tanous #include "utils/time_utils.hpp" 128d2f868cSEd Tanous 138d2f868cSEd Tanous #include <cstdint> 148d2f868cSEd Tanous #include <memory> 158d2f868cSEd Tanous #include <string_view> 168d2f868cSEd Tanous #include <utility> 178d2f868cSEd Tanous #include <vector> 188d2f868cSEd Tanous 198d2f868cSEd Tanous namespace redfish 208d2f868cSEd Tanous { 2134fe470aSEd Tanous 2234fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesGet( 2334fe470aSEd Tanous App& app, const crow::Request& req, 248d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2534fe470aSEd Tanous const std::string& systemName) 2634fe470aSEd Tanous { 278d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 288d2f868cSEd Tanous { 298d2f868cSEd Tanous return; 308d2f868cSEd Tanous } 318d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 328d2f868cSEd Tanous { 338d2f868cSEd Tanous // Option currently returns no systems. TBD 348d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 358d2f868cSEd Tanous systemName); 368d2f868cSEd Tanous return; 378d2f868cSEd Tanous } 388d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 398d2f868cSEd Tanous { 408d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 418d2f868cSEd Tanous systemName); 428d2f868cSEd Tanous return; 438d2f868cSEd Tanous } 448d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 458d2f868cSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes", 468d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 4734fe470aSEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 488d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 498d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 508d2f868cSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 518d2f868cSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 528d2f868cSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 5334fe470aSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 5434fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 558d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 568d2f868cSEd Tanous 578d2f868cSEd Tanous std::pair<std::string, std::string> redfishDateTimeOffset = 588d2f868cSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 598d2f868cSEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 608d2f868cSEd Tanous asyncResp->res.jsonValue["DateTimeLocalOffset"] = 618d2f868cSEd Tanous redfishDateTimeOffset.second; 628d2f868cSEd Tanous 6334fe470aSEd Tanous asyncResp->res 6434fe470aSEd Tanous .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = std::format( 658d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog", 668d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 678d2f868cSEd Tanous } 688d2f868cSEd Tanous 6934fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesPost( 7034fe470aSEd Tanous App& app, const crow::Request& req, 718d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7234fe470aSEd Tanous const std::string& systemName) 7334fe470aSEd Tanous { 748d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 758d2f868cSEd Tanous { 768d2f868cSEd Tanous return; 778d2f868cSEd Tanous } 788d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 798d2f868cSEd Tanous { 808d2f868cSEd Tanous // Option currently returns no systems. TBD 818d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 828d2f868cSEd Tanous systemName); 838d2f868cSEd Tanous return; 848d2f868cSEd Tanous } 858d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 868d2f868cSEd Tanous { 878d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 888d2f868cSEd Tanous systemName); 898d2f868cSEd Tanous return; 908d2f868cSEd Tanous } 918d2f868cSEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 928d2f868cSEd Tanous 938d2f868cSEd Tanous // Make call to post-code service to request clear all 948d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 958d2f868cSEd Tanous [asyncResp](const boost::system::error_code& ec) { 968d2f868cSEd Tanous if (ec) 978d2f868cSEd Tanous { 988d2f868cSEd Tanous // TODO Handle for specific error code 9934fe470aSEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 1008d2f868cSEd Tanous ec); 10134fe470aSEd Tanous asyncResp->res.result( 10234fe470aSEd Tanous boost::beast::http::status::internal_server_error); 1038d2f868cSEd Tanous messages::internalError(asyncResp->res); 1048d2f868cSEd Tanous return; 1058d2f868cSEd Tanous } 1068d2f868cSEd Tanous messages::success(asyncResp->res); 1078d2f868cSEd Tanous }, 1088d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 1098d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 1108d2f868cSEd Tanous "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 1118d2f868cSEd Tanous } 1128d2f868cSEd Tanous 1138d2f868cSEd Tanous /** 1148d2f868cSEd Tanous * @brief Parse post code ID and get the current value and index value 1158d2f868cSEd Tanous * eg: postCodeID=B1-2, currentValue=1, index=2 1168d2f868cSEd Tanous * 1178d2f868cSEd Tanous * @param[in] postCodeID Post Code ID 1188d2f868cSEd Tanous * @param[out] currentValue Current value 1198d2f868cSEd Tanous * @param[out] index Index value 1208d2f868cSEd Tanous * 1218d2f868cSEd Tanous * @return bool true if the parsing is successful, false the parsing fails 1228d2f868cSEd Tanous */ 1238d2f868cSEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 1248d2f868cSEd Tanous uint16_t& index) 1258d2f868cSEd Tanous { 1268d2f868cSEd Tanous std::vector<std::string> split; 1278d2f868cSEd Tanous bmcweb::split(split, postCodeID, '-'); 1288d2f868cSEd Tanous if (split.size() != 2) 1298d2f868cSEd Tanous { 1308d2f868cSEd Tanous return false; 1318d2f868cSEd Tanous } 1328d2f868cSEd Tanous std::string_view postCodeNumber = split[0]; 1338d2f868cSEd Tanous if (postCodeNumber.size() < 2) 1348d2f868cSEd Tanous { 1358d2f868cSEd Tanous return false; 1368d2f868cSEd Tanous } 1378d2f868cSEd Tanous if (postCodeNumber[0] != 'B') 1388d2f868cSEd Tanous { 1398d2f868cSEd Tanous return false; 1408d2f868cSEd Tanous } 1418d2f868cSEd Tanous postCodeNumber.remove_prefix(1); 1428d2f868cSEd Tanous auto [ptrIndex, ecIndex] = 1438d2f868cSEd Tanous std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index); 1448d2f868cSEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 1458d2f868cSEd Tanous { 1468d2f868cSEd Tanous return false; 1478d2f868cSEd Tanous } 1488d2f868cSEd Tanous 1498d2f868cSEd Tanous std::string_view postCodeIndex = split[1]; 1508d2f868cSEd Tanous 1518d2f868cSEd Tanous auto [ptrValue, ecValue] = std::from_chars( 1528d2f868cSEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 1538d2f868cSEd Tanous 1548d2f868cSEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 1558d2f868cSEd Tanous } 1568d2f868cSEd Tanous 1578d2f868cSEd Tanous static bool fillPostCodeEntry( 1588d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1598d2f868cSEd Tanous const boost::container::flat_map< 1606a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>>& 1616a42dc61SPotin Lai postcode, 1628d2f868cSEd Tanous const uint16_t bootIndex, const uint64_t codeIndex = 0, 1638d2f868cSEd Tanous const uint64_t skip = 0, const uint64_t top = 0) 1648d2f868cSEd Tanous { 1658d2f868cSEd Tanous // Get the Message from the MessageRegistry 1668d2f868cSEd Tanous const registries::Message* message = 1678d2f868cSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 1688d2f868cSEd Tanous if (message == nullptr) 1698d2f868cSEd Tanous { 1708d2f868cSEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 1718d2f868cSEd Tanous return false; 1728d2f868cSEd Tanous } 1738d2f868cSEd Tanous uint64_t currentCodeIndex = 0; 1748d2f868cSEd Tanous uint64_t firstCodeTimeUs = 0; 1756a42dc61SPotin Lai for (const std::pair<uint64_t, std::tuple<std::vector<uint8_t>, 1766a42dc61SPotin Lai std::vector<uint8_t>>>& code : 1776a42dc61SPotin Lai postcode) 1788d2f868cSEd Tanous { 1798d2f868cSEd Tanous currentCodeIndex++; 1808d2f868cSEd Tanous std::string postcodeEntryID = 1818d2f868cSEd Tanous "B" + std::to_string(bootIndex) + "-" + 1828d2f868cSEd Tanous std::to_string(currentCodeIndex); // 1 based index in EntryID string 1838d2f868cSEd Tanous 1848d2f868cSEd Tanous uint64_t usecSinceEpoch = code.first; 1858d2f868cSEd Tanous uint64_t usTimeOffset = 0; 1868d2f868cSEd Tanous 1878d2f868cSEd Tanous if (1 == currentCodeIndex) 1888d2f868cSEd Tanous { // already incremented 1898d2f868cSEd Tanous firstCodeTimeUs = code.first; 1908d2f868cSEd Tanous } 1918d2f868cSEd Tanous else 1928d2f868cSEd Tanous { 1938d2f868cSEd Tanous usTimeOffset = code.first - firstCodeTimeUs; 1948d2f868cSEd Tanous } 1958d2f868cSEd Tanous 1968d2f868cSEd Tanous // skip if no specific codeIndex is specified and currentCodeIndex does 1978d2f868cSEd Tanous // not fall between top and skip 1988d2f868cSEd Tanous if ((codeIndex == 0) && 1998d2f868cSEd Tanous (currentCodeIndex <= skip || currentCodeIndex > top)) 2008d2f868cSEd Tanous { 2018d2f868cSEd Tanous continue; 2028d2f868cSEd Tanous } 2038d2f868cSEd Tanous 2048d2f868cSEd Tanous // skip if a specific codeIndex is specified and does not match the 2058d2f868cSEd Tanous // currentIndex 2068d2f868cSEd Tanous if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 2078d2f868cSEd Tanous { 2088d2f868cSEd Tanous // This is done for simplicity. 1st entry is needed to calculate 2098d2f868cSEd Tanous // time offset. To improve efficiency, one can get to the entry 2108d2f868cSEd Tanous // directly (possibly with flatmap's nth method) 2118d2f868cSEd Tanous continue; 2128d2f868cSEd Tanous } 2138d2f868cSEd Tanous 2148d2f868cSEd Tanous // currentCodeIndex is within top and skip or equal to specified code 2158d2f868cSEd Tanous // index 2168d2f868cSEd Tanous 2178d2f868cSEd Tanous // Get the Created time from the timestamp 2188d2f868cSEd Tanous std::string entryTimeStr; 2198d2f868cSEd Tanous entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 2208d2f868cSEd Tanous 2218d2f868cSEd Tanous // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 2228d2f868cSEd Tanous std::ostringstream timeOffsetStr; 2238d2f868cSEd Tanous // Set Fixed -Point Notation 2248d2f868cSEd Tanous timeOffsetStr << std::fixed; 2258d2f868cSEd Tanous // Set precision to 4 digits 2268d2f868cSEd Tanous timeOffsetStr << std::setprecision(4); 2278d2f868cSEd Tanous // Add double to stream 2288d2f868cSEd Tanous timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 2298d2f868cSEd Tanous 2308d2f868cSEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 2318d2f868cSEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 2326a42dc61SPotin Lai std::string hexCodeStr = 2336a42dc61SPotin Lai "0x" + bytesToHexString(std::get<0>(code.second)); 2348d2f868cSEd Tanous 2358d2f868cSEd Tanous std::array<std::string_view, 3> messageArgs = { 2368d2f868cSEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 2378d2f868cSEd Tanous 2388d2f868cSEd Tanous std::string msg = 2398d2f868cSEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 2408d2f868cSEd Tanous if (msg.empty()) 2418d2f868cSEd Tanous { 2428d2f868cSEd Tanous messages::internalError(asyncResp->res); 2438d2f868cSEd Tanous return false; 2448d2f868cSEd Tanous } 2458d2f868cSEd Tanous 2468d2f868cSEd Tanous // Get Severity template from message registry 2478d2f868cSEd Tanous std::string severity; 2488d2f868cSEd Tanous if (message != nullptr) 2498d2f868cSEd Tanous { 2508d2f868cSEd Tanous severity = message->messageSeverity; 2518d2f868cSEd Tanous } 2528d2f868cSEd Tanous 2538d2f868cSEd Tanous // Format entry 2548d2f868cSEd Tanous nlohmann::json::object_t bmcLogEntry; 2558d2f868cSEd Tanous bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2568d2f868cSEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 2578d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 2588d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 2598d2f868cSEd Tanous bmcLogEntry["Name"] = "POST Code Log Entry"; 2608d2f868cSEd Tanous bmcLogEntry["Id"] = postcodeEntryID; 2618d2f868cSEd Tanous bmcLogEntry["Message"] = std::move(msg); 2628d2f868cSEd Tanous bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 2638d2f868cSEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 2648d2f868cSEd Tanous bmcLogEntry["EntryType"] = "Event"; 2658d2f868cSEd Tanous bmcLogEntry["Severity"] = std::move(severity); 2668d2f868cSEd Tanous bmcLogEntry["Created"] = entryTimeStr; 2676a42dc61SPotin Lai if (!std::get<1>(code.second).empty()) 2688d2f868cSEd Tanous { 2698d2f868cSEd Tanous bmcLogEntry["AdditionalDataURI"] = 2708d2f868cSEd Tanous std::format( 2718d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 2728d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 2738d2f868cSEd Tanous postcodeEntryID + "/attachment"; 2748d2f868cSEd Tanous } 2758d2f868cSEd Tanous 2768d2f868cSEd Tanous // codeIndex is only specified when querying single entry, return only 2778d2f868cSEd Tanous // that entry in this case 2788d2f868cSEd Tanous if (codeIndex != 0) 2798d2f868cSEd Tanous { 2808d2f868cSEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 2818d2f868cSEd Tanous return true; 2828d2f868cSEd Tanous } 2838d2f868cSEd Tanous 2848d2f868cSEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2858d2f868cSEd Tanous logEntryArray.emplace_back(std::move(bmcLogEntry)); 2868d2f868cSEd Tanous } 2878d2f868cSEd Tanous 2888d2f868cSEd Tanous // Return value is always false when querying multiple entries 2898d2f868cSEd Tanous return false; 2908d2f868cSEd Tanous } 2918d2f868cSEd Tanous 29234fe470aSEd Tanous inline void 2938d2f868cSEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2948d2f868cSEd Tanous const std::string& entryId) 2958d2f868cSEd Tanous { 2968d2f868cSEd Tanous uint16_t bootIndex = 0; 2978d2f868cSEd Tanous uint64_t codeIndex = 0; 2988d2f868cSEd Tanous if (!parsePostCode(entryId, codeIndex, bootIndex)) 2998d2f868cSEd Tanous { 3008d2f868cSEd Tanous // Requested ID was not found 3018d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3028d2f868cSEd Tanous return; 3038d2f868cSEd Tanous } 3048d2f868cSEd Tanous 3058d2f868cSEd Tanous if (bootIndex == 0 || codeIndex == 0) 3068d2f868cSEd Tanous { 3078d2f868cSEd Tanous // 0 is an invalid index 3088d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3098d2f868cSEd Tanous return; 3108d2f868cSEd Tanous } 3118d2f868cSEd Tanous 3128d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 3138d2f868cSEd Tanous [asyncResp, entryId, bootIndex, 3148d2f868cSEd Tanous codeIndex](const boost::system::error_code& ec, 3158d2f868cSEd Tanous const boost::container::flat_map< 3166a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, 3176a42dc61SPotin Lai std::vector<uint8_t>>>& postcode) { 3188d2f868cSEd Tanous if (ec) 3198d2f868cSEd Tanous { 3208d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3218d2f868cSEd Tanous messages::internalError(asyncResp->res); 3228d2f868cSEd Tanous return; 3238d2f868cSEd Tanous } 3248d2f868cSEd Tanous 3258d2f868cSEd Tanous if (postcode.empty()) 3268d2f868cSEd Tanous { 3278d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3288d2f868cSEd Tanous return; 3298d2f868cSEd Tanous } 3308d2f868cSEd Tanous 3318d2f868cSEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 3328d2f868cSEd Tanous { 3338d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3348d2f868cSEd Tanous return; 3358d2f868cSEd Tanous } 3368d2f868cSEd Tanous }, 3378d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 3388d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 3398d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3408d2f868cSEd Tanous bootIndex); 3418d2f868cSEd Tanous } 3428d2f868cSEd Tanous 34334fe470aSEd Tanous inline void 3448d2f868cSEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3458d2f868cSEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3468d2f868cSEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3478d2f868cSEd Tanous { 3488d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 3498d2f868cSEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 3508d2f868cSEd Tanous top](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 uint64_t endCount = entryCount; 3628d2f868cSEd Tanous if (!postcode.empty()) 3638d2f868cSEd Tanous { 3648d2f868cSEd Tanous endCount = entryCount + postcode.size(); 3658d2f868cSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3668d2f868cSEd Tanous { 3678d2f868cSEd Tanous uint64_t thisBootSkip = 3688d2f868cSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 3698d2f868cSEd Tanous entryCount; 3708d2f868cSEd Tanous uint64_t thisBootTop = 3718d2f868cSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 3728d2f868cSEd Tanous entryCount; 3738d2f868cSEd Tanous 3748d2f868cSEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 3758d2f868cSEd Tanous thisBootSkip, thisBootTop); 3768d2f868cSEd Tanous } 3778d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 3788d2f868cSEd Tanous } 3798d2f868cSEd Tanous 3808d2f868cSEd Tanous // continue to previous bootIndex 3818d2f868cSEd Tanous if (bootIndex < bootCount) 3828d2f868cSEd Tanous { 3838d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 3848d2f868cSEd Tanous static_cast<uint16_t>(bootIndex + 1), 3858d2f868cSEd Tanous bootCount, endCount, skip, top); 3868d2f868cSEd Tanous } 3878d2f868cSEd Tanous else if (skip + top < endCount) 3888d2f868cSEd Tanous { 3898d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 3908d2f868cSEd Tanous std::format( 3918d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 3928d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3938d2f868cSEd Tanous std::to_string(skip + top); 3948d2f868cSEd Tanous } 3958d2f868cSEd Tanous }, 3968d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 3978d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 3988d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3998d2f868cSEd Tanous bootIndex); 4008d2f868cSEd Tanous } 4018d2f868cSEd Tanous 40234fe470aSEd Tanous inline void 4038d2f868cSEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4048d2f868cSEd Tanous size_t skip, size_t top) 4058d2f868cSEd Tanous { 4068d2f868cSEd Tanous uint64_t entryCount = 0; 407deae6a78SEd Tanous dbus::utility::getProperty<uint16_t>( 4088d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 4098d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 4108d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4118d2f868cSEd Tanous [asyncResp, entryCount, skip, 4128d2f868cSEd Tanous top](const boost::system::error_code& ec, const uint16_t bootCount) { 4138d2f868cSEd Tanous if (ec) 4148d2f868cSEd Tanous { 4158d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4168d2f868cSEd Tanous messages::internalError(asyncResp->res); 4178d2f868cSEd Tanous return; 4188d2f868cSEd Tanous } 4198d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 4208d2f868cSEd Tanous }); 4218d2f868cSEd Tanous } 4228d2f868cSEd Tanous 42334fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesGet( 42434fe470aSEd Tanous App& app, const crow::Request& req, 4258d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 42634fe470aSEd Tanous const std::string& systemName) 42734fe470aSEd Tanous { 4288d2f868cSEd Tanous query_param::QueryCapabilities capabilities = { 4298d2f868cSEd Tanous .canDelegateTop = true, 4308d2f868cSEd Tanous .canDelegateSkip = true, 4318d2f868cSEd Tanous }; 4328d2f868cSEd Tanous query_param::Query delegatedQuery; 43334fe470aSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 43434fe470aSEd Tanous delegatedQuery, capabilities)) 4358d2f868cSEd Tanous { 4368d2f868cSEd Tanous return; 4378d2f868cSEd Tanous } 4388d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 4398d2f868cSEd Tanous { 4408d2f868cSEd Tanous // Option currently returns no systems. TBD 4418d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4428d2f868cSEd Tanous systemName); 4438d2f868cSEd Tanous return; 4448d2f868cSEd Tanous } 4458d2f868cSEd Tanous 4468d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 4478d2f868cSEd Tanous { 4488d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4498d2f868cSEd Tanous systemName); 4508d2f868cSEd Tanous return; 4518d2f868cSEd Tanous } 4528d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 4538d2f868cSEd Tanous "#LogEntryCollection.LogEntryCollection"; 45434fe470aSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 45534fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 4568d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 4578d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4588d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = 4598d2f868cSEd Tanous "Collection of POST Code Log Entries"; 4608d2f868cSEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4618d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 4628d2f868cSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 46334fe470aSEd Tanous size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 4648d2f868cSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 4658d2f868cSEd Tanous } 4668d2f868cSEd Tanous 46734fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet( 46834fe470aSEd Tanous App& app, const crow::Request& req, 4698d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 47034fe470aSEd Tanous const std::string& systemName, const std::string& postCodeID) 47134fe470aSEd Tanous { 4728d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 4738d2f868cSEd Tanous { 4748d2f868cSEd Tanous return; 4758d2f868cSEd Tanous } 4768d2f868cSEd Tanous if (!http_helpers::isContentTypeAllowed( 4778d2f868cSEd Tanous req.getHeaderValue("Accept"), 4788d2f868cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4798d2f868cSEd Tanous { 4808d2f868cSEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4818d2f868cSEd Tanous return; 4828d2f868cSEd Tanous } 4838d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 4848d2f868cSEd Tanous { 4858d2f868cSEd Tanous // Option currently returns no systems. TBD 4868d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4878d2f868cSEd Tanous systemName); 4888d2f868cSEd Tanous return; 4898d2f868cSEd Tanous } 4908d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 4918d2f868cSEd Tanous { 4928d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4938d2f868cSEd Tanous systemName); 4948d2f868cSEd Tanous return; 4958d2f868cSEd Tanous } 4968d2f868cSEd Tanous 4978d2f868cSEd Tanous uint64_t currentValue = 0; 4988d2f868cSEd Tanous uint16_t index = 0; 4998d2f868cSEd Tanous if (!parsePostCode(postCodeID, currentValue, index)) 5008d2f868cSEd Tanous { 50134fe470aSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 5028d2f868cSEd Tanous return; 5038d2f868cSEd Tanous } 5048d2f868cSEd Tanous 5058d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 5068d2f868cSEd Tanous [asyncResp, postCodeID, currentValue]( 5078d2f868cSEd Tanous const boost::system::error_code& ec, 5086a42dc61SPotin Lai const std::vector<std::tuple<std::vector<uint8_t>, 5096a42dc61SPotin Lai std::vector<uint8_t>>>& postcodes) { 5108d2f868cSEd Tanous if (ec.value() == EBADR) 5118d2f868cSEd Tanous { 5128d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5138d2f868cSEd Tanous postCodeID); 5148d2f868cSEd Tanous return; 5158d2f868cSEd Tanous } 5168d2f868cSEd Tanous if (ec) 5178d2f868cSEd Tanous { 5188d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 5198d2f868cSEd Tanous messages::internalError(asyncResp->res); 5208d2f868cSEd Tanous return; 5218d2f868cSEd Tanous } 5228d2f868cSEd Tanous 5238d2f868cSEd Tanous size_t value = static_cast<size_t>(currentValue) - 1; 52434fe470aSEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 5258d2f868cSEd Tanous { 5268d2f868cSEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 5278d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5288d2f868cSEd Tanous postCodeID); 5298d2f868cSEd Tanous return; 5308d2f868cSEd Tanous } 5318d2f868cSEd Tanous 5328d2f868cSEd Tanous const auto& [tID, c] = postcodes[value]; 5338d2f868cSEd Tanous if (c.empty()) 5348d2f868cSEd Tanous { 5358d2f868cSEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 5368d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5378d2f868cSEd Tanous postCodeID); 5388d2f868cSEd Tanous return; 5398d2f868cSEd Tanous } 5408d2f868cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 5418d2f868cSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 5428d2f868cSEd Tanous std::string_view strData(d, c.size()); 5438d2f868cSEd Tanous 54434fe470aSEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 5458d2f868cSEd Tanous "application/octet-stream"); 5468d2f868cSEd Tanous asyncResp->res.addHeader( 54734fe470aSEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 5488d2f868cSEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 5498d2f868cSEd Tanous }, 5508d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 5518d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 55234fe470aSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 5538d2f868cSEd Tanous } 5548d2f868cSEd Tanous 55534fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryGet( 55634fe470aSEd Tanous App& app, const crow::Request& req, 5578d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 55834fe470aSEd Tanous const std::string& systemName, const std::string& targetID) 55934fe470aSEd Tanous { 5608d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5618d2f868cSEd Tanous { 5628d2f868cSEd Tanous return; 5638d2f868cSEd Tanous } 5648d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5658d2f868cSEd Tanous { 5668d2f868cSEd Tanous // Option currently returns no systems. TBD 5678d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5688d2f868cSEd Tanous systemName); 5698d2f868cSEd Tanous return; 5708d2f868cSEd Tanous } 5718d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 5728d2f868cSEd Tanous { 5738d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5748d2f868cSEd Tanous systemName); 5758d2f868cSEd Tanous return; 5768d2f868cSEd Tanous } 5778d2f868cSEd Tanous 5788d2f868cSEd Tanous getPostCodeForEntry(asyncResp, targetID); 5798d2f868cSEd Tanous } 5808d2f868cSEd Tanous 5818d2f868cSEd Tanous inline void requestRoutesSystemsLogServicesPostCode(App& app) 5828d2f868cSEd Tanous { 58334fe470aSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 58434fe470aSEd Tanous .privileges(redfish::privileges::getLogService) 58534fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 58634fe470aSEd Tanous handleSystemsLogServicesPostCodesGet, std::ref(app))); 58734fe470aSEd Tanous 58834fe470aSEd Tanous BMCWEB_ROUTE( 58934fe470aSEd Tanous app, 59034fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 5919d62d126SGunnar Mills // The following privilege is correct; we need "SubordinateOverrides" 5929d62d126SGunnar Mills // before we can automate it. 59334fe470aSEd Tanous .privileges({{"ConfigureComponents"}}) 59434fe470aSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 59534fe470aSEd Tanous handleSystemsLogServicesPostCodesPost, std::ref(app))); 59634fe470aSEd Tanous 59734fe470aSEd Tanous BMCWEB_ROUTE(app, 59834fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 59934fe470aSEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 60034fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 60134fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesGet, std::ref(app))); 60234fe470aSEd Tanous 60334fe470aSEd Tanous BMCWEB_ROUTE( 60434fe470aSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 60534fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 60634fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 60734fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app))); 60834fe470aSEd Tanous 60934fe470aSEd Tanous BMCWEB_ROUTE( 61034fe470aSEd Tanous app, 61134fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 61234fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 61334fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 61434fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet, 61534fe470aSEd Tanous std::ref(app))); 6168d2f868cSEd Tanous } 6178d2f868cSEd Tanous } // namespace redfish 618