blob: de1896fca401c1578cc8424d166a2fbc542a1ecd [file] [log] [blame]
Deepak Kodihalli4a475bd2016-11-24 07:08:20 -06001#include <sstream>
Deepak Kodihalli810c9de2016-11-22 11:42:51 -06002#include <exception>
3#include <iostream>
4#include <iterator>
Deepak Kodihalli4a475bd2016-11-24 07:08:20 -06005#include <iomanip>
6#include <tuple>
7#include <algorithm>
8#include "defines.hpp"
Deepak Kodihalli810c9de2016-11-22 11:42:51 -06009#include "impl.hpp"
10
11namespace openpower
12{
13namespace vpd
14{
15namespace parser
16{
17
Deepak Kodihallia1143462016-11-24 06:28:45 -060018static const std::unordered_map<std::string, Record> supportedRecords =
19{
20 {"VINI", Record::VINI},
21 {"OPFR", Record::OPFR},
22 {"OSYS", Record::OSYS}
23};
24
Deepak Kodihalli4a475bd2016-11-24 07:08:20 -060025static constexpr auto MAC_ADDRESS_LEN_BYTES = 6;
26
27static const std::unordered_map<std::string,
28 internal::KeywordInfo> supportedKeywords =
29{
30 {"DR", std::make_tuple(record::Keyword::DR, keyword::Encoding::ASCII)},
31 {"PN", std::make_tuple(record::Keyword::PN, keyword::Encoding::ASCII)},
32 {"SN", std::make_tuple(record::Keyword::SN, keyword::Encoding::ASCII)},
33 {"CC", std::make_tuple(record::Keyword::CC, keyword::Encoding::ASCII)},
34 {"HW", std::make_tuple(record::Keyword::HW, keyword::Encoding::RAW)},
35 {"B1", std::make_tuple(record::Keyword::B1, keyword::Encoding::B1)},
36 {"VN", std::make_tuple(record::Keyword::VN, keyword::Encoding::ASCII)},
37 {"MB", std::make_tuple(record::Keyword::MB, keyword::Encoding::RAW)},
38 {"MM", std::make_tuple(record::Keyword::MM, keyword::Encoding::ASCII)}
39};
40
Deepak Kodihalli023112f2016-11-22 22:02:14 -060041namespace
42{
43
44using RecordId = uint8_t;
45using RecordOffset = uint16_t;
46using RecordSize = uint16_t;
47using RecordType = uint16_t;
48using RecordLength = uint16_t;
49using KwSize = uint8_t;
50using ECCOffset = uint16_t;
51using ECCLength = uint16_t;
52
Deepak Kodihalli4a475bd2016-11-24 07:08:20 -060053constexpr auto toHex(size_t c)
54{
55 constexpr auto map = "0123456789abcdef";
56 return map[c];
57}
58
Deepak Kodihalli023112f2016-11-22 22:02:14 -060059}
60
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060061namespace offsets
62{
63
64enum Offsets
65{
Deepak Kodihalli023112f2016-11-22 22:02:14 -060066 VHDR = 17,
67 VHDR_TOC_ENTRY = 29,
68 VTOC_PTR = 35,
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060069};
70
71}
72
73namespace lengths
74{
75
76enum Lengths
77{
78 RECORD_NAME = 4,
Deepak Kodihalli023112f2016-11-22 22:02:14 -060079 KW_NAME = 2,
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060080 RECORD_MIN = 44,
81};
82
83}
84
85void Impl::checkHeader() const
86{
87 if (vpd.empty() || (lengths::RECORD_MIN > vpd.size()))
88 {
89 throw std::runtime_error("Malformed VPD");
90 }
91 else
92 {
93 auto iterator = vpd.cbegin();
94 std::advance(iterator, offsets::VHDR);
95 auto stop = std::next(iterator, lengths::RECORD_NAME);
96 std::string record(iterator, stop);
97 if ("VHDR" != record)
98 {
99 throw std::runtime_error("VHDR record not found");
100 }
101 }
102}
103
Deepak Kodihalli023112f2016-11-22 22:02:14 -0600104internal::OffsetList Impl::readTOC() const
105{
106 internal::OffsetList offsets {};
107
108 // The offset to VTOC could be 1 or 2 bytes long
109 RecordOffset vtocOffset = vpd.at(offsets::VTOC_PTR);
110 RecordOffset highByte = vpd.at(offsets::VTOC_PTR + 1);
111 vtocOffset |= (highByte << 8);
112
113 // Got the offset to VTOC, skip past record header and keyword header
114 // to get to the record name.
115 auto iterator = vpd.cbegin();
116 std::advance(iterator,
117 vtocOffset +
118 sizeof(RecordId) +
119 sizeof(RecordSize) +
120 // Skip past the RT keyword, which contains
121 // the record name.
122 lengths::KW_NAME +
123 sizeof(KwSize));
124
125 auto stop = std::next(iterator, lengths::RECORD_NAME);
126 std::string record(iterator, stop);
127 if ("VTOC" != record)
128 {
129 throw std::runtime_error("VTOC record not found");
130 }
131
132 // VTOC record name is good, now read through the TOC, stored in the PT
133 // PT keyword; vpdBuffer is now pointing at the first character of the
134 // name 'VTOC', jump to PT data.
135 // Skip past record name and KW name, 'PT'
136 std::advance(iterator, lengths::RECORD_NAME + lengths::KW_NAME);
137 // Note size of PT
138 std::size_t ptLen = *iterator;
139 // Skip past PT size
140 std::advance(iterator, sizeof(KwSize));
141
142 // vpdBuffer is now pointing to PT data
143 return readPT(iterator, ptLen);
144}
145
146internal::OffsetList Impl::readPT(Binary::const_iterator iterator,
147 std::size_t ptLength) const
148{
149 internal::OffsetList offsets{};
150
151 auto end = iterator;
152 std::advance(end, ptLength);
153
154 // Look at each entry in the PT keyword. In the entry,
155 // we care only about the record offset information.
156 while (iterator < end)
157 {
158 // Skip record name and record type
159 std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType));
160
161 // Get record offset
162 RecordOffset offset = *iterator;
163 RecordOffset highByte = *(iterator + 1);
164 offset |= (highByte << 8);
165 offsets.push_back(offset);
166
167 // Jump record size, record length, ECC offset and ECC length
168 std::advance(iterator,
169 sizeof(RecordSize) +
170 sizeof(RecordLength) +
171 sizeof(ECCOffset) +
172 sizeof(ECCLength));
173 }
174
175 return offsets;
176}
177
Deepak Kodihallia1143462016-11-24 06:28:45 -0600178void Impl::processRecord(std::size_t recordOffset)
179{
180 // Jump to record name
181 auto nameOffset = recordOffset +
182 sizeof(RecordId) +
183 sizeof(RecordSize) +
184 // Skip past the RT keyword, which contains
185 // the record name.
186 lengths::KW_NAME +
187 sizeof(KwSize);
188 // Get record name
189 auto iterator = vpd.cbegin();
190 std::advance(iterator, nameOffset);
191
192 std::string name(iterator, iterator + lengths::RECORD_NAME);
193 if (supportedRecords.end() != supportedRecords.find(name))
194 {
195 // If it's a record we're interested in, proceed to find
196 // contained keywords and their values.
197 std::advance(iterator, lengths::RECORD_NAME);
198 auto kwMap = readKeywords(iterator);
199 // Add entry for this record (and contained keyword:value pairs)
200 // to the parsed vpd output.
201 out.emplace(std::move(name), std::move(kwMap));
202 }
203}
204
Deepak Kodihalli4a475bd2016-11-24 07:08:20 -0600205std::string Impl::readKwData(const internal::KeywordInfo& keyword,
206 std::size_t dataLength,
207 Binary::const_iterator iterator)
208{
209 switch (std::get<keyword::Encoding>(keyword))
210 {
211 case keyword::Encoding::ASCII:
212 {
213 auto stop = std::next(iterator, dataLength);
214 return std::string(iterator, stop);
215 }
216
217 case keyword::Encoding::RAW:
218 {
219 auto stop = std::next(iterator, dataLength);
220 std::string data(iterator, stop);
221 std::string result {};
222 std::for_each(data.cbegin(), data.cend(),
223 [&result](size_t c)
224 {
225 result += toHex(c >> 4);
226 result += toHex(c & 0x0F);
227 });
228 return result;
229 }
230
231 case keyword::Encoding::B1:
232 {
233 //B1 is MAC address, represent as AA:BB:CC:DD:EE:FF
234 auto stop = std::next(iterator, MAC_ADDRESS_LEN_BYTES);
235 std::string data(iterator, stop);
236 std::string result {};
237 auto strItr = data.cbegin();
238 size_t firstDigit = *strItr;
239 result += toHex(firstDigit >> 4);
240 result += toHex(firstDigit & 0x0F);
241 std::advance(strItr, 1);
242 std::for_each(strItr, data.cend(),
243 [&result](size_t c)
244 {
245 result += ":";
246 result += toHex(c >> 4);
247 result += toHex(c & 0x0F);
248 });
249 return result;
250 }
251
252 default:
253 break;
254 }
255
256 return {};
257}
258
Deepak Kodihalli810c9de2016-11-22 11:42:51 -0600259} // namespace parser
260} // namespace vpd
261} // namespace openpower