blob: fae03a9a54a8d1b158db85a2257901aef519710c [file] [log] [blame]
Deepak Kodihalli393821d2017-04-28 04:44:38 -05001#pragma once
2
3#include <vector>
4#include <memory>
5#include <numeric>
6#include <experimental/filesystem>
7#include "pnor_partition_defs.h"
8
9namespace openpower
10{
11namespace virtual_pnor
12{
13
14namespace fs = std::experimental::filesystem;
15
16using PartitionTable = std::vector<uint8_t>;
17using checksum_t = uint32_t;
18
19/** @brief Convert the input partition table to big endian.
20 *
21 * @param[in] src - reference to the pnor partition table
22 *
23 * @returns converted partition table
24 */
25PartitionTable endianFixup(const PartitionTable& src);
26
Andrew Jefferyd394a782018-02-21 16:16:14 +103027/** @brief Parse a ToC line (entry) into the corresponding FFS partition
28 * object.
29 *
30 * @param[in] line - The ToC line to parse
31 * @param[in] blockSize - The flash block size in bytes
32 * @param[out] part - The partition object to populate with the information
33 * parsed from the provided ToC line
34 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103035 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103036 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103037void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103038 pnor_partition& part);
39
Deepak Kodihalli393821d2017-04-28 04:44:38 -050040namespace details
41{
42
43/** @brief Compute XOR-based checksum, by XORing consecutive words
44 * in the input data. Input must be aligned to word boundary.
45 *
46 * @param[in] data - input data on which checksum is computed
47 *
48 * @returns computed checksum
49 */
Andrew Jefferyf34db312018-03-09 15:27:03 +103050template <class T> checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050051{
52 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
53 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
54
55 auto begin = reinterpret_cast<const checksum_t*>(&data);
56 auto end = begin + (sizeof(decltype(data)) / sizeof(checksum_t));
57
58 return std::accumulate(begin, end, 0, std::bit_xor<checksum_t>());
59}
60
61} // namespace details
62
63namespace partition
64{
65
66/** @class Table
67 * @brief Generates virtual PNOR partition table.
68 *
69 * Generates virtual PNOR partition table upon construction. Reads
70 * the PNOR information generated by this tool :
71 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-squashfs,
72 * which generates a minimalistic table-of-contents (toc) file and
73 * individual files to represent various partitions that are of interest -
74 * these help form the "virtual" PNOR, which is typically a subset of the full
75 * PNOR image.
76 * These files are stored in a well-known location on the PNOR.
77 * Based on this information, this class prepares the partition table whose
78 * structure is as outlined in pnor_partition.h.
79 *
80 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
81 * this size.
82 */
83class Table
84{
Andrew Jefferyf34db312018-03-09 15:27:03 +103085 public:
86 /** @brief Constructor accepting the path of the directory
87 * that houses the PNOR partition files.
88 *
89 * @param[in] directory - path of the directory housing PNOR partitions
90 * @param[in] blockSize - PNOR block size, in bytes. See
91 * open-power/hostboot/blob/master/src/usr/pnor/ffs.h for
92 * the PNOR FFS structure.
93 * @param[in] pnorSize - PNOR size, in bytes
Andrew Jefferyf96bd162018-02-26 13:05:00 +103094 *
95 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +103096 */
97 Table(fs::path&& directory, size_t blockSize, size_t pnorSize);
Deepak Kodihalli393821d2017-04-28 04:44:38 -050098
Andrew Jefferyf34db312018-03-09 15:27:03 +103099 Table(const Table&) = delete;
100 Table& operator=(const Table&) = delete;
101 Table(Table&&) = delete;
102 Table& operator=(Table&&) = delete;
103 ~Table() = default;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500104
Andrew Jefferyf34db312018-03-09 15:27:03 +1030105 /** @brief Return size of partition table
106 *
107 * @returns size_t - size of partition table in blocks
108 */
109 size_t size() const
110 {
111 return szBlocks;
112 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500113
Andrew Jefferyf34db312018-03-09 15:27:03 +1030114 /** @brief Return a partition table having byte-ordering
115 * that the host expects.
116 *
117 * The host needs the partion table in big-endian.
118 *
119 * @returns const reference to host partition table.
120 */
121 const pnor_partition_table& getHostTable() const
122 {
123 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
124 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500125
Andrew Jefferyf34db312018-03-09 15:27:03 +1030126 /** @brief Return a little-endian partition table
127 *
128 * @returns const reference to native partition table
129 */
130 const pnor_partition_table& getNativeTable() const
131 {
132 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
133 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500134
Andrew Jefferyf34db312018-03-09 15:27:03 +1030135 /** @brief Return partition corresponding to PNOR offset, the offset
136 * is within returned partition.
137 *
138 * @param[in] offset - PNOR offset in bytes
139 *
140 * @returns const reference to pnor_partition, if found, else an
141 * exception will be thrown.
142 */
143 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500144
Andrew Jefferyf34db312018-03-09 15:27:03 +1030145 /** @brief Return partition corresponding to input partition name.
146 *
147 * @param[in] name - PNOR partition name
148 *
149 * @returns const reference to pnor_partition, if found, else an
150 * exception will be thrown.
151 */
152 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500153
Andrew Jefferyf34db312018-03-09 15:27:03 +1030154 private:
155 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030156 *
157 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030158 */
159 void preparePartitions();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500160
Andrew Jefferyf34db312018-03-09 15:27:03 +1030161 /** @brief Prepares the PNOR header.
162 */
163 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500164
Andrew Jefferyf34db312018-03-09 15:27:03 +1030165 /** @brief Allocate memory to hold the partion table. Determine the
166 * amount needed based on the partition files in the toc file.
167 *
168 * @param[in] tocFile - Table of contents file path.
169 */
170 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500171
Andrew Jefferyf34db312018-03-09 15:27:03 +1030172 /** @brief Return a little-endian partition table
173 *
174 * @returns reference to native partition table
175 */
176 pnor_partition_table& getNativeTable()
177 {
178 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
179 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500180
Andrew Jefferyf34db312018-03-09 15:27:03 +1030181 /** @brief Size of the PNOR partition table -
182 * sizeof(pnor_partition_table) +
183 * (no. of partitions * sizeof(pnor_partition)),
184 * measured in erase-blocks.
185 */
186 size_t szBlocks;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500187
Andrew Jefferyf34db312018-03-09 15:27:03 +1030188 /** @brief Partition table */
189 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500190
Andrew Jefferyf34db312018-03-09 15:27:03 +1030191 /** @brief Partition table with host byte ordering */
192 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500193
Andrew Jefferyf34db312018-03-09 15:27:03 +1030194 /** @brief Directory housing generated PNOR partition files */
195 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500196
Andrew Jefferyf34db312018-03-09 15:27:03 +1030197 /** @brief Number of partitions */
198 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500199
Andrew Jefferyf34db312018-03-09 15:27:03 +1030200 /** @brief PNOR block size, in bytes */
201 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500202
Andrew Jefferyf34db312018-03-09 15:27:03 +1030203 /** @brief PNOR size, in bytes */
204 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500205};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500206} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030207
208/** @brief An exception type storing a reason string.
209 *
210 * This looks a lot like how std::runtime_error might be implemented however
211 * we want to avoid extending it, as exceptions extending ReasonedError have
212 * an expectation of being handled (can be predicted and are inside the scope
213 * of the program).
214 *
215 * From std::runtime_error documentation[1]:
216 *
217 * > Defines a type of object to be thrown as exception. It reports errors
218 * > that are due to events beyond the scope of the program and can not be
219 * > easily predicted.
220 *
221 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
222 *
223 * We need to keep the inheritance hierarchy separate: This avoids the
224 * introduction of code that overzealously catches std::runtime_error to
225 * handle exceptions that would otherwise derive ReasonedError, and in the
226 * process swallows genuine runtime failures.
227 */
228class ReasonedError : public std::exception
229{
230 public:
231 ReasonedError(const std::string&& what) : _what(what)
232 {
233 }
234 const char* what() const noexcept
235 {
236 return _what.c_str();
237 };
238
239 private:
240 const std::string _what;
241};
242
243/** @brief Base exception type for errors related to ToC entry parsing.
244 *
245 * Callers of parseTocEntry() may not be concerned with the specifics and
246 * rather just want to extract and log what().
247 */
248class TocEntryError : public ReasonedError
249{
250 public:
251 TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
252 {
253 }
254};
255
256/** @brief The exception thrown on finding a syntax error in the ToC entry
257 *
258 * If the syntax is wrong, or expected values are missing, the ToC entry is
259 * malformed
260 */
261class MalformedTocEntry : public TocEntryError
262{
263 public:
264 MalformedTocEntry(const std::string&& reason) :
265 TocEntryError(std::move(reason))
266 {
267 }
268};
269
270/** @brief The exception thrown on finding a semantic error in the ToC entry
271 *
272 * If the syntax of the ToC entry is correct but the semantics are broken,
273 * then we have an invalid ToC entry.
274 */
275class InvalidTocEntry : public TocEntryError
276{
277 public:
278 InvalidTocEntry(const std::string&& reason) :
279 TocEntryError(std::move(reason))
280 {
281 }
282};
283
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500284} // namespace virtual_pnor
285} // namespace openpower