xref: /openbmc/smbios-mdr/src/firmware_inventory.cpp (revision 6981b7ffb8a81bd1ea90c8deba8466accbe2693b)
1 #include "firmware_inventory.hpp"
2 
3 #include "mdrv2.hpp"
4 
5 #include <boost/algorithm/string.hpp>
6 
7 #include <fstream>
8 #include <iomanip>
9 #include <iostream>
10 #include <regex>
11 #include <sstream>
12 
13 namespace phosphor
14 {
15 namespace smbios
16 {
17 namespace utils
18 {
19 std::vector<std::string> getExistingVersionPaths(sdbusplus::bus_t& bus)
20 {
21     std::vector<std::string> existingVersionPaths;
22 
23     auto getVersionPaths = bus.new_method_call(
24         phosphor::smbios::mapperBusName, phosphor::smbios::mapperPath,
25         phosphor::smbios::mapperInterface, "GetSubTreePaths");
26     getVersionPaths.append(firmwarePath);
27     getVersionPaths.append(0);
28     getVersionPaths.append(
29         std::array<std::string, 1>({phosphor::smbios::versionInterface}));
30 
31     try
32     {
33         auto reply = bus.call(getVersionPaths);
34         reply.read(existingVersionPaths);
35     }
36     catch (const sdbusplus::exception_t& e)
37     {
38         lg2::error("Failed to query version objects. ERROR={E}", "E", e.what());
39         existingVersionPaths.clear();
40     }
41 
42     return existingVersionPaths;
43 }
44 } // namespace utils
45 
46 bool FirmwareInventory::getFirmwareInventoryData(uint8_t*& dataIn,
47                                                  int inventoryIndex)
48 {
49     dataIn = getSMBIOSTypePtr(dataIn, firmwareInventoryInformationType);
50     if (dataIn == nullptr)
51     {
52         return false;
53     }
54     for (uint8_t index = 0; index < inventoryIndex; index++)
55     {
56         dataIn = smbiosNextPtr(dataIn);
57         if (dataIn == nullptr)
58         {
59             return false;
60         }
61         dataIn = getSMBIOSTypePtr(dataIn, firmwareInventoryInformationType);
62         if (dataIn == nullptr)
63         {
64             return false;
65         }
66     }
67     return true;
68 }
69 
70 void FirmwareInventory::firmwareInfoUpdate(uint8_t* smbiosTableStorage)
71 {
72     uint8_t* dataIn = smbiosTableStorage;
73     if (!getFirmwareInventoryData(dataIn, firmwareInventoryIndex))
74     {
75         lg2::info("Failed to get data for firmware inventory index {I}", "I",
76                   firmwareInventoryIndex);
77         return;
78     }
79 
80     auto firmwareInfo = reinterpret_cast<struct FirmwareInfo*>(dataIn);
81 
82     firmwareComponentName(firmwareInfo->componentName, firmwareInfo->length,
83                           dataIn);
84     firmwareVersion(firmwareInfo->version, firmwareInfo->length, dataIn);
85     firmwareId(firmwareInfo->id, firmwareInfo->length, dataIn);
86     firmwareReleaseDate(firmwareInfo->releaseDate, firmwareInfo->length,
87                         dataIn);
88     firmwareManufacturer(firmwareInfo->manufacturer, firmwareInfo->length,
89                          dataIn);
90     present(true);
91     purpose(softwareVersion::VersionPurpose::Other);
92 
93     std::vector<std::tuple<std::string, std::string, std::string>> assocs;
94     assocs.emplace_back("software_version", "functional",
95                         "/xyz/openbmc_project/software");
96     association::associations(assocs);
97 }
98 
99 std::string FirmwareInventory::checkAndCreateFirmwarePath(
100     uint8_t* dataIn, int inventoryIndex,
101     std::vector<std::string>& existingVersionPaths)
102 {
103     if (!getFirmwareInventoryData(dataIn, inventoryIndex))
104     {
105         lg2::info("Failed to get data for firmware inventory index {I}", "I",
106                   inventoryIndex);
107         return "";
108     }
109     auto firmwareInfo = reinterpret_cast<struct FirmwareInfo*>(dataIn);
110     std::string firmwareId =
111         positionToString(firmwareInfo->id, firmwareInfo->length, dataIn);
112     auto firmwareName = positionToString(firmwareInfo->componentName,
113                                          firmwareInfo->length, dataIn);
114     std::string firmwareObjPath = "";
115 #ifdef EXPOSE_FW_COMPONENT_NAME
116     firmwareObjPath = firmwareName;
117 #else
118     firmwareObjPath = firmwareId;
119 #endif
120     if (firmwareInfo->numOfAssociatedComponents > 0)
121     {
122         for (int i = 0; i < firmwareInfo->numOfAssociatedComponents; i++)
123         {
124             auto component = smbiosHandlePtr(
125                 dataIn, firmwareInfo->associatedComponentHandles[i]);
126             if (component == nullptr)
127             {
128                 continue;
129             }
130 
131             auto header = reinterpret_cast<struct StructureHeader*>(component);
132             switch (header->type)
133             {
134                 case processorsType:
135                 case systemSlots:
136                 case onboardDevicesExtended:
137                 {
138                     auto designation = positionToString(
139                         component[4], header->length, component);
140                     if (!designation.empty())
141                     {
142                         firmwareObjPath.append("_").append(designation);
143                     }
144                     break;
145                 }
146                 case systemPowerSupply:
147                 {
148                     auto location = positionToString(component[5],
149                                                      header->length, component);
150                     if (!location.empty())
151                     {
152                         firmwareObjPath.append("_").append(location);
153                     }
154                     break;
155                 }
156                 default:
157                     break;
158             }
159         }
160     }
161     if (firmwareObjPath.empty())
162     {
163         firmwareObjPath = "firmware" + std::to_string(inventoryIndex);
164     }
165     boost::algorithm::trim_right(firmwareObjPath);
166     firmwareObjPath =
167         std::regex_replace(firmwareObjPath, std::regex("[^a-zA-Z0-9_/]+"), "_");
168 
169     auto eqObjName = [firmwareObjPath](std::string s) {
170         std::filesystem::path p(s);
171         return p.filename().compare(firmwareObjPath) == 0;
172     };
173     if (std::find_if(existingVersionPaths.begin(), existingVersionPaths.end(),
174                      std::move(eqObjName)) != existingVersionPaths.end())
175     {
176         return "";
177     }
178     std::string path = firmwarePath;
179     path.append("/").append(firmwareObjPath);
180     return path;
181 }
182 
183 void FirmwareInventory::firmwareComponentName(
184     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
185 {
186     std::string result = positionToString(positionNum, structLen, dataIn);
187     prettyName(result);
188 }
189 
190 void FirmwareInventory::firmwareVersion(
191     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
192 {
193     std::string result = positionToString(positionNum, structLen, dataIn);
194     version(result);
195 }
196 
197 void FirmwareInventory::firmwareId(const uint8_t positionNum,
198                                    const uint8_t structLen, uint8_t* dataIn)
199 {
200     std::string result = positionToString(positionNum, structLen, dataIn);
201     extendedVersion(result);
202 }
203 
204 void FirmwareInventory::firmwareReleaseDate(
205     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
206 {
207     std::string result = positionToString(positionNum, structLen, dataIn);
208     buildDate(result);
209 }
210 
211 void FirmwareInventory::firmwareManufacturer(
212     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
213 {
214     std::string result = positionToString(positionNum, structLen, dataIn);
215     manufacturer(result);
216 }
217 } // namespace smbios
218 } // namespace phosphor
219