1 #include "config.h"
2 
3 #include "item_updater_mmc.hpp"
4 
5 #include "activation_mmc.hpp"
6 #include "utils.hpp"
7 #include "version.hpp"
8 
9 #include <fmt/core.h>
10 
11 #include <phosphor-logging/log.hpp>
12 
13 #include <filesystem>
14 #include <iostream>
15 #include <thread>
16 
17 namespace openpower
18 {
19 namespace software
20 {
21 namespace updater
22 {
23 
24 using ::phosphor::logging::level;
25 using ::phosphor::logging::log;
26 // These functions are just a stub (empty) because the current eMMC
27 // implementation uses the BMC updater (repo phosphor-bmc-code-mgmt) to write
28 // the new host FW to flash since it's delivered as a "System" image in the
29 // same BMC tarball as the BMC image.
30 
31 std::unique_ptr<Activation> ItemUpdaterMMC::createActivationObject(
32     const std::string& path, const std::string& versionId,
33     const std::string& extVersion,
34     sdbusplus::xyz::openbmc_project::Software::server::Activation::Activations
35         activationStatus,
36     AssociationList& assocs)
37 {
38     return std::make_unique<ActivationMMC>(
39         bus, path, *this, versionId, extVersion, activationStatus, assocs);
40 }
41 
42 std::unique_ptr<Version> ItemUpdaterMMC::createVersionObject(
43     const std::string& objPath, const std::string& versionId,
44     const std::string& versionString,
45     sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
46         versionPurpose,
47     const std::string& filePath)
48 {
49     auto version = std::make_unique<Version>(
50         bus, objPath, *this, versionId, versionString, versionPurpose, filePath,
51         std::bind(&ItemUpdaterMMC::erase, this, std::placeholders::_1));
52     version->deleteObject = std::make_unique<Delete>(bus, objPath, *version);
53     return version;
54 }
55 
56 bool ItemUpdaterMMC::validateImage(const std::string&)
57 {
58     return true;
59 }
60 
61 void ItemUpdaterMMC::processPNORImage() {}
62 
63 void ItemUpdaterMMC::reset()
64 {
65     // Do not reset read-only files needed for reset or ext4 default files
66     const std::vector<std::string> exclusionList = {"alternate", "hostfw-a",
67                                                     "hostfw-b",  "lost+found",
68                                                     "nvram",     "running-ro"};
69     std::filesystem::path dirPath(std::string(MEDIA_DIR "hostfw/"));
70     // Delete all files in /media/hostfw/ except for those on exclusionList
71     for (const auto& p : std::filesystem::directory_iterator(dirPath))
72     {
73         if (std::find(exclusionList.begin(), exclusionList.end(),
74                       p.path().stem().string()) == exclusionList.end())
75         {
76             std::filesystem::remove_all(p);
77         }
78     }
79 
80     // Delete all BMC error logs to avoid discrepancies with the host error logs
81     utils::deleteAllErrorLogs(bus);
82 
83     // Set attribute to clear hypervisor NVRAM
84     utils::setClearNvram(bus);
85 
86     // reset the enabled property of dimms/cpu after factory reset
87     gardReset->reset();
88 
89     // Remove files related to the Hardware Management Console / BMC web app
90     utils::clearHMCManaged(bus);
91     std::filesystem::path consolePath("/var/lib/bmcweb/ibm-management-console");
92     if (std::filesystem::exists(consolePath))
93     {
94         std::filesystem::remove_all(consolePath);
95     }
96     std::filesystem::path bmcdataPath("/home/root/bmcweb_persistent_data.json");
97     if (std::filesystem::exists(bmcdataPath))
98     {
99         std::filesystem::remove(bmcdataPath);
100     }
101 
102     // Recreate default files.
103     // std::tuple<method, service_name>
104     const std::tuple<std::string, std::string> services[] = {
105         {"StartUnit", "obmc-flash-bios-init.service"},
106         {"StartUnit", "obmc-flash-bios-patch.service"},
107         {"StartUnit", "openpower-process-host-firmware.service"},
108         {"StartUnit", "openpower-update-bios-attr-table.service"},
109         {"RestartUnit", "org.open_power.HardwareIsolation.service"}};
110 
111     for (const auto& service : services)
112     {
113         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
114                                           SYSTEMD_INTERFACE,
115                                           std::get<0>(service).c_str());
116         method.append(std::get<1>(service), "replace");
117         // Ignore errors if the service is not found - not all systems
118         // may have these services
119         try
120         {
121             bus.call_noreply(method);
122         }
123         catch (const std::exception& e)
124         {}
125     }
126 
127     // Wait a few seconds for the service files and reset operations to finish,
128     // otherwise the BMC may be rebooted and cause corruption.
129     constexpr auto resetWait = std::chrono::seconds(5);
130     std::this_thread::sleep_for(resetWait);
131 }
132 
133 bool ItemUpdaterMMC::isVersionFunctional(const std::string& versionId)
134 {
135     return versionId == functionalVersionId;
136 }
137 
138 void ItemUpdaterMMC::freePriority(uint8_t, const std::string&) {}
139 
140 void ItemUpdaterMMC::deleteAll() {}
141 
142 bool ItemUpdaterMMC::freeSpace()
143 {
144     return true;
145 }
146 
147 void ItemUpdaterMMC::updateFunctionalAssociation(const std::string&) {}
148 void GardResetMMC::enableInventoryItems()
149 {
150     (void)enableInventoryItemsHelper(
151         "xyz.openbmc_project.PLDM",
152         "xyz.openbmc_project.Inventory.Item.CpuCore",
153         "/xyz/openbmc_project/inventory/system/chassis/motherboard");
154 
155     (void)enableInventoryItemsHelper("xyz.openbmc_project.Inventory.Manager",
156                                      "xyz.openbmc_project.Inventory.Item.Dimm",
157                                      "/xyz/openbmc_project/inventory");
158 }
159 
160 void GardResetMMC::enableInventoryItemsHelper(const std::string& service,
161                                               const std::string& intf,
162                                               const std::string& objPath)
163 {
164     const std::vector<std::string> intflist{intf};
165 
166     std::vector<std::string> objs;
167     try
168     {
169         auto mapperCall = bus.new_method_call(
170             "xyz.openbmc_project.ObjectMapper",
171             "/xyz/openbmc_project/object_mapper",
172             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
173         mapperCall.append(objPath);
174         mapperCall.append(0);
175         mapperCall.append(intflist);
176 
177         auto response = bus.call(mapperCall);
178         response.read(objs);
179         for (auto& obj : objs)
180         {
181             auto method = bus.new_method_call(service.c_str(), obj.c_str(),
182                                               "org.freedesktop.DBus.Properties",
183                                               "Set");
184             std::variant<bool> propertyVal{true};
185             method.append("xyz.openbmc_project.Object.Enable", "Enabled",
186                           propertyVal);
187             bus.call_noreply(method);
188         }
189     }
190     catch (const sdbusplus::exception_t& e)
191     {
192         log<level::ERR>(
193             fmt::format("Failed to enable specified inventory items ex({}) "
194                         "intf({}) objpath({})",
195                         e.what(), intf, objPath)
196                 .c_str());
197     }
198 }
199 
200 void GardResetMMC::reset()
201 {
202     log<level::INFO>("GardResetMMC::reset");
203     (void)enableInventoryItems();
204 }
205 
206 } // namespace updater
207 } // namespace software
208 } // namespace openpower
209