blob: 10dccdd18e149817d8472242f58aed3d38c5a52e [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301/* SPDX-License-Identifier: Apache-2.0 */
2/* Copyright (C) 2018 IBM Corp. */
Deepak Kodihalli393821d2017-04-28 04:44:38 -05003#pragma once
4
5#include <vector>
6#include <memory>
7#include <numeric>
8#include <experimental/filesystem>
Andrew Jeffery7f9c3432018-03-01 12:07:13 +10309#include "common.h"
Andrew Jeffery742a1f62018-03-02 09:26:03 +103010#include "mbox.h"
Deepak Kodihalli393821d2017-04-28 04:44:38 -050011#include "pnor_partition_defs.h"
12
13namespace openpower
14{
15namespace virtual_pnor
16{
17
18namespace fs = std::experimental::filesystem;
19
20using PartitionTable = std::vector<uint8_t>;
21using checksum_t = uint32_t;
22
23/** @brief Convert the input partition table to big endian.
24 *
25 * @param[in] src - reference to the pnor partition table
26 *
27 * @returns converted partition table
28 */
29PartitionTable endianFixup(const PartitionTable& src);
30
Andrew Jefferyd394a782018-02-21 16:16:14 +103031/** @brief Parse a ToC line (entry) into the corresponding FFS partition
32 * object.
33 *
34 * @param[in] line - The ToC line to parse
35 * @param[in] blockSize - The flash block size in bytes
36 * @param[out] part - The partition object to populate with the information
37 * parsed from the provided ToC line
38 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103039 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103040 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103041void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103042 pnor_partition& part);
43
Deepak Kodihalli393821d2017-04-28 04:44:38 -050044namespace details
45{
46
47/** @brief Compute XOR-based checksum, by XORing consecutive words
48 * in the input data. Input must be aligned to word boundary.
49 *
50 * @param[in] data - input data on which checksum is computed
51 *
52 * @returns computed checksum
53 */
Andrew Jefferyf34db312018-03-09 15:27:03 +103054template <class T> checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050055{
56 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
57 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
58
59 auto begin = reinterpret_cast<const checksum_t*>(&data);
60 auto end = begin + (sizeof(decltype(data)) / sizeof(checksum_t));
61
62 return std::accumulate(begin, end, 0, std::bit_xor<checksum_t>());
63}
64
65} // namespace details
66
67namespace partition
68{
69
70/** @class Table
71 * @brief Generates virtual PNOR partition table.
72 *
73 * Generates virtual PNOR partition table upon construction. Reads
74 * the PNOR information generated by this tool :
75 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-squashfs,
76 * which generates a minimalistic table-of-contents (toc) file and
77 * individual files to represent various partitions that are of interest -
78 * these help form the "virtual" PNOR, which is typically a subset of the full
79 * PNOR image.
80 * These files are stored in a well-known location on the PNOR.
81 * Based on this information, this class prepares the partition table whose
82 * structure is as outlined in pnor_partition.h.
83 *
84 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
85 * this size.
86 */
87class Table
88{
Andrew Jefferyf34db312018-03-09 15:27:03 +103089 public:
90 /** @brief Constructor accepting the path of the directory
91 * that houses the PNOR partition files.
92 *
Andrew Jeffery742a1f62018-03-02 09:26:03 +103093 * @param[in] ctx - Acquire sizes and paths relevant to the table
Andrew Jefferyf96bd162018-02-26 13:05:00 +103094 *
95 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +103096 */
Andrew Jeffery742a1f62018-03-02 09:26:03 +103097 Table(const struct mbox_context* ctx);
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 Jeffery7f9c3432018-03-01 12:07:13 +1030105 /** @brief Return the exact size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030106 *
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030107 * @returns size_t - size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030108 */
109 size_t size() const
110 {
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030111 return szBytes;
112 }
113
114 /** @brief Return aligned size of partition table in bytes
115 *
116 * The value returned will be greater-than or equal to size(), and
117 * aligned to blockSize.
118 *
119 * @returns size_t - capacity of partition table in bytes
120 */
121 size_t capacity() const
122 {
123 return align_up(szBytes, blockSize);
124 }
125
126 /** @brief Return the size of partition table in blocks
127 *
128 * @returns size_t - size of partition table in blocks
129 */
130 size_t blocks() const
131 {
132 return capacity() / blockSize;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030133 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500134
Andrew Jefferyf34db312018-03-09 15:27:03 +1030135 /** @brief Return a partition table having byte-ordering
136 * that the host expects.
137 *
138 * The host needs the partion table in big-endian.
139 *
140 * @returns const reference to host partition table.
141 */
142 const pnor_partition_table& getHostTable() const
143 {
144 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
145 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500146
Andrew Jefferyf34db312018-03-09 15:27:03 +1030147 /** @brief Return a little-endian partition table
148 *
149 * @returns const reference to native partition table
150 */
151 const pnor_partition_table& getNativeTable() const
152 {
153 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
154 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500155
Andrew Jefferyf34db312018-03-09 15:27:03 +1030156 /** @brief Return partition corresponding to PNOR offset, the offset
157 * is within returned partition.
158 *
159 * @param[in] offset - PNOR offset in bytes
160 *
161 * @returns const reference to pnor_partition, if found, else an
162 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030163 *
164 * Throws: UnmappedOffset
Andrew Jefferyf34db312018-03-09 15:27:03 +1030165 */
166 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500167
Andrew Jefferyf34db312018-03-09 15:27:03 +1030168 /** @brief Return partition corresponding to input partition name.
169 *
170 * @param[in] name - PNOR partition name
171 *
172 * @returns const reference to pnor_partition, if found, else an
173 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030174 *
175 * Throws: UnknownPartition
Andrew Jefferyf34db312018-03-09 15:27:03 +1030176 */
177 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500178
Andrew Jefferyf34db312018-03-09 15:27:03 +1030179 private:
180 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030181 *
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030182 * @param[in] ctx - An mbox context providing partition locations
183 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030184 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030185 */
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030186 void preparePartitions(const struct mbox_context* ctx);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500187
Andrew Jefferyf34db312018-03-09 15:27:03 +1030188 /** @brief Prepares the PNOR header.
189 */
190 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500191
Andrew Jefferyf34db312018-03-09 15:27:03 +1030192 /** @brief Allocate memory to hold the partion table. Determine the
193 * amount needed based on the partition files in the toc file.
194 *
195 * @param[in] tocFile - Table of contents file path.
196 */
197 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500198
Andrew Jefferyf34db312018-03-09 15:27:03 +1030199 /** @brief Return a little-endian partition table
200 *
201 * @returns reference to native partition table
202 */
203 pnor_partition_table& getNativeTable()
204 {
205 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
206 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500207
Andrew Jefferyf34db312018-03-09 15:27:03 +1030208 /** @brief Size of the PNOR partition table -
209 * sizeof(pnor_partition_table) +
210 * (no. of partitions * sizeof(pnor_partition)),
Andrew Jefferyf34db312018-03-09 15:27:03 +1030211 */
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030212 size_t szBytes;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500213
Andrew Jefferyf34db312018-03-09 15:27:03 +1030214 /** @brief Partition table */
215 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500216
Andrew Jefferyf34db312018-03-09 15:27:03 +1030217 /** @brief Partition table with host byte ordering */
218 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500219
Andrew Jefferyf34db312018-03-09 15:27:03 +1030220 /** @brief Directory housing generated PNOR partition files */
221 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500222
Andrew Jefferyf34db312018-03-09 15:27:03 +1030223 /** @brief Number of partitions */
224 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500225
Andrew Jefferyf34db312018-03-09 15:27:03 +1030226 /** @brief PNOR block size, in bytes */
227 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500228
Andrew Jefferyf34db312018-03-09 15:27:03 +1030229 /** @brief PNOR size, in bytes */
230 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500231};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500232} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030233
234/** @brief An exception type storing a reason string.
235 *
236 * This looks a lot like how std::runtime_error might be implemented however
237 * we want to avoid extending it, as exceptions extending ReasonedError have
238 * an expectation of being handled (can be predicted and are inside the scope
239 * of the program).
240 *
241 * From std::runtime_error documentation[1]:
242 *
243 * > Defines a type of object to be thrown as exception. It reports errors
244 * > that are due to events beyond the scope of the program and can not be
245 * > easily predicted.
246 *
247 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
248 *
249 * We need to keep the inheritance hierarchy separate: This avoids the
250 * introduction of code that overzealously catches std::runtime_error to
251 * handle exceptions that would otherwise derive ReasonedError, and in the
252 * process swallows genuine runtime failures.
253 */
254class ReasonedError : public std::exception
255{
256 public:
257 ReasonedError(const std::string&& what) : _what(what)
258 {
259 }
260 const char* what() const noexcept
261 {
262 return _what.c_str();
263 };
264
265 private:
266 const std::string _what;
267};
268
269/** @brief Base exception type for errors related to ToC entry parsing.
270 *
271 * Callers of parseTocEntry() may not be concerned with the specifics and
272 * rather just want to extract and log what().
273 */
274class TocEntryError : public ReasonedError
275{
276 public:
277 TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
278 {
279 }
280};
281
282/** @brief The exception thrown on finding a syntax error in the ToC entry
283 *
284 * If the syntax is wrong, or expected values are missing, the ToC entry is
285 * malformed
286 */
287class MalformedTocEntry : public TocEntryError
288{
289 public:
290 MalformedTocEntry(const std::string&& reason) :
291 TocEntryError(std::move(reason))
292 {
293 }
294};
295
296/** @brief The exception thrown on finding a semantic error in the ToC entry
297 *
298 * If the syntax of the ToC entry is correct but the semantics are broken,
299 * then we have an invalid ToC entry.
300 */
301class InvalidTocEntry : public TocEntryError
302{
303 public:
304 InvalidTocEntry(const std::string&& reason) :
305 TocEntryError(std::move(reason))
306 {
307 }
308};
309
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030310class UnmappedOffset : public std::exception
311{
312 public:
313 UnmappedOffset(size_t base, size_t next) : base(base), next(next)
314 {
315 }
316
317 const size_t base;
318 const size_t next;
319};
320
321class OutOfBoundsOffset : public ReasonedError
322{
323 public:
324 OutOfBoundsOffset(const std::string&& reason) :
325 ReasonedError(std::move(reason))
326 {
327 }
328};
329
330class UnknownPartition : public ReasonedError
331{
332 public:
333 UnknownPartition(const std::string&& reason) :
334 ReasonedError(std::move(reason))
335 {
336 }
337};
338
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500339} // namespace virtual_pnor
340} // namespace openpower
Andrew Jeffery2ceba892018-02-28 17:44:54 +1030341
342struct vpnor_partition_table
343{
344 openpower::virtual_pnor::partition::Table* table;
345};