blob: 834cc6c4547a0da7360cc27752c9381c26273c4f [file] [log] [blame]
Deepak Kodihalli810c9de2016-11-22 11:42:51 -06001#include <exception>
2#include <iostream>
3#include <iterator>
4#include "impl.hpp"
5
6namespace openpower
7{
8namespace vpd
9{
10namespace parser
11{
12
Deepak Kodihallia1143462016-11-24 06:28:45 -060013static const std::unordered_map<std::string, Record> supportedRecords =
14{
15 {"VINI", Record::VINI},
16 {"OPFR", Record::OPFR},
17 {"OSYS", Record::OSYS}
18};
19
Deepak Kodihalli023112f2016-11-22 22:02:14 -060020namespace
21{
22
23using RecordId = uint8_t;
24using RecordOffset = uint16_t;
25using RecordSize = uint16_t;
26using RecordType = uint16_t;
27using RecordLength = uint16_t;
28using KwSize = uint8_t;
29using ECCOffset = uint16_t;
30using ECCLength = uint16_t;
31
32}
33
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060034namespace offsets
35{
36
37enum Offsets
38{
Deepak Kodihalli023112f2016-11-22 22:02:14 -060039 VHDR = 17,
40 VHDR_TOC_ENTRY = 29,
41 VTOC_PTR = 35,
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060042};
43
44}
45
46namespace lengths
47{
48
49enum Lengths
50{
51 RECORD_NAME = 4,
Deepak Kodihalli023112f2016-11-22 22:02:14 -060052 KW_NAME = 2,
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060053 RECORD_MIN = 44,
54};
55
56}
57
58void Impl::checkHeader() const
59{
60 if (vpd.empty() || (lengths::RECORD_MIN > vpd.size()))
61 {
62 throw std::runtime_error("Malformed VPD");
63 }
64 else
65 {
66 auto iterator = vpd.cbegin();
67 std::advance(iterator, offsets::VHDR);
68 auto stop = std::next(iterator, lengths::RECORD_NAME);
69 std::string record(iterator, stop);
70 if ("VHDR" != record)
71 {
72 throw std::runtime_error("VHDR record not found");
73 }
74 }
75}
76
Deepak Kodihalli023112f2016-11-22 22:02:14 -060077internal::OffsetList Impl::readTOC() const
78{
79 internal::OffsetList offsets {};
80
81 // The offset to VTOC could be 1 or 2 bytes long
82 RecordOffset vtocOffset = vpd.at(offsets::VTOC_PTR);
83 RecordOffset highByte = vpd.at(offsets::VTOC_PTR + 1);
84 vtocOffset |= (highByte << 8);
85
86 // Got the offset to VTOC, skip past record header and keyword header
87 // to get to the record name.
88 auto iterator = vpd.cbegin();
89 std::advance(iterator,
90 vtocOffset +
91 sizeof(RecordId) +
92 sizeof(RecordSize) +
93 // Skip past the RT keyword, which contains
94 // the record name.
95 lengths::KW_NAME +
96 sizeof(KwSize));
97
98 auto stop = std::next(iterator, lengths::RECORD_NAME);
99 std::string record(iterator, stop);
100 if ("VTOC" != record)
101 {
102 throw std::runtime_error("VTOC record not found");
103 }
104
105 // VTOC record name is good, now read through the TOC, stored in the PT
106 // PT keyword; vpdBuffer is now pointing at the first character of the
107 // name 'VTOC', jump to PT data.
108 // Skip past record name and KW name, 'PT'
109 std::advance(iterator, lengths::RECORD_NAME + lengths::KW_NAME);
110 // Note size of PT
111 std::size_t ptLen = *iterator;
112 // Skip past PT size
113 std::advance(iterator, sizeof(KwSize));
114
115 // vpdBuffer is now pointing to PT data
116 return readPT(iterator, ptLen);
117}
118
119internal::OffsetList Impl::readPT(Binary::const_iterator iterator,
120 std::size_t ptLength) const
121{
122 internal::OffsetList offsets{};
123
124 auto end = iterator;
125 std::advance(end, ptLength);
126
127 // Look at each entry in the PT keyword. In the entry,
128 // we care only about the record offset information.
129 while (iterator < end)
130 {
131 // Skip record name and record type
132 std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType));
133
134 // Get record offset
135 RecordOffset offset = *iterator;
136 RecordOffset highByte = *(iterator + 1);
137 offset |= (highByte << 8);
138 offsets.push_back(offset);
139
140 // Jump record size, record length, ECC offset and ECC length
141 std::advance(iterator,
142 sizeof(RecordSize) +
143 sizeof(RecordLength) +
144 sizeof(ECCOffset) +
145 sizeof(ECCLength));
146 }
147
148 return offsets;
149}
150
Deepak Kodihallia1143462016-11-24 06:28:45 -0600151void Impl::processRecord(std::size_t recordOffset)
152{
153 // Jump to record name
154 auto nameOffset = recordOffset +
155 sizeof(RecordId) +
156 sizeof(RecordSize) +
157 // Skip past the RT keyword, which contains
158 // the record name.
159 lengths::KW_NAME +
160 sizeof(KwSize);
161 // Get record name
162 auto iterator = vpd.cbegin();
163 std::advance(iterator, nameOffset);
164
165 std::string name(iterator, iterator + lengths::RECORD_NAME);
166 if (supportedRecords.end() != supportedRecords.find(name))
167 {
168 // If it's a record we're interested in, proceed to find
169 // contained keywords and their values.
170 std::advance(iterator, lengths::RECORD_NAME);
171 auto kwMap = readKeywords(iterator);
172 // Add entry for this record (and contained keyword:value pairs)
173 // to the parsed vpd output.
174 out.emplace(std::move(name), std::move(kwMap));
175 }
176}
177
Deepak Kodihalli810c9de2016-11-22 11:42:51 -0600178} // namespace parser
179} // namespace vpd
180} // namespace openpower