blob: 091d6f9f8da65754c5ac3985c8410b6c492eaa6e [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 Kodihalli023112f2016-11-22 22:02:14 -060013namespace
14{
15
16using RecordId = uint8_t;
17using RecordOffset = uint16_t;
18using RecordSize = uint16_t;
19using RecordType = uint16_t;
20using RecordLength = uint16_t;
21using KwSize = uint8_t;
22using ECCOffset = uint16_t;
23using ECCLength = uint16_t;
24
25}
26
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060027namespace offsets
28{
29
30enum Offsets
31{
Deepak Kodihalli023112f2016-11-22 22:02:14 -060032 VHDR = 17,
33 VHDR_TOC_ENTRY = 29,
34 VTOC_PTR = 35,
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060035};
36
37}
38
39namespace lengths
40{
41
42enum Lengths
43{
44 RECORD_NAME = 4,
Deepak Kodihalli023112f2016-11-22 22:02:14 -060045 KW_NAME = 2,
Deepak Kodihalli810c9de2016-11-22 11:42:51 -060046 RECORD_MIN = 44,
47};
48
49}
50
51void Impl::checkHeader() const
52{
53 if (vpd.empty() || (lengths::RECORD_MIN > vpd.size()))
54 {
55 throw std::runtime_error("Malformed VPD");
56 }
57 else
58 {
59 auto iterator = vpd.cbegin();
60 std::advance(iterator, offsets::VHDR);
61 auto stop = std::next(iterator, lengths::RECORD_NAME);
62 std::string record(iterator, stop);
63 if ("VHDR" != record)
64 {
65 throw std::runtime_error("VHDR record not found");
66 }
67 }
68}
69
Deepak Kodihalli023112f2016-11-22 22:02:14 -060070internal::OffsetList Impl::readTOC() const
71{
72 internal::OffsetList offsets {};
73
74 // The offset to VTOC could be 1 or 2 bytes long
75 RecordOffset vtocOffset = vpd.at(offsets::VTOC_PTR);
76 RecordOffset highByte = vpd.at(offsets::VTOC_PTR + 1);
77 vtocOffset |= (highByte << 8);
78
79 // Got the offset to VTOC, skip past record header and keyword header
80 // to get to the record name.
81 auto iterator = vpd.cbegin();
82 std::advance(iterator,
83 vtocOffset +
84 sizeof(RecordId) +
85 sizeof(RecordSize) +
86 // Skip past the RT keyword, which contains
87 // the record name.
88 lengths::KW_NAME +
89 sizeof(KwSize));
90
91 auto stop = std::next(iterator, lengths::RECORD_NAME);
92 std::string record(iterator, stop);
93 if ("VTOC" != record)
94 {
95 throw std::runtime_error("VTOC record not found");
96 }
97
98 // VTOC record name is good, now read through the TOC, stored in the PT
99 // PT keyword; vpdBuffer is now pointing at the first character of the
100 // name 'VTOC', jump to PT data.
101 // Skip past record name and KW name, 'PT'
102 std::advance(iterator, lengths::RECORD_NAME + lengths::KW_NAME);
103 // Note size of PT
104 std::size_t ptLen = *iterator;
105 // Skip past PT size
106 std::advance(iterator, sizeof(KwSize));
107
108 // vpdBuffer is now pointing to PT data
109 return readPT(iterator, ptLen);
110}
111
112internal::OffsetList Impl::readPT(Binary::const_iterator iterator,
113 std::size_t ptLength) const
114{
115 internal::OffsetList offsets{};
116
117 auto end = iterator;
118 std::advance(end, ptLength);
119
120 // Look at each entry in the PT keyword. In the entry,
121 // we care only about the record offset information.
122 while (iterator < end)
123 {
124 // Skip record name and record type
125 std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType));
126
127 // Get record offset
128 RecordOffset offset = *iterator;
129 RecordOffset highByte = *(iterator + 1);
130 offset |= (highByte << 8);
131 offsets.push_back(offset);
132
133 // Jump record size, record length, ECC offset and ECC length
134 std::advance(iterator,
135 sizeof(RecordSize) +
136 sizeof(RecordLength) +
137 sizeof(ECCOffset) +
138 sizeof(ECCLength));
139 }
140
141 return offsets;
142}
143
Deepak Kodihalli810c9de2016-11-22 11:42:51 -0600144} // namespace parser
145} // namespace vpd
146} // namespace openpower