blob: d19ff4b4acc9555557190d1b10472f7b71651d59 [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>
Andrew Jeffery7f9c3432018-03-01 12:07:13 +10307#include "common.h"
Deepak Kodihalli393821d2017-04-28 04:44:38 -05008#include "pnor_partition_defs.h"
9
10namespace openpower
11{
12namespace virtual_pnor
13{
14
15namespace fs = std::experimental::filesystem;
16
17using PartitionTable = std::vector<uint8_t>;
18using checksum_t = uint32_t;
19
20/** @brief Convert the input partition table to big endian.
21 *
22 * @param[in] src - reference to the pnor partition table
23 *
24 * @returns converted partition table
25 */
26PartitionTable endianFixup(const PartitionTable& src);
27
Andrew Jefferyd394a782018-02-21 16:16:14 +103028/** @brief Parse a ToC line (entry) into the corresponding FFS partition
29 * object.
30 *
31 * @param[in] line - The ToC line to parse
32 * @param[in] blockSize - The flash block size in bytes
33 * @param[out] part - The partition object to populate with the information
34 * parsed from the provided ToC line
35 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103036 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103037 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103038void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103039 pnor_partition& part);
40
Deepak Kodihalli393821d2017-04-28 04:44:38 -050041namespace details
42{
43
44/** @brief Compute XOR-based checksum, by XORing consecutive words
45 * in the input data. Input must be aligned to word boundary.
46 *
47 * @param[in] data - input data on which checksum is computed
48 *
49 * @returns computed checksum
50 */
Andrew Jefferyf34db312018-03-09 15:27:03 +103051template <class T> checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050052{
53 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
54 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
55
56 auto begin = reinterpret_cast<const checksum_t*>(&data);
57 auto end = begin + (sizeof(decltype(data)) / sizeof(checksum_t));
58
59 return std::accumulate(begin, end, 0, std::bit_xor<checksum_t>());
60}
61
62} // namespace details
63
64namespace partition
65{
66
67/** @class Table
68 * @brief Generates virtual PNOR partition table.
69 *
70 * Generates virtual PNOR partition table upon construction. Reads
71 * the PNOR information generated by this tool :
72 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-squashfs,
73 * which generates a minimalistic table-of-contents (toc) file and
74 * individual files to represent various partitions that are of interest -
75 * these help form the "virtual" PNOR, which is typically a subset of the full
76 * PNOR image.
77 * These files are stored in a well-known location on the PNOR.
78 * Based on this information, this class prepares the partition table whose
79 * structure is as outlined in pnor_partition.h.
80 *
81 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
82 * this size.
83 */
84class Table
85{
Andrew Jefferyf34db312018-03-09 15:27:03 +103086 public:
87 /** @brief Constructor accepting the path of the directory
88 * that houses the PNOR partition files.
89 *
90 * @param[in] directory - path of the directory housing PNOR partitions
91 * @param[in] blockSize - PNOR block size, in bytes. See
92 * open-power/hostboot/blob/master/src/usr/pnor/ffs.h for
93 * the PNOR FFS structure.
94 * @param[in] pnorSize - PNOR size, in bytes
Andrew Jefferyf96bd162018-02-26 13:05:00 +103095 *
96 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +103097 */
98 Table(fs::path&& directory, size_t blockSize, size_t pnorSize);
Deepak Kodihalli393821d2017-04-28 04:44:38 -050099
Andrew Jefferyf34db312018-03-09 15:27:03 +1030100 Table(const Table&) = delete;
101 Table& operator=(const Table&) = delete;
102 Table(Table&&) = delete;
103 Table& operator=(Table&&) = delete;
104 ~Table() = default;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500105
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030106 /** @brief Return the exact size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030107 *
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030108 * @returns size_t - size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030109 */
110 size_t size() const
111 {
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030112 return szBytes;
113 }
114
115 /** @brief Return aligned size of partition table in bytes
116 *
117 * The value returned will be greater-than or equal to size(), and
118 * aligned to blockSize.
119 *
120 * @returns size_t - capacity of partition table in bytes
121 */
122 size_t capacity() const
123 {
124 return align_up(szBytes, blockSize);
125 }
126
127 /** @brief Return the size of partition table in blocks
128 *
129 * @returns size_t - size of partition table in blocks
130 */
131 size_t blocks() const
132 {
133 return capacity() / blockSize;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030134 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500135
Andrew Jefferyf34db312018-03-09 15:27:03 +1030136 /** @brief Return a partition table having byte-ordering
137 * that the host expects.
138 *
139 * The host needs the partion table in big-endian.
140 *
141 * @returns const reference to host partition table.
142 */
143 const pnor_partition_table& getHostTable() const
144 {
145 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
146 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500147
Andrew Jefferyf34db312018-03-09 15:27:03 +1030148 /** @brief Return a little-endian partition table
149 *
150 * @returns const reference to native partition table
151 */
152 const pnor_partition_table& getNativeTable() const
153 {
154 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
155 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500156
Andrew Jefferyf34db312018-03-09 15:27:03 +1030157 /** @brief Return partition corresponding to PNOR offset, the offset
158 * is within returned partition.
159 *
160 * @param[in] offset - PNOR offset in bytes
161 *
162 * @returns const reference to pnor_partition, if found, else an
163 * exception will be thrown.
164 */
165 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500166
Andrew Jefferyf34db312018-03-09 15:27:03 +1030167 /** @brief Return partition corresponding to input partition name.
168 *
169 * @param[in] name - PNOR partition name
170 *
171 * @returns const reference to pnor_partition, if found, else an
172 * exception will be thrown.
173 */
174 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500175
Andrew Jefferyf34db312018-03-09 15:27:03 +1030176 private:
177 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030178 *
179 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030180 */
181 void preparePartitions();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500182
Andrew Jefferyf34db312018-03-09 15:27:03 +1030183 /** @brief Prepares the PNOR header.
184 */
185 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500186
Andrew Jefferyf34db312018-03-09 15:27:03 +1030187 /** @brief Allocate memory to hold the partion table. Determine the
188 * amount needed based on the partition files in the toc file.
189 *
190 * @param[in] tocFile - Table of contents file path.
191 */
192 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500193
Andrew Jefferyf34db312018-03-09 15:27:03 +1030194 /** @brief Return a little-endian partition table
195 *
196 * @returns reference to native partition table
197 */
198 pnor_partition_table& getNativeTable()
199 {
200 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
201 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500202
Andrew Jefferyf34db312018-03-09 15:27:03 +1030203 /** @brief Size of the PNOR partition table -
204 * sizeof(pnor_partition_table) +
205 * (no. of partitions * sizeof(pnor_partition)),
Andrew Jefferyf34db312018-03-09 15:27:03 +1030206 */
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030207 size_t szBytes;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500208
Andrew Jefferyf34db312018-03-09 15:27:03 +1030209 /** @brief Partition table */
210 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500211
Andrew Jefferyf34db312018-03-09 15:27:03 +1030212 /** @brief Partition table with host byte ordering */
213 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500214
Andrew Jefferyf34db312018-03-09 15:27:03 +1030215 /** @brief Directory housing generated PNOR partition files */
216 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500217
Andrew Jefferyf34db312018-03-09 15:27:03 +1030218 /** @brief Number of partitions */
219 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500220
Andrew Jefferyf34db312018-03-09 15:27:03 +1030221 /** @brief PNOR block size, in bytes */
222 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500223
Andrew Jefferyf34db312018-03-09 15:27:03 +1030224 /** @brief PNOR size, in bytes */
225 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500226};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500227} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030228
229/** @brief An exception type storing a reason string.
230 *
231 * This looks a lot like how std::runtime_error might be implemented however
232 * we want to avoid extending it, as exceptions extending ReasonedError have
233 * an expectation of being handled (can be predicted and are inside the scope
234 * of the program).
235 *
236 * From std::runtime_error documentation[1]:
237 *
238 * > Defines a type of object to be thrown as exception. It reports errors
239 * > that are due to events beyond the scope of the program and can not be
240 * > easily predicted.
241 *
242 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
243 *
244 * We need to keep the inheritance hierarchy separate: This avoids the
245 * introduction of code that overzealously catches std::runtime_error to
246 * handle exceptions that would otherwise derive ReasonedError, and in the
247 * process swallows genuine runtime failures.
248 */
249class ReasonedError : public std::exception
250{
251 public:
252 ReasonedError(const std::string&& what) : _what(what)
253 {
254 }
255 const char* what() const noexcept
256 {
257 return _what.c_str();
258 };
259
260 private:
261 const std::string _what;
262};
263
264/** @brief Base exception type for errors related to ToC entry parsing.
265 *
266 * Callers of parseTocEntry() may not be concerned with the specifics and
267 * rather just want to extract and log what().
268 */
269class TocEntryError : public ReasonedError
270{
271 public:
272 TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
273 {
274 }
275};
276
277/** @brief The exception thrown on finding a syntax error in the ToC entry
278 *
279 * If the syntax is wrong, or expected values are missing, the ToC entry is
280 * malformed
281 */
282class MalformedTocEntry : public TocEntryError
283{
284 public:
285 MalformedTocEntry(const std::string&& reason) :
286 TocEntryError(std::move(reason))
287 {
288 }
289};
290
291/** @brief The exception thrown on finding a semantic error in the ToC entry
292 *
293 * If the syntax of the ToC entry is correct but the semantics are broken,
294 * then we have an invalid ToC entry.
295 */
296class InvalidTocEntry : public TocEntryError
297{
298 public:
299 InvalidTocEntry(const std::string&& reason) :
300 TocEntryError(std::move(reason))
301 {
302 }
303};
304
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500305} // namespace virtual_pnor
306} // namespace openpower