xref: /openbmc/smbios-mdr/src/firmware_inventory.cpp (revision ac4cb328365c7073a54da815c7f2362f1c64bf01)
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 {
getExistingVersionPaths(sdbusplus::bus_t & bus)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 
getFirmwareInventoryData(uint8_t * & dataIn,int inventoryIndex)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 
firmwareInfoUpdate(uint8_t * smbiosTableStorage)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 
checkAndCreateFirmwarePath(uint8_t * dataIn,int inventoryIndex,std::vector<std::string> & existingVersionPaths)94 std::string FirmwareInventory::checkAndCreateFirmwarePath(
95     uint8_t* dataIn, int inventoryIndex,
96     std::vector<std::string>& existingVersionPaths)
97 {
98     if (!getFirmwareInventoryData(dataIn, inventoryIndex))
99     {
100         lg2::info("Failed to get data for firmware inventory index {I}", "I",
101                   inventoryIndex);
102         return "";
103     }
104     auto firmwareInfo = reinterpret_cast<struct FirmwareInfo*>(dataIn);
105     std::string firmwareId =
106         positionToString(firmwareInfo->id, firmwareInfo->length, dataIn);
107     auto firmwareName = positionToString(firmwareInfo->componentName,
108                                          firmwareInfo->length, dataIn);
109     std::string firmwareObjPath = "";
110 #ifdef EXPOSE_FW_COMPONENT_NAME
111     firmwareObjPath = firmwareName;
112 #else
113     firmwareObjPath = firmwareId;
114 #endif
115     if (firmwareInfo->numOfAssociatedComponents > 0)
116     {
117         for (int i = 0; i < firmwareInfo->numOfAssociatedComponents; i++)
118         {
119             auto component = smbiosHandlePtr(
120                 dataIn, firmwareInfo->associatedComponentHandles[i]);
121             if (component == nullptr)
122             {
123                 continue;
124             }
125 
126             auto header = reinterpret_cast<struct StructureHeader*>(component);
127             switch (header->type)
128             {
129                 case processorsType:
130                 case systemSlots:
131                 case onboardDevicesExtended:
132                 {
133                     auto designation = positionToString(
134                         component[4], header->length, component);
135                     if (!designation.empty())
136                     {
137                         firmwareObjPath.append("_").append(designation);
138                     }
139                     break;
140                 }
141                 case systemPowerSupply:
142                 {
143                     auto location = positionToString(component[5],
144                                                      header->length, component);
145                     if (!location.empty())
146                     {
147                         firmwareObjPath.append("_").append(location);
148                     }
149                     break;
150                 }
151                 default:
152                     break;
153             }
154         }
155     }
156     if (firmwareObjPath.empty())
157     {
158         firmwareObjPath = "firmware" + std::to_string(inventoryIndex);
159     }
160     boost::algorithm::trim_right(firmwareObjPath);
161     firmwareObjPath =
162         std::regex_replace(firmwareObjPath, std::regex("[^a-zA-Z0-9_/]+"), "_");
163 
164     auto eqObjName = [firmwareObjPath](std::string s) {
165         std::filesystem::path p(s);
166         return p.filename().compare(firmwareObjPath) == 0;
167     };
168     if (std::find_if(existingVersionPaths.begin(), existingVersionPaths.end(),
169                      std::move(eqObjName)) != existingVersionPaths.end())
170     {
171         return "";
172     }
173     std::string path = firmwarePath;
174     path.append("/").append(firmwareObjPath);
175     return path;
176 }
177 
firmwareComponentName(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)178 void FirmwareInventory::firmwareComponentName(
179     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
180 {
181     std::string result = positionToString(positionNum, structLen, dataIn);
182     prettyName(result);
183 }
184 
firmwareVersion(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)185 void FirmwareInventory::firmwareVersion(
186     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
187 {
188     std::string result = positionToString(positionNum, structLen, dataIn);
189     version(result);
190 }
191 
firmwareId(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)192 void FirmwareInventory::firmwareId(const uint8_t positionNum,
193                                    const uint8_t structLen, uint8_t* dataIn)
194 {
195     std::string result = positionToString(positionNum, structLen, dataIn);
196     extendedVersion(result);
197 }
198 
firmwareReleaseDate(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)199 void FirmwareInventory::firmwareReleaseDate(
200     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
201 {
202     std::string result = positionToString(positionNum, structLen, dataIn);
203     releaseDate(result);
204 }
205 
firmwareManufacturer(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)206 void FirmwareInventory::firmwareManufacturer(
207     const uint8_t positionNum, const uint8_t structLen, uint8_t* dataIn)
208 {
209     std::string result = positionToString(positionNum, structLen, dataIn);
210     manufacturer(result);
211 }
212 } // namespace smbios
213 } // namespace phosphor
214