18d2f868cSEd Tanous #pragma once 28d2f868cSEd Tanous 38d2f868cSEd Tanous #include "app.hpp" 4*deae6a78SEd Tanous #include "dbus_utility.hpp" 58d2f868cSEd Tanous #include "generated/enums/log_service.hpp" 68d2f868cSEd Tanous #include "query.hpp" 78d2f868cSEd Tanous #include "registries/openbmc_message_registry.hpp" 88d2f868cSEd Tanous #include "registries/privilege_registry.hpp" 98d2f868cSEd Tanous #include "utils/time_utils.hpp" 108d2f868cSEd Tanous 118d2f868cSEd Tanous #include <cstdint> 128d2f868cSEd Tanous #include <memory> 138d2f868cSEd Tanous #include <string_view> 148d2f868cSEd Tanous #include <utility> 158d2f868cSEd Tanous #include <vector> 168d2f868cSEd Tanous 178d2f868cSEd Tanous namespace redfish 188d2f868cSEd Tanous { 1934fe470aSEd Tanous 2034fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesGet( 2134fe470aSEd Tanous App& app, const crow::Request& req, 228d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2334fe470aSEd Tanous const std::string& systemName) 2434fe470aSEd Tanous { 258d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 268d2f868cSEd Tanous { 278d2f868cSEd Tanous return; 288d2f868cSEd Tanous } 298d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 308d2f868cSEd Tanous { 318d2f868cSEd Tanous // Option currently returns no systems. TBD 328d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 338d2f868cSEd Tanous systemName); 348d2f868cSEd Tanous return; 358d2f868cSEd Tanous } 368d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 378d2f868cSEd Tanous { 388d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 398d2f868cSEd Tanous systemName); 408d2f868cSEd Tanous return; 418d2f868cSEd Tanous } 428d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 438d2f868cSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes", 448d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 4534fe470aSEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 468d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 478d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 488d2f868cSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 498d2f868cSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 508d2f868cSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 5134fe470aSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 5234fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 538d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 548d2f868cSEd Tanous 558d2f868cSEd Tanous std::pair<std::string, std::string> redfishDateTimeOffset = 568d2f868cSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 578d2f868cSEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 588d2f868cSEd Tanous asyncResp->res.jsonValue["DateTimeLocalOffset"] = 598d2f868cSEd Tanous redfishDateTimeOffset.second; 608d2f868cSEd Tanous 6134fe470aSEd Tanous asyncResp->res 6234fe470aSEd Tanous .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = std::format( 638d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog", 648d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 658d2f868cSEd Tanous } 668d2f868cSEd Tanous 6734fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesPost( 6834fe470aSEd Tanous App& app, const crow::Request& req, 698d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7034fe470aSEd Tanous const std::string& systemName) 7134fe470aSEd Tanous { 728d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 738d2f868cSEd Tanous { 748d2f868cSEd Tanous return; 758d2f868cSEd Tanous } 768d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 778d2f868cSEd Tanous { 788d2f868cSEd Tanous // Option currently returns no systems. TBD 798d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 808d2f868cSEd Tanous systemName); 818d2f868cSEd Tanous return; 828d2f868cSEd Tanous } 838d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 848d2f868cSEd Tanous { 858d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 868d2f868cSEd Tanous systemName); 878d2f868cSEd Tanous return; 888d2f868cSEd Tanous } 898d2f868cSEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 908d2f868cSEd Tanous 918d2f868cSEd Tanous // Make call to post-code service to request clear all 928d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 938d2f868cSEd Tanous [asyncResp](const boost::system::error_code& ec) { 948d2f868cSEd Tanous if (ec) 958d2f868cSEd Tanous { 968d2f868cSEd Tanous // TODO Handle for specific error code 9734fe470aSEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 988d2f868cSEd Tanous ec); 9934fe470aSEd Tanous asyncResp->res.result( 10034fe470aSEd Tanous boost::beast::http::status::internal_server_error); 1018d2f868cSEd Tanous messages::internalError(asyncResp->res); 1028d2f868cSEd Tanous return; 1038d2f868cSEd Tanous } 1048d2f868cSEd Tanous messages::success(asyncResp->res); 1058d2f868cSEd Tanous }, 1068d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 1078d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 1088d2f868cSEd Tanous "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 1098d2f868cSEd Tanous } 1108d2f868cSEd Tanous 1118d2f868cSEd Tanous /** 1128d2f868cSEd Tanous * @brief Parse post code ID and get the current value and index value 1138d2f868cSEd Tanous * eg: postCodeID=B1-2, currentValue=1, index=2 1148d2f868cSEd Tanous * 1158d2f868cSEd Tanous * @param[in] postCodeID Post Code ID 1168d2f868cSEd Tanous * @param[out] currentValue Current value 1178d2f868cSEd Tanous * @param[out] index Index value 1188d2f868cSEd Tanous * 1198d2f868cSEd Tanous * @return bool true if the parsing is successful, false the parsing fails 1208d2f868cSEd Tanous */ 1218d2f868cSEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 1228d2f868cSEd Tanous uint16_t& index) 1238d2f868cSEd Tanous { 1248d2f868cSEd Tanous std::vector<std::string> split; 1258d2f868cSEd Tanous bmcweb::split(split, postCodeID, '-'); 1268d2f868cSEd Tanous if (split.size() != 2) 1278d2f868cSEd Tanous { 1288d2f868cSEd Tanous return false; 1298d2f868cSEd Tanous } 1308d2f868cSEd Tanous std::string_view postCodeNumber = split[0]; 1318d2f868cSEd Tanous if (postCodeNumber.size() < 2) 1328d2f868cSEd Tanous { 1338d2f868cSEd Tanous return false; 1348d2f868cSEd Tanous } 1358d2f868cSEd Tanous if (postCodeNumber[0] != 'B') 1368d2f868cSEd Tanous { 1378d2f868cSEd Tanous return false; 1388d2f868cSEd Tanous } 1398d2f868cSEd Tanous postCodeNumber.remove_prefix(1); 1408d2f868cSEd Tanous auto [ptrIndex, ecIndex] = 1418d2f868cSEd Tanous std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index); 1428d2f868cSEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 1438d2f868cSEd Tanous { 1448d2f868cSEd Tanous return false; 1458d2f868cSEd Tanous } 1468d2f868cSEd Tanous 1478d2f868cSEd Tanous std::string_view postCodeIndex = split[1]; 1488d2f868cSEd Tanous 1498d2f868cSEd Tanous auto [ptrValue, ecValue] = std::from_chars( 1508d2f868cSEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 1518d2f868cSEd Tanous 1528d2f868cSEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 1538d2f868cSEd Tanous } 1548d2f868cSEd Tanous 1558d2f868cSEd Tanous static bool fillPostCodeEntry( 1568d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1578d2f868cSEd Tanous const boost::container::flat_map< 1586a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>>& 1596a42dc61SPotin Lai postcode, 1608d2f868cSEd Tanous const uint16_t bootIndex, const uint64_t codeIndex = 0, 1618d2f868cSEd Tanous const uint64_t skip = 0, const uint64_t top = 0) 1628d2f868cSEd Tanous { 1638d2f868cSEd Tanous // Get the Message from the MessageRegistry 1648d2f868cSEd Tanous const registries::Message* message = 1658d2f868cSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 1668d2f868cSEd Tanous if (message == nullptr) 1678d2f868cSEd Tanous { 1688d2f868cSEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 1698d2f868cSEd Tanous return false; 1708d2f868cSEd Tanous } 1718d2f868cSEd Tanous uint64_t currentCodeIndex = 0; 1728d2f868cSEd Tanous uint64_t firstCodeTimeUs = 0; 1736a42dc61SPotin Lai for (const std::pair<uint64_t, std::tuple<std::vector<uint8_t>, 1746a42dc61SPotin Lai std::vector<uint8_t>>>& code : 1756a42dc61SPotin Lai postcode) 1768d2f868cSEd Tanous { 1778d2f868cSEd Tanous currentCodeIndex++; 1788d2f868cSEd Tanous std::string postcodeEntryID = 1798d2f868cSEd Tanous "B" + std::to_string(bootIndex) + "-" + 1808d2f868cSEd Tanous std::to_string(currentCodeIndex); // 1 based index in EntryID string 1818d2f868cSEd Tanous 1828d2f868cSEd Tanous uint64_t usecSinceEpoch = code.first; 1838d2f868cSEd Tanous uint64_t usTimeOffset = 0; 1848d2f868cSEd Tanous 1858d2f868cSEd Tanous if (1 == currentCodeIndex) 1868d2f868cSEd Tanous { // already incremented 1878d2f868cSEd Tanous firstCodeTimeUs = code.first; 1888d2f868cSEd Tanous } 1898d2f868cSEd Tanous else 1908d2f868cSEd Tanous { 1918d2f868cSEd Tanous usTimeOffset = code.first - firstCodeTimeUs; 1928d2f868cSEd Tanous } 1938d2f868cSEd Tanous 1948d2f868cSEd Tanous // skip if no specific codeIndex is specified and currentCodeIndex does 1958d2f868cSEd Tanous // not fall between top and skip 1968d2f868cSEd Tanous if ((codeIndex == 0) && 1978d2f868cSEd Tanous (currentCodeIndex <= skip || currentCodeIndex > top)) 1988d2f868cSEd Tanous { 1998d2f868cSEd Tanous continue; 2008d2f868cSEd Tanous } 2018d2f868cSEd Tanous 2028d2f868cSEd Tanous // skip if a specific codeIndex is specified and does not match the 2038d2f868cSEd Tanous // currentIndex 2048d2f868cSEd Tanous if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 2058d2f868cSEd Tanous { 2068d2f868cSEd Tanous // This is done for simplicity. 1st entry is needed to calculate 2078d2f868cSEd Tanous // time offset. To improve efficiency, one can get to the entry 2088d2f868cSEd Tanous // directly (possibly with flatmap's nth method) 2098d2f868cSEd Tanous continue; 2108d2f868cSEd Tanous } 2118d2f868cSEd Tanous 2128d2f868cSEd Tanous // currentCodeIndex is within top and skip or equal to specified code 2138d2f868cSEd Tanous // index 2148d2f868cSEd Tanous 2158d2f868cSEd Tanous // Get the Created time from the timestamp 2168d2f868cSEd Tanous std::string entryTimeStr; 2178d2f868cSEd Tanous entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 2188d2f868cSEd Tanous 2198d2f868cSEd Tanous // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 2208d2f868cSEd Tanous std::ostringstream timeOffsetStr; 2218d2f868cSEd Tanous // Set Fixed -Point Notation 2228d2f868cSEd Tanous timeOffsetStr << std::fixed; 2238d2f868cSEd Tanous // Set precision to 4 digits 2248d2f868cSEd Tanous timeOffsetStr << std::setprecision(4); 2258d2f868cSEd Tanous // Add double to stream 2268d2f868cSEd Tanous timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 2278d2f868cSEd Tanous 2288d2f868cSEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 2298d2f868cSEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 2306a42dc61SPotin Lai std::string hexCodeStr = 2316a42dc61SPotin Lai "0x" + bytesToHexString(std::get<0>(code.second)); 2328d2f868cSEd Tanous 2338d2f868cSEd Tanous std::array<std::string_view, 3> messageArgs = { 2348d2f868cSEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 2358d2f868cSEd Tanous 2368d2f868cSEd Tanous std::string msg = 2378d2f868cSEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 2388d2f868cSEd Tanous if (msg.empty()) 2398d2f868cSEd Tanous { 2408d2f868cSEd Tanous messages::internalError(asyncResp->res); 2418d2f868cSEd Tanous return false; 2428d2f868cSEd Tanous } 2438d2f868cSEd Tanous 2448d2f868cSEd Tanous // Get Severity template from message registry 2458d2f868cSEd Tanous std::string severity; 2468d2f868cSEd Tanous if (message != nullptr) 2478d2f868cSEd Tanous { 2488d2f868cSEd Tanous severity = message->messageSeverity; 2498d2f868cSEd Tanous } 2508d2f868cSEd Tanous 2518d2f868cSEd Tanous // Format entry 2528d2f868cSEd Tanous nlohmann::json::object_t bmcLogEntry; 2538d2f868cSEd Tanous bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2548d2f868cSEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 2558d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 2568d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 2578d2f868cSEd Tanous bmcLogEntry["Name"] = "POST Code Log Entry"; 2588d2f868cSEd Tanous bmcLogEntry["Id"] = postcodeEntryID; 2598d2f868cSEd Tanous bmcLogEntry["Message"] = std::move(msg); 2608d2f868cSEd Tanous bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 2618d2f868cSEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 2628d2f868cSEd Tanous bmcLogEntry["EntryType"] = "Event"; 2638d2f868cSEd Tanous bmcLogEntry["Severity"] = std::move(severity); 2648d2f868cSEd Tanous bmcLogEntry["Created"] = entryTimeStr; 2656a42dc61SPotin Lai if (!std::get<1>(code.second).empty()) 2668d2f868cSEd Tanous { 2678d2f868cSEd Tanous bmcLogEntry["AdditionalDataURI"] = 2688d2f868cSEd Tanous std::format( 2698d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 2708d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 2718d2f868cSEd Tanous postcodeEntryID + "/attachment"; 2728d2f868cSEd Tanous } 2738d2f868cSEd Tanous 2748d2f868cSEd Tanous // codeIndex is only specified when querying single entry, return only 2758d2f868cSEd Tanous // that entry in this case 2768d2f868cSEd Tanous if (codeIndex != 0) 2778d2f868cSEd Tanous { 2788d2f868cSEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 2798d2f868cSEd Tanous return true; 2808d2f868cSEd Tanous } 2818d2f868cSEd Tanous 2828d2f868cSEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2838d2f868cSEd Tanous logEntryArray.emplace_back(std::move(bmcLogEntry)); 2848d2f868cSEd Tanous } 2858d2f868cSEd Tanous 2868d2f868cSEd Tanous // Return value is always false when querying multiple entries 2878d2f868cSEd Tanous return false; 2888d2f868cSEd Tanous } 2898d2f868cSEd Tanous 29034fe470aSEd Tanous inline void 2918d2f868cSEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2928d2f868cSEd Tanous const std::string& entryId) 2938d2f868cSEd Tanous { 2948d2f868cSEd Tanous uint16_t bootIndex = 0; 2958d2f868cSEd Tanous uint64_t codeIndex = 0; 2968d2f868cSEd Tanous if (!parsePostCode(entryId, codeIndex, bootIndex)) 2978d2f868cSEd Tanous { 2988d2f868cSEd Tanous // Requested ID was not found 2998d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3008d2f868cSEd Tanous return; 3018d2f868cSEd Tanous } 3028d2f868cSEd Tanous 3038d2f868cSEd Tanous if (bootIndex == 0 || codeIndex == 0) 3048d2f868cSEd Tanous { 3058d2f868cSEd Tanous // 0 is an invalid index 3068d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3078d2f868cSEd Tanous return; 3088d2f868cSEd Tanous } 3098d2f868cSEd Tanous 3108d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 3118d2f868cSEd Tanous [asyncResp, entryId, bootIndex, 3128d2f868cSEd Tanous codeIndex](const boost::system::error_code& ec, 3138d2f868cSEd Tanous const boost::container::flat_map< 3146a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, 3156a42dc61SPotin Lai std::vector<uint8_t>>>& postcode) { 3168d2f868cSEd Tanous if (ec) 3178d2f868cSEd Tanous { 3188d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3198d2f868cSEd Tanous messages::internalError(asyncResp->res); 3208d2f868cSEd Tanous return; 3218d2f868cSEd Tanous } 3228d2f868cSEd Tanous 3238d2f868cSEd Tanous if (postcode.empty()) 3248d2f868cSEd Tanous { 3258d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3268d2f868cSEd Tanous return; 3278d2f868cSEd Tanous } 3288d2f868cSEd Tanous 3298d2f868cSEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 3308d2f868cSEd Tanous { 3318d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3328d2f868cSEd Tanous return; 3338d2f868cSEd Tanous } 3348d2f868cSEd Tanous }, 3358d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 3368d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 3378d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3388d2f868cSEd Tanous bootIndex); 3398d2f868cSEd Tanous } 3408d2f868cSEd Tanous 34134fe470aSEd Tanous inline void 3428d2f868cSEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3438d2f868cSEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3448d2f868cSEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3458d2f868cSEd Tanous { 3468d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 3478d2f868cSEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 3488d2f868cSEd Tanous top](const boost::system::error_code& ec, 3498d2f868cSEd Tanous const boost::container::flat_map< 3506a42dc61SPotin Lai uint64_t, std::tuple<std::vector<uint8_t>, 3516a42dc61SPotin Lai std::vector<uint8_t>>>& postcode) { 3528d2f868cSEd Tanous if (ec) 3538d2f868cSEd Tanous { 3548d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3558d2f868cSEd Tanous messages::internalError(asyncResp->res); 3568d2f868cSEd Tanous return; 3578d2f868cSEd Tanous } 3588d2f868cSEd Tanous 3598d2f868cSEd Tanous uint64_t endCount = entryCount; 3608d2f868cSEd Tanous if (!postcode.empty()) 3618d2f868cSEd Tanous { 3628d2f868cSEd Tanous endCount = entryCount + postcode.size(); 3638d2f868cSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3648d2f868cSEd Tanous { 3658d2f868cSEd Tanous uint64_t thisBootSkip = 3668d2f868cSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 3678d2f868cSEd Tanous entryCount; 3688d2f868cSEd Tanous uint64_t thisBootTop = 3698d2f868cSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 3708d2f868cSEd Tanous entryCount; 3718d2f868cSEd Tanous 3728d2f868cSEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 3738d2f868cSEd Tanous thisBootSkip, thisBootTop); 3748d2f868cSEd Tanous } 3758d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 3768d2f868cSEd Tanous } 3778d2f868cSEd Tanous 3788d2f868cSEd Tanous // continue to previous bootIndex 3798d2f868cSEd Tanous if (bootIndex < bootCount) 3808d2f868cSEd Tanous { 3818d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 3828d2f868cSEd Tanous static_cast<uint16_t>(bootIndex + 1), 3838d2f868cSEd Tanous bootCount, endCount, skip, top); 3848d2f868cSEd Tanous } 3858d2f868cSEd Tanous else if (skip + top < endCount) 3868d2f868cSEd Tanous { 3878d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 3888d2f868cSEd Tanous std::format( 3898d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 3908d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3918d2f868cSEd Tanous std::to_string(skip + top); 3928d2f868cSEd Tanous } 3938d2f868cSEd Tanous }, 3948d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 3958d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 3968d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3978d2f868cSEd Tanous bootIndex); 3988d2f868cSEd Tanous } 3998d2f868cSEd Tanous 40034fe470aSEd Tanous inline void 4018d2f868cSEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4028d2f868cSEd Tanous size_t skip, size_t top) 4038d2f868cSEd Tanous { 4048d2f868cSEd Tanous uint64_t entryCount = 0; 405*deae6a78SEd Tanous dbus::utility::getProperty<uint16_t>( 4068d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 4078d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 4088d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4098d2f868cSEd Tanous [asyncResp, entryCount, skip, 4108d2f868cSEd Tanous top](const boost::system::error_code& ec, const uint16_t bootCount) { 4118d2f868cSEd Tanous if (ec) 4128d2f868cSEd Tanous { 4138d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4148d2f868cSEd Tanous messages::internalError(asyncResp->res); 4158d2f868cSEd Tanous return; 4168d2f868cSEd Tanous } 4178d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 4188d2f868cSEd Tanous }); 4198d2f868cSEd Tanous } 4208d2f868cSEd Tanous 42134fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesGet( 42234fe470aSEd Tanous App& app, const crow::Request& req, 4238d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 42434fe470aSEd Tanous const std::string& systemName) 42534fe470aSEd Tanous { 4268d2f868cSEd Tanous query_param::QueryCapabilities capabilities = { 4278d2f868cSEd Tanous .canDelegateTop = true, 4288d2f868cSEd Tanous .canDelegateSkip = true, 4298d2f868cSEd Tanous }; 4308d2f868cSEd Tanous query_param::Query delegatedQuery; 43134fe470aSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 43234fe470aSEd Tanous delegatedQuery, capabilities)) 4338d2f868cSEd Tanous { 4348d2f868cSEd Tanous return; 4358d2f868cSEd Tanous } 4368d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 4378d2f868cSEd Tanous { 4388d2f868cSEd Tanous // Option currently returns no systems. TBD 4398d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4408d2f868cSEd Tanous systemName); 4418d2f868cSEd Tanous return; 4428d2f868cSEd Tanous } 4438d2f868cSEd Tanous 4448d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 4458d2f868cSEd Tanous { 4468d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4478d2f868cSEd Tanous systemName); 4488d2f868cSEd Tanous return; 4498d2f868cSEd Tanous } 4508d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 4518d2f868cSEd Tanous "#LogEntryCollection.LogEntryCollection"; 45234fe470aSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 45334fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 4548d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 4558d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4568d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = 4578d2f868cSEd Tanous "Collection of POST Code Log Entries"; 4588d2f868cSEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4598d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 4608d2f868cSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 46134fe470aSEd Tanous size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 4628d2f868cSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 4638d2f868cSEd Tanous } 4648d2f868cSEd Tanous 46534fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet( 46634fe470aSEd Tanous App& app, const crow::Request& req, 4678d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 46834fe470aSEd Tanous const std::string& systemName, const std::string& postCodeID) 46934fe470aSEd Tanous { 4708d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 4718d2f868cSEd Tanous { 4728d2f868cSEd Tanous return; 4738d2f868cSEd Tanous } 4748d2f868cSEd Tanous if (!http_helpers::isContentTypeAllowed( 4758d2f868cSEd Tanous req.getHeaderValue("Accept"), 4768d2f868cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4778d2f868cSEd Tanous { 4788d2f868cSEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4798d2f868cSEd Tanous return; 4808d2f868cSEd Tanous } 4818d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 4828d2f868cSEd Tanous { 4838d2f868cSEd Tanous // Option currently returns no systems. TBD 4848d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4858d2f868cSEd Tanous systemName); 4868d2f868cSEd Tanous return; 4878d2f868cSEd Tanous } 4888d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 4898d2f868cSEd Tanous { 4908d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4918d2f868cSEd Tanous systemName); 4928d2f868cSEd Tanous return; 4938d2f868cSEd Tanous } 4948d2f868cSEd Tanous 4958d2f868cSEd Tanous uint64_t currentValue = 0; 4968d2f868cSEd Tanous uint16_t index = 0; 4978d2f868cSEd Tanous if (!parsePostCode(postCodeID, currentValue, index)) 4988d2f868cSEd Tanous { 49934fe470aSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 5008d2f868cSEd Tanous return; 5018d2f868cSEd Tanous } 5028d2f868cSEd Tanous 5038d2f868cSEd Tanous crow::connections::systemBus->async_method_call( 5048d2f868cSEd Tanous [asyncResp, postCodeID, currentValue]( 5058d2f868cSEd Tanous const boost::system::error_code& ec, 5066a42dc61SPotin Lai const std::vector<std::tuple<std::vector<uint8_t>, 5076a42dc61SPotin Lai std::vector<uint8_t>>>& postcodes) { 5088d2f868cSEd Tanous if (ec.value() == EBADR) 5098d2f868cSEd Tanous { 5108d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5118d2f868cSEd Tanous postCodeID); 5128d2f868cSEd Tanous return; 5138d2f868cSEd Tanous } 5148d2f868cSEd Tanous if (ec) 5158d2f868cSEd Tanous { 5168d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 5178d2f868cSEd Tanous messages::internalError(asyncResp->res); 5188d2f868cSEd Tanous return; 5198d2f868cSEd Tanous } 5208d2f868cSEd Tanous 5218d2f868cSEd Tanous size_t value = static_cast<size_t>(currentValue) - 1; 52234fe470aSEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 5238d2f868cSEd Tanous { 5248d2f868cSEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 5258d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5268d2f868cSEd Tanous postCodeID); 5278d2f868cSEd Tanous return; 5288d2f868cSEd Tanous } 5298d2f868cSEd Tanous 5308d2f868cSEd Tanous const auto& [tID, c] = postcodes[value]; 5318d2f868cSEd Tanous if (c.empty()) 5328d2f868cSEd Tanous { 5338d2f868cSEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 5348d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 5358d2f868cSEd Tanous postCodeID); 5368d2f868cSEd Tanous return; 5378d2f868cSEd Tanous } 5388d2f868cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 5398d2f868cSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 5408d2f868cSEd Tanous std::string_view strData(d, c.size()); 5418d2f868cSEd Tanous 54234fe470aSEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 5438d2f868cSEd Tanous "application/octet-stream"); 5448d2f868cSEd Tanous asyncResp->res.addHeader( 54534fe470aSEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 5468d2f868cSEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 5478d2f868cSEd Tanous }, 5488d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0", 5498d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0", 55034fe470aSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 5518d2f868cSEd Tanous } 5528d2f868cSEd Tanous 55334fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryGet( 55434fe470aSEd Tanous App& app, const crow::Request& req, 5558d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 55634fe470aSEd Tanous const std::string& systemName, const std::string& targetID) 55734fe470aSEd Tanous { 5588d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5598d2f868cSEd Tanous { 5608d2f868cSEd Tanous return; 5618d2f868cSEd Tanous } 5628d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5638d2f868cSEd Tanous { 5648d2f868cSEd Tanous // Option currently returns no systems. TBD 5658d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5668d2f868cSEd Tanous systemName); 5678d2f868cSEd Tanous return; 5688d2f868cSEd Tanous } 5698d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 5708d2f868cSEd Tanous { 5718d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5728d2f868cSEd Tanous systemName); 5738d2f868cSEd Tanous return; 5748d2f868cSEd Tanous } 5758d2f868cSEd Tanous 5768d2f868cSEd Tanous getPostCodeForEntry(asyncResp, targetID); 5778d2f868cSEd Tanous } 5788d2f868cSEd Tanous 5798d2f868cSEd Tanous inline void requestRoutesSystemsLogServicesPostCode(App& app) 5808d2f868cSEd Tanous { 58134fe470aSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 58234fe470aSEd Tanous .privileges(redfish::privileges::getLogService) 58334fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 58434fe470aSEd Tanous handleSystemsLogServicesPostCodesGet, std::ref(app))); 58534fe470aSEd Tanous 58634fe470aSEd Tanous BMCWEB_ROUTE( 58734fe470aSEd Tanous app, 58834fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 5899d62d126SGunnar Mills // The following privilege is correct; we need "SubordinateOverrides" 5909d62d126SGunnar Mills // before we can automate it. 59134fe470aSEd Tanous .privileges({{"ConfigureComponents"}}) 59234fe470aSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 59334fe470aSEd Tanous handleSystemsLogServicesPostCodesPost, std::ref(app))); 59434fe470aSEd Tanous 59534fe470aSEd Tanous BMCWEB_ROUTE(app, 59634fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 59734fe470aSEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 59834fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 59934fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesGet, std::ref(app))); 60034fe470aSEd Tanous 60134fe470aSEd Tanous BMCWEB_ROUTE( 60234fe470aSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 60334fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 60434fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 60534fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app))); 60634fe470aSEd Tanous 60734fe470aSEd Tanous BMCWEB_ROUTE( 60834fe470aSEd Tanous app, 60934fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 61034fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry) 61134fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 61234fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet, 61334fe470aSEd Tanous std::ref(app))); 6148d2f868cSEd Tanous } 6158d2f868cSEd Tanous } // namespace redfish 616