194fc70cbSJayanth Othayoth #include "config.h"
294fc70cbSJayanth Othayoth
394fc70cbSJayanth Othayoth #include "extensions/phal/create_pel.hpp"
494fc70cbSJayanth Othayoth #include "registration.hpp"
594fc70cbSJayanth Othayoth #include "temporary_file.hpp"
694fc70cbSJayanth Othayoth
794fc70cbSJayanth Othayoth #include <fcntl.h>
894fc70cbSJayanth Othayoth
994fc70cbSJayanth Othayoth #include <nlohmann/json.hpp>
1094fc70cbSJayanth Othayoth #include <phosphor-logging/elog-errors.hpp>
1194fc70cbSJayanth Othayoth
1294fc70cbSJayanth Othayoth #include <cstdio>
1394fc70cbSJayanth Othayoth #include <filesystem>
14e0dd7af4SJayanth Othayoth #include <format>
1594fc70cbSJayanth Othayoth
1694fc70cbSJayanth Othayoth extern "C"
1794fc70cbSJayanth Othayoth {
1894fc70cbSJayanth Othayoth #include <dtree.h>
1994fc70cbSJayanth Othayoth }
2094fc70cbSJayanth Othayoth
2194fc70cbSJayanth Othayoth namespace openpower
2294fc70cbSJayanth Othayoth {
2394fc70cbSJayanth Othayoth namespace phal
2494fc70cbSJayanth Othayoth {
255409e877SJayanth Othayoth using namespace phosphor::logging;
26773fd244SJayanth Othayoth
27773fd244SJayanth Othayoth struct FileCloser
28773fd244SJayanth Othayoth {
operator ()openpower::phal::FileCloser29773fd244SJayanth Othayoth void operator()(FILE* fp) const
30773fd244SJayanth Othayoth {
31773fd244SJayanth Othayoth fclose(fp);
32773fd244SJayanth Othayoth }
33773fd244SJayanth Othayoth };
34773fd244SJayanth Othayoth using FILE_Ptr = std::unique_ptr<FILE, FileCloser>;
35773fd244SJayanth Othayoth
365409e877SJayanth Othayoth namespace fs = std::filesystem;
375409e877SJayanth Othayoth
applyAttrOverride(fs::path & devtreeFile)385409e877SJayanth Othayoth void applyAttrOverride(fs::path& devtreeFile)
395409e877SJayanth Othayoth {
405409e877SJayanth Othayoth constexpr auto DEVTREE_ATTR_OVERRIDE_PATH = "/tmp/devtree_attr_override";
415409e877SJayanth Othayoth auto overrideFile = fs::path(DEVTREE_ATTR_OVERRIDE_PATH);
425409e877SJayanth Othayoth if (!fs::exists(overrideFile))
435409e877SJayanth Othayoth {
445409e877SJayanth Othayoth return;
455409e877SJayanth Othayoth }
465409e877SJayanth Othayoth
475409e877SJayanth Othayoth // Open attribute override file in r/o mode
48773fd244SJayanth Othayoth FILE_Ptr fpOverride(fopen(DEVTREE_ATTR_OVERRIDE_PATH, "r"), FileCloser());
495409e877SJayanth Othayoth
505409e877SJayanth Othayoth // Update Devtree with attribute override data.
515409e877SJayanth Othayoth auto ret = dtree_cronus_import(devtreeFile.c_str(), CEC_INFODB_PATH,
525409e877SJayanth Othayoth fpOverride.get());
535409e877SJayanth Othayoth if (ret)
545409e877SJayanth Othayoth {
555409e877SJayanth Othayoth log<level::ERR>(
56e0dd7af4SJayanth Othayoth std::format("Failed({}) to update attribute override data", ret)
575409e877SJayanth Othayoth .c_str());
585409e877SJayanth Othayoth throw std::runtime_error(
595409e877SJayanth Othayoth "applyAttrOverride: dtree_cronus_import failed");
605409e877SJayanth Othayoth }
615409e877SJayanth Othayoth log<level::INFO>("DEVTREE: Applied attribute override data");
625409e877SJayanth Othayoth }
635409e877SJayanth Othayoth
6494fc70cbSJayanth Othayoth /**
6590166c15SMarri Devender Rao * @brief Compute RO device tree file path from RW symbolic link
6690166c15SMarri Devender Rao * @return RO file path one failure exception will be thrown
6790166c15SMarri Devender Rao */
computeRODeviceTreePath()6890166c15SMarri Devender Rao fs::path computeRODeviceTreePath()
6990166c15SMarri Devender Rao {
7090166c15SMarri Devender Rao // Symbolic links are not created for RO files, compute the lid name
7190166c15SMarri Devender Rao // for the RW symbolic link and use it to compute RO file.
7290166c15SMarri Devender Rao // Example:
7390166c15SMarri Devender Rao // RW file = /media/hostfw/running/DEVTREE -> 81e00672.lid
7490166c15SMarri Devender Rao // RO file = /media/hostfw/running-ro/ + 81e00672.lid
7590166c15SMarri Devender Rao fs::path rwFileName = fs::read_symlink(CEC_DEVTREE_RW_PATH);
7690166c15SMarri Devender Rao if (rwFileName.empty())
7790166c15SMarri Devender Rao {
7890166c15SMarri Devender Rao std::string err =
79e0dd7af4SJayanth Othayoth std::format("Failed to read the target file "
8090166c15SMarri Devender Rao "for the RW device tree symbolic link ({})",
8190166c15SMarri Devender Rao CEC_DEVTREE_RW_PATH);
8290166c15SMarri Devender Rao log<level::ERR>(err.c_str());
8390166c15SMarri Devender Rao throw std::runtime_error(err);
8490166c15SMarri Devender Rao }
8590166c15SMarri Devender Rao fs::path roFilePath = CEC_DEVTREE_RO_BASE_PATH / rwFileName;
8690166c15SMarri Devender Rao if (!fs::exists(roFilePath))
8790166c15SMarri Devender Rao {
88e0dd7af4SJayanth Othayoth auto err = std::format("RO device tree file ({}) does not "
8990166c15SMarri Devender Rao "exit ",
9090166c15SMarri Devender Rao roFilePath.string());
9190166c15SMarri Devender Rao log<level::ERR>(err.c_str());
9290166c15SMarri Devender Rao throw std::runtime_error(err);
9390166c15SMarri Devender Rao }
9490166c15SMarri Devender Rao return roFilePath;
9590166c15SMarri Devender Rao }
9690166c15SMarri Devender Rao
9790166c15SMarri Devender Rao /**
9894fc70cbSJayanth Othayoth * @brief reinitialize the devtree attributes.
9994fc70cbSJayanth Othayoth * In the regular host boot path devtree attribute need to
10094fc70cbSJayanth Othayoth * initialize the default data and also some of the selected
10194fc70cbSJayanth Othayoth * attributes need to preserve with previous boot value.
10294fc70cbSJayanth Othayoth * Preserve attribute list is available BMC pre-defined location.
10394fc70cbSJayanth Othayoth * This function helps to meet the host ipl requirement
10494fc70cbSJayanth Othayoth * related to attribute persistency management for host ipl.
10594fc70cbSJayanth Othayoth * Steps involved
10694fc70cbSJayanth Othayoth * 1. Create attribute data file from devtree r/w version based on
10794fc70cbSJayanth Othayoth * the reinit attribute list file bmc /usr/share/pdata path.
10894fc70cbSJayanth Othayoth * 2. Create temporary devtree file by copying devtree r/o file
10994fc70cbSJayanth Othayoth * 3. Override temporary copy of devtree with attribute data file
11094fc70cbSJayanth Othayoth * from step 1.
1115409e877SJayanth Othayoth * 3a. Apply user provided attribute override if present in the
1125409e877SJayanth Othayoth * predefined location.
11394fc70cbSJayanth Othayoth * 4. Copy temporary copy devtree to r/w devtree version file.
11494fc70cbSJayanth Othayoth */
11594fc70cbSJayanth Othayoth
reinitDevtree()11694fc70cbSJayanth Othayoth void reinitDevtree()
11794fc70cbSJayanth Othayoth {
11894fc70cbSJayanth Othayoth using json = nlohmann::json;
1194d5b5bfeSMarri Devender Rao using Severity =
1204d5b5bfeSMarri Devender Rao sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
12194fc70cbSJayanth Othayoth
12294fc70cbSJayanth Othayoth log<level::INFO>("reinitDevtree: started");
12394fc70cbSJayanth Othayoth
12494fc70cbSJayanth Othayoth // All the file operations is done on temporary copy
12594fc70cbSJayanth Othayoth // This is to avoid any file corruption issue during
12694fc70cbSJayanth Othayoth // copy or attribute import path.
12794fc70cbSJayanth Othayoth openpower::util::TemporaryFile tmpDevtreeFile{};
12894fc70cbSJayanth Othayoth const auto copyOptions = std::filesystem::copy_options::overwrite_existing;
12994fc70cbSJayanth Othayoth auto tmpDevtreePath = tmpDevtreeFile.getPath();
13094fc70cbSJayanth Othayoth bool tmpReinitDone = false;
13194fc70cbSJayanth Othayoth // To store callouts details in json format as per pel expectation.
13294fc70cbSJayanth Othayoth json jsonCalloutDataList;
13394fc70cbSJayanth Othayoth jsonCalloutDataList = json::array();
13494fc70cbSJayanth Othayoth
13594fc70cbSJayanth Othayoth try
13694fc70cbSJayanth Othayoth {
13794fc70cbSJayanth Othayoth // Check devtree reinit attributes list file is present
13894fc70cbSJayanth Othayoth auto attrFile = fs::path(DEVTREE_REINIT_ATTRS_LIST);
13994fc70cbSJayanth Othayoth if (!fs::exists(attrFile))
14094fc70cbSJayanth Othayoth {
14194fc70cbSJayanth Othayoth log<level::ERR>(
142e0dd7af4SJayanth Othayoth std::format(
14394fc70cbSJayanth Othayoth "devtree attribute export list file is not available: ({})",
14494fc70cbSJayanth Othayoth DEVTREE_REINIT_ATTRS_LIST)
14594fc70cbSJayanth Othayoth .c_str());
14694fc70cbSJayanth Othayoth throw std::runtime_error("reinitDevtree: missing export list file");
14794fc70cbSJayanth Othayoth }
14894fc70cbSJayanth Othayoth
14994fc70cbSJayanth Othayoth // create temporary data file to store the devtree export data
15094fc70cbSJayanth Othayoth openpower::util::TemporaryFile tmpFile{};
15194fc70cbSJayanth Othayoth
15294fc70cbSJayanth Othayoth {
15394fc70cbSJayanth Othayoth // get temporary datafile pointer.
154773fd244SJayanth Othayoth FILE_Ptr fpExport(fopen(tmpFile.getPath().c_str(), "w+"),
155773fd244SJayanth Othayoth FileCloser());
15694fc70cbSJayanth Othayoth
15794fc70cbSJayanth Othayoth if (fpExport.get() == nullptr)
15894fc70cbSJayanth Othayoth {
15994fc70cbSJayanth Othayoth log<level::ERR>(
160e0dd7af4SJayanth Othayoth std::format("Temporary data file failed to open: ({})",
16194fc70cbSJayanth Othayoth tmpFile.getPath().c_str())
16294fc70cbSJayanth Othayoth .c_str());
16394fc70cbSJayanth Othayoth throw std::runtime_error(
16494fc70cbSJayanth Othayoth "reinitDevtree: failed to open temporaray data file");
16594fc70cbSJayanth Othayoth }
16694fc70cbSJayanth Othayoth
16794fc70cbSJayanth Othayoth // Step 1: export devtree data based on the reinit attribute list.
168*1e43be06SPatrick Williams auto ret =
169*1e43be06SPatrick Williams dtree_cronus_export(CEC_DEVTREE_RW_PATH, CEC_INFODB_PATH,
170*1e43be06SPatrick Williams DEVTREE_REINIT_ATTRS_LIST, fpExport.get());
17194fc70cbSJayanth Othayoth if (ret)
17294fc70cbSJayanth Othayoth {
17394fc70cbSJayanth Othayoth log<level::ERR>(
174e0dd7af4SJayanth Othayoth std::format("Failed({}) to collect attribute export data",
17594fc70cbSJayanth Othayoth ret)
17694fc70cbSJayanth Othayoth .c_str());
17794fc70cbSJayanth Othayoth throw std::runtime_error(
17894fc70cbSJayanth Othayoth "reinitDevtree: dtree_cronus_export function failed");
17994fc70cbSJayanth Othayoth }
18094fc70cbSJayanth Othayoth }
18194fc70cbSJayanth Othayoth
18294fc70cbSJayanth Othayoth // Step 2: Create temporary devtree file by copying devtree r/o version
18390166c15SMarri Devender Rao fs::path roFilePath = computeRODeviceTreePath();
18490166c15SMarri Devender Rao std::filesystem::copy(roFilePath, tmpDevtreePath, copyOptions);
18594fc70cbSJayanth Othayoth
18694fc70cbSJayanth Othayoth // get r/o version data file pointer
187773fd244SJayanth Othayoth FILE_Ptr fpImport(fopen(tmpFile.getPath().c_str(), "r"), FileCloser());
18894fc70cbSJayanth Othayoth if (fpImport.get() == nullptr)
18994fc70cbSJayanth Othayoth {
19094fc70cbSJayanth Othayoth log<level::ERR>(
191e0dd7af4SJayanth Othayoth std::format("import, temporary data file failed to open: ({})",
19294fc70cbSJayanth Othayoth tmpFile.getPath().c_str())
19394fc70cbSJayanth Othayoth .c_str());
19494fc70cbSJayanth Othayoth throw std::runtime_error(
19594fc70cbSJayanth Othayoth "reinitDevtree: import, failed to open temporaray data file");
19694fc70cbSJayanth Othayoth }
19794fc70cbSJayanth Othayoth
19894fc70cbSJayanth Othayoth // Step 3: Update Devtree r/w version with data file attribute data.
19994fc70cbSJayanth Othayoth auto ret = dtree_cronus_import(tmpDevtreePath.c_str(), CEC_INFODB_PATH,
20094fc70cbSJayanth Othayoth fpImport.get());
20194fc70cbSJayanth Othayoth if (ret)
20294fc70cbSJayanth Othayoth {
20394fc70cbSJayanth Othayoth log<level::ERR>(
204e0dd7af4SJayanth Othayoth std::format("Failed({}) to update attribute data", ret)
20594fc70cbSJayanth Othayoth .c_str());
20694fc70cbSJayanth Othayoth throw std::runtime_error(
20794fc70cbSJayanth Othayoth "reinitDevtree: dtree_cronus_import function failed");
20894fc70cbSJayanth Othayoth }
2095409e877SJayanth Othayoth // Step 3.a: Apply user provided attribute override data if present.
2105409e877SJayanth Othayoth applyAttrOverride(tmpDevtreePath);
2115409e877SJayanth Othayoth
21294fc70cbSJayanth Othayoth // Temporary file reinit is success.
21394fc70cbSJayanth Othayoth tmpReinitDone = true;
21494fc70cbSJayanth Othayoth }
21594fc70cbSJayanth Othayoth catch (const std::exception& e)
21694fc70cbSJayanth Othayoth {
21794fc70cbSJayanth Othayoth // Any failures during temporary file re-init should create PEL
21894fc70cbSJayanth Othayoth // and continue with current version of devtree file to allow boot.
21994fc70cbSJayanth Othayoth log<level::ERR>(
220e0dd7af4SJayanth Othayoth std::format("reinitDevtree failed ({})", e.what()).c_str());
22194fc70cbSJayanth Othayoth json jsonCalloutDataList;
22294fc70cbSJayanth Othayoth jsonCalloutDataList = json::array();
22394fc70cbSJayanth Othayoth json jsonCalloutData;
22494fc70cbSJayanth Othayoth jsonCalloutData["Procedure"] = "BMC0001";
22594fc70cbSJayanth Othayoth jsonCalloutData["Priority"] = "M";
22694fc70cbSJayanth Othayoth jsonCalloutDataList.emplace_back(jsonCalloutData);
22794fc70cbSJayanth Othayoth openpower::pel::createErrorPEL(
2284d5b5bfeSMarri Devender Rao "org.open_power.PHAL.Error.devtreeReinit", jsonCalloutDataList, {},
2294d5b5bfeSMarri Devender Rao Severity::Error);
23094fc70cbSJayanth Othayoth }
23194fc70cbSJayanth Othayoth
23294fc70cbSJayanth Othayoth // Step 4: Update devtree r/w file
23394fc70cbSJayanth Othayoth try
23494fc70cbSJayanth Othayoth {
23594fc70cbSJayanth Othayoth if (tmpReinitDone)
23694fc70cbSJayanth Othayoth {
23794fc70cbSJayanth Othayoth // Step 4: Copy temporary version devtree file r/w version file.
23894fc70cbSJayanth Othayoth // Any copy failures should results service failure.
23994fc70cbSJayanth Othayoth std::filesystem::copy(tmpDevtreePath, CEC_DEVTREE_RW_PATH,
24094fc70cbSJayanth Othayoth copyOptions);
24194fc70cbSJayanth Othayoth log<level::INFO>("reinitDevtree: completed successfully");
24294fc70cbSJayanth Othayoth }
24394fc70cbSJayanth Othayoth else
24494fc70cbSJayanth Othayoth {
24594fc70cbSJayanth Othayoth // Attempt boot with genesis mode attribute data.
24690166c15SMarri Devender Rao fs::path roFilePath = computeRODeviceTreePath();
24794fc70cbSJayanth Othayoth log<level::WARNING>("reinitDevtree: DEVTREE(r/w) initilizing with "
24894fc70cbSJayanth Othayoth "genesis mode attribute data");
24990166c15SMarri Devender Rao std::filesystem::copy(roFilePath, CEC_DEVTREE_RW_PATH, copyOptions);
25094fc70cbSJayanth Othayoth }
25194fc70cbSJayanth Othayoth }
25294fc70cbSJayanth Othayoth catch (const std::exception& e)
25394fc70cbSJayanth Othayoth {
25494fc70cbSJayanth Othayoth // Any failures during update on r/w file is serious error should create
25594fc70cbSJayanth Othayoth // PEL, with code callout. Also failed the service.
25694fc70cbSJayanth Othayoth // and continue with current version of devtree file to allow boot.
25794fc70cbSJayanth Othayoth log<level::ERR>(
258e0dd7af4SJayanth Othayoth std::format("reinitDevtree r/w version update failed ({})",
25994fc70cbSJayanth Othayoth e.what())
26094fc70cbSJayanth Othayoth .c_str());
26194fc70cbSJayanth Othayoth json jsonCalloutDataList;
26294fc70cbSJayanth Othayoth jsonCalloutDataList = json::array();
26394fc70cbSJayanth Othayoth json jsonCalloutData;
26494fc70cbSJayanth Othayoth jsonCalloutData["Procedure"] = "BMC0001";
26594fc70cbSJayanth Othayoth jsonCalloutData["Priority"] = "H";
26694fc70cbSJayanth Othayoth jsonCalloutDataList.emplace_back(jsonCalloutData);
26794fc70cbSJayanth Othayoth openpower::pel::createErrorPEL(
2684d5b5bfeSMarri Devender Rao "org.open_power.PHAL.Error.devtreeReinit", jsonCalloutDataList, {},
2694d5b5bfeSMarri Devender Rao Severity::Error);
27094fc70cbSJayanth Othayoth throw;
27194fc70cbSJayanth Othayoth }
27294fc70cbSJayanth Othayoth }
27394fc70cbSJayanth Othayoth
27494fc70cbSJayanth Othayoth REGISTER_PROCEDURE("reinitDevtree", reinitDevtree)
27594fc70cbSJayanth Othayoth
27694fc70cbSJayanth Othayoth } // namespace phal
27794fc70cbSJayanth Othayoth } // namespace openpower
278