blob: a500a0061fe7a472e04f2921acfdd5a88d3dcef2 [file] [log] [blame]
Tom Joseph151d5332019-11-17 22:21:45 +05301#include "fru_parser.hpp"
2
George Liu6492f522020-06-16 10:34:05 +08003#include <nlohmann/json.hpp>
4#include <xyz/openbmc_project/Common/error.hpp>
5
Tom Joseph151d5332019-11-17 22:21:45 +05306#include <filesystem>
7#include <fstream>
8#include <iostream>
Tom Joseph151d5332019-11-17 22:21:45 +05309
10namespace pldm
11{
12
13namespace responder
14{
15
16namespace fru_parser
17{
18
19using Json = nlohmann::json;
20using InternalFailure =
21 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
22
23const Json emptyJson{};
24const std::vector<Json> emptyJsonList{};
25const std::vector<std::string> emptyStringVec{};
26
27constexpr auto fruMasterJson = "FRU_Master.json";
28
29FruParser::FruParser(const std::string& dirPath)
30{
31 fs::path dir(dirPath);
32 if (!fs::exists(dir) || fs::is_empty(dir))
33 {
John Wang55732c22020-05-14 10:33:00 +080034 setupDefaultDBusLookup();
35 setupDefaultFruRecordMap();
Tom Josephf0076332020-02-06 10:18:50 +053036 return;
Tom Joseph151d5332019-11-17 22:21:45 +053037 }
38
39 fs::path masterFilePath = dir / fruMasterJson;
40 if (!fs::exists(masterFilePath))
41 {
42 std::cerr << "FRU D-Bus lookup JSON does not exist, PATH="
Tom Josephf0076332020-02-06 10:18:50 +053043 << masterFilePath << "\n";
Tom Joseph151d5332019-11-17 22:21:45 +053044 throw InternalFailure();
45 }
46
47 setupDBusLookup(masterFilePath);
48 setupFruRecordMap(dirPath);
49}
50
John Wang55732c22020-05-14 10:33:00 +080051void FruParser::setupDefaultDBusLookup()
52{
53 constexpr auto service = "xyz.openbmc_project.Inventory.Manager";
54 constexpr auto rootPath = "/xyz/openbmc_project/inventory";
55
56 // DSP0249 1.0.0 Table 15 Entity ID Codes
57 const std::map<Interface, EntityType> defIntfToEntityType = {
58 {"xyz.openbmc_project.Inventory.Item.Chassis", 45},
59 {"xyz.openbmc_project.Inventory.Item.Board", 60},
60 {"xyz.openbmc_project.Inventory.Item.Board.Motherboard", 64},
61 {"xyz.openbmc_project.Inventory.Item.Panel", 69},
62 {"xyz.openbmc_project.Inventory.Item.PowerSupply", 120},
63 {"xyz.openbmc_project.Inventory.Item.Vrm", 123},
64 {"xyz.openbmc_project.Inventory.Item.Cpu", 135},
65 {"xyz.openbmc_project.Inventory.Item.Bmc", 137},
66 {"xyz.openbmc_project.Inventory.Item.Dimm", 142},
67 };
68
69 Interfaces interfaces{};
70 for (auto [intf, entityType] : defIntfToEntityType)
71 {
72 intfToEntityType[intf] = entityType;
73 interfaces.emplace(intf);
74 }
75
76 lookupInfo.emplace(service, rootPath, std::move(interfaces));
77}
78
Tom Joseph151d5332019-11-17 22:21:45 +053079void FruParser::setupDBusLookup(const fs::path& filePath)
80{
81 std::ifstream jsonFile(filePath);
82
83 auto data = Json::parse(jsonFile, nullptr, false);
84 if (data.is_discarded())
85 {
86 std::cerr << "Parsing FRU master config file failed, FILE=" << filePath;
87 throw InternalFailure();
88 }
89
90 Service service = data.value("service", "");
91 RootPath rootPath = data.value("root_path", "");
Deepak Kodihalli3cd61812020-03-10 06:38:45 -050092 auto entities = data.value("entities", emptyJsonList);
93 Interfaces interfaces{};
94 EntityType entityType{};
95 for (auto& entity : entities)
96 {
97 auto intf = entity.value("interface", "");
98 intfToEntityType[intf] =
99 std::move(entity.value("entity_type", entityType));
100 interfaces.emplace(std::move(intf));
101 }
Tom Joseph151d5332019-11-17 22:21:45 +0530102 lookupInfo.emplace(std::make_tuple(std::move(service), std::move(rootPath),
103 std::move(interfaces)));
104}
105
John Wang55732c22020-05-14 10:33:00 +0800106void FruParser::setupDefaultFruRecordMap()
107{
108 const FruRecordInfo generalRecordInfo = {
109 1, // generalRecordType
110 1, // encodingTypeASCII
111 {
112 // DSP0257 Table 5 General FRU Record Field Type Definitions
113 {"xyz.openbmc_project.Inventory.Decorator.Asset", "Model", "string",
114 2},
115 {"xyz.openbmc_project.Inventory.Decorator.Asset", "PartNumber",
116 "string", 3},
117 {"xyz.openbmc_project.Inventory.Decorator.Asset", "SerialNumber",
118 "string", 4},
119 {"xyz.openbmc_project.Inventory.Decorator.Asset", "Manufacturer",
120 "string", 5},
121 {"xyz.openbmc_project.Inventory.Item", "PrettyName", "string", 8},
122 {"xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
123 "string", 11},
124 {"xyz.openbmc_project.Inventory.Decorator.Revision", "Version",
125 "string", 10},
126 }};
127
128 for (auto [intf, entityType] : intfToEntityType)
129 {
130 recordMap[intf] = {generalRecordInfo};
131 }
132}
133
Tom Joseph151d5332019-11-17 22:21:45 +0530134void FruParser::setupFruRecordMap(const std::string& dirPath)
135{
136 for (auto& file : fs::directory_iterator(dirPath))
137 {
138 auto fileName = file.path().filename().string();
139 if (fruMasterJson == fileName)
140 {
141 continue;
142 }
143
144 std::ifstream jsonFile(file.path());
145 auto data = Json::parse(jsonFile, nullptr, false);
146 if (data.is_discarded())
147 {
148
149 std::cerr << "Parsing FRU master config file failed, FILE="
150 << file.path();
151 throw InternalFailure();
152 }
153
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500154 try
Tom Joseph151d5332019-11-17 22:21:45 +0530155 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500156 auto record = data.value("record_details", emptyJson);
157 auto recordType =
158 static_cast<uint8_t>(record.value("fru_record_type", 0));
159 auto encType =
160 static_cast<uint8_t>(record.value("fru_encoding_type", 0));
161 auto dbusIntfName = record.value("dbus_interface_name", "");
162 auto entries = data.value("fru_fields", emptyJsonList);
163 std::vector<FieldInfo> fieldInfo;
164
165 for (const auto& entry : entries)
166 {
167 auto fieldType =
168 static_cast<uint8_t>(entry.value("fru_field_type", 0));
169 auto dbus = entry.value("dbus", emptyJson);
170 auto interface = dbus.value("interface", "");
171 auto property = dbus.value("property_name", "");
172 auto propType = dbus.value("property_type", "");
173 fieldInfo.emplace_back(
174 std::make_tuple(std::move(interface), std::move(property),
175 std::move(propType), std::move(fieldType)));
176 }
177
178 FruRecordInfo fruInfo;
179 fruInfo =
180 std::make_tuple(recordType, encType, std::move(fieldInfo));
181
182 auto search = recordMap.find(dbusIntfName);
183
184 // PLDM FRU can have multiple records for the same FRU like General
185 // FRU record and multiple OEM FRU records. If the FRU item
186 // interface name is already in the map, that indicates a record
187 // info is already added for the FRU, so append the new record info
188 // to the same data.
189 if (search != recordMap.end())
190 {
191 search->second.emplace_back(std::move(fruInfo));
192 }
193 else
194 {
195 FruRecordInfos recordInfos{fruInfo};
196 recordMap.emplace(dbusIntfName, recordInfos);
197 }
Tom Joseph151d5332019-11-17 22:21:45 +0530198 }
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500199 catch (const std::exception& e)
Tom Joseph151d5332019-11-17 22:21:45 +0530200 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500201 continue;
Tom Joseph151d5332019-11-17 22:21:45 +0530202 }
203 }
204}
205
206} // namespace fru_parser
207
208} // namespace responder
209
210} // namespace pldm