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 
64 void ItemUpdaterMMC::reset()
65 {
66     // Do not reset read-only files needed for reset or ext4 default files
67     const std::vector<std::string> exclusionList = {"alternate", "hostfw-a",
68                                                     "hostfw-b",  "lost+found",
69                                                     "nvram",     "running-ro"};
70     std::filesystem::path dirPath(std::string(MEDIA_DIR "hostfw/"));
71     // Delete all files in /media/hostfw/ except for those on exclusionList
72     for (const auto& p : std::filesystem::directory_iterator(dirPath))
73     {
74         if (std::find(exclusionList.begin(), exclusionList.end(),
75                       p.path().stem().string()) == exclusionList.end())
76         {
77             std::filesystem::remove_all(p);
78         }
79     }
80 
81     // Delete all BMC error logs to avoid discrepancies with the host error logs
82     utils::deleteAllErrorLogs(bus);
83 
84     // Set attribute to clear hypervisor NVRAM
85     utils::setClearNvram(bus);
86 
87     // reset the enabled property of dimms/cpu after factory reset
88     gardReset->reset();
89 
90     // Remove files related to the Hardware Management Console / BMC web app
91     utils::clearHMCManaged(bus);
92     std::filesystem::path consolePath("/var/lib/bmcweb/ibm-management-console");
93     if (std::filesystem::exists(consolePath))
94     {
95         std::filesystem::remove_all(consolePath);
96     }
97     std::filesystem::path bmcdataPath("/home/root/bmcweb_persistent_data.json");
98     if (std::filesystem::exists(bmcdataPath))
99     {
100         std::filesystem::remove(bmcdataPath);
101     }
102 
103     // Recreate default files.
104     // std::tuple<method, service_name>
105     const std::tuple<std::string, std::string> services[] = {
106         {"StartUnit", "obmc-flash-bios-init.service"},
107         {"StartUnit", "obmc-flash-bios-patch.service"},
108         {"StartUnit", "openpower-process-host-firmware.service"},
109         {"StartUnit", "openpower-update-bios-attr-table.service"},
110         {"RestartUnit", "org.open_power.HardwareIsolation.service"}};
111 
112     for (const auto& service : services)
113     {
114         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
115                                           SYSTEMD_INTERFACE,
116                                           std::get<0>(service).c_str());
117         method.append(std::get<1>(service), "replace");
118         // Ignore errors if the service is not found - not all systems
119         // may have these services
120         try
121         {
122             bus.call_noreply(method);
123         }
124         catch (const std::exception& e)
125         {}
126     }
127 
128     // Wait a few seconds for the service files and reset operations to finish,
129     // otherwise the BMC may be rebooted and cause corruption.
130     constexpr auto resetWait = std::chrono::seconds(5);
131     std::this_thread::sleep_for(resetWait);
132 }
133 
134 bool ItemUpdaterMMC::isVersionFunctional(const std::string& versionId)
135 {
136     return versionId == functionalVersionId;
137 }
138 
139 void ItemUpdaterMMC::freePriority(uint8_t, const std::string&)
140 {}
141 
142 void ItemUpdaterMMC::deleteAll()
143 {}
144 
145 bool ItemUpdaterMMC::freeSpace()
146 {
147     return true;
148 }
149 
150 void ItemUpdaterMMC::updateFunctionalAssociation(const std::string&)
151 {}
152 void GardResetMMC::enableInventoryItems()
153 {
154     (void)enableInventoryItemsHelper(
155         "xyz.openbmc_project.PLDM",
156         "xyz.openbmc_project.Inventory.Item.CpuCore",
157         "/xyz/openbmc_project/inventory/system/chassis/motherboard");
158 
159     (void)enableInventoryItemsHelper("xyz.openbmc_project.Inventory.Manager",
160                                      "xyz.openbmc_project.Inventory.Item.Dimm",
161                                      "/xyz/openbmc_project/inventory");
162 }
163 
164 void GardResetMMC::enableInventoryItemsHelper(const std::string& service,
165                                               const std::string& intf,
166                                               const std::string& objPath)
167 {
168     const std::vector<std::string> intflist{intf};
169 
170     std::vector<std::string> objs;
171     try
172     {
173         auto mapperCall = bus.new_method_call(
174             "xyz.openbmc_project.ObjectMapper",
175             "/xyz/openbmc_project/object_mapper",
176             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
177         mapperCall.append(objPath);
178         mapperCall.append(0);
179         mapperCall.append(intflist);
180 
181         auto response = bus.call(mapperCall);
182         response.read(objs);
183         for (auto& obj : objs)
184         {
185             auto method =
186                 bus.new_method_call(service.c_str(), obj.c_str(),
187                                     "org.freedesktop.DBus.Properties", "Set");
188             std::variant<bool> propertyVal{true};
189             method.append("xyz.openbmc_project.Object.Enable", "Enabled",
190                           propertyVal);
191             bus.call_noreply(method);
192         }
193     }
194     catch (const sdbusplus::exception_t& e)
195     {
196         log<level::ERR>(
197             fmt::format("Failed to enable specified inventory items ex({}) "
198                         "intf({}) objpath({})",
199                         e.what(), intf, objPath)
200                 .c_str());
201     }
202 }
203 
204 void GardResetMMC::reset()
205 {
206     log<level::INFO>("GardResetMMC::reset");
207     (void)enableInventoryItems();
208 }
209 
210 } // namespace updater
211 } // namespace software
212 } // namespace openpower
213