blob: 0a867ad20415f3a4d0c3fc6c6fb7428510f821e6 [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
William A. Kennington IIId5f1d402018-10-11 13:55:04 -07005#include <experimental/filesystem>
Deepak Kodihalli393821d2017-04-28 04:44:38 -05006#include <memory>
7#include <numeric>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -07008#include <vector>
9
Evan Lojewskif1e547c2019-03-14 14:34:33 +103010extern "C" {
11#include "backend.h"
Andrew Jeffery7f9c3432018-03-01 12:07:13 +103012#include "common.h"
Andrew Jefferyf4bc3352019-03-18 12:09:48 +103013#include "vpnor/backend.h"
Andrew Jefferydec59b42019-03-18 13:09:59 +103014#include "vpnor/ffs.h"
Evan Lojewskif1e547c2019-03-14 14:34:33 +103015}
Deepak Kodihalli393821d2017-04-28 04:44:38 -050016
Andrew Jeffery26558db2018-08-10 00:22:38 +093017struct mbox_context;
18
Deepak Kodihalli393821d2017-04-28 04:44:38 -050019namespace openpower
20{
21namespace virtual_pnor
22{
23
24namespace fs = std::experimental::filesystem;
25
26using PartitionTable = std::vector<uint8_t>;
27using checksum_t = uint32_t;
28
29/** @brief Convert the input partition table to big endian.
30 *
31 * @param[in] src - reference to the pnor partition table
32 *
33 * @returns converted partition table
34 */
35PartitionTable endianFixup(const PartitionTable& src);
36
Andrew Jefferyd394a782018-02-21 16:16:14 +103037/** @brief Parse a ToC line (entry) into the corresponding FFS partition
38 * object.
39 *
40 * @param[in] line - The ToC line to parse
41 * @param[in] blockSize - The flash block size in bytes
42 * @param[out] part - The partition object to populate with the information
43 * parsed from the provided ToC line
44 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103045 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103046 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103047void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103048 pnor_partition& part);
49
Deepak Kodihalli393821d2017-04-28 04:44:38 -050050namespace details
51{
52
53/** @brief Compute XOR-based checksum, by XORing consecutive words
54 * in the input data. Input must be aligned to word boundary.
55 *
56 * @param[in] data - input data on which checksum is computed
57 *
58 * @returns computed checksum
59 */
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070060template <class T>
61checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050062{
63 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
64 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
65
66 auto begin = reinterpret_cast<const checksum_t*>(&data);
67 auto end = begin + (sizeof(decltype(data)) / sizeof(checksum_t));
68
69 return std::accumulate(begin, end, 0, std::bit_xor<checksum_t>());
70}
71
72} // namespace details
73
74namespace partition
75{
76
77/** @class Table
78 * @brief Generates virtual PNOR partition table.
79 *
80 * Generates virtual PNOR partition table upon construction. Reads
81 * the PNOR information generated by this tool :
Lei YU81d27b02019-03-08 13:56:53 +080082 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-tar,
Deepak Kodihalli393821d2017-04-28 04:44:38 -050083 * which generates a minimalistic table-of-contents (toc) file and
84 * individual files to represent various partitions that are of interest -
85 * these help form the "virtual" PNOR, which is typically a subset of the full
86 * PNOR image.
87 * These files are stored in a well-known location on the PNOR.
88 * Based on this information, this class prepares the partition table whose
Andrew Jefferyfb01e142019-03-18 13:17:08 +103089 * structure is as outlined in partition.hpp.
Deepak Kodihalli393821d2017-04-28 04:44:38 -050090 *
91 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
92 * this size.
93 */
94class Table
95{
Andrew Jefferyf34db312018-03-09 15:27:03 +103096 public:
97 /** @brief Constructor accepting the path of the directory
98 * that houses the PNOR partition files.
99 *
Andrew Jeffery035ad762019-03-18 13:02:01 +1030100 * @param[in] be - Acquire sizes and paths relevant to the table
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030101 *
102 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030103 */
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030104 Table(const struct backend* be);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500105
Andrew Jefferyf34db312018-03-09 15:27:03 +1030106 Table(const Table&) = delete;
107 Table& operator=(const Table&) = delete;
108 Table(Table&&) = delete;
109 Table& operator=(Table&&) = delete;
110 ~Table() = default;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500111
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030112 /** @brief Return the exact size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030113 *
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030114 * @returns size_t - size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030115 */
116 size_t size() const
117 {
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030118 return szBytes;
119 }
120
121 /** @brief Return aligned size of partition table in bytes
122 *
123 * The value returned will be greater-than or equal to size(), and
124 * aligned to blockSize.
125 *
126 * @returns size_t - capacity of partition table in bytes
127 */
128 size_t capacity() const
129 {
130 return align_up(szBytes, blockSize);
131 }
132
133 /** @brief Return the size of partition table in blocks
134 *
135 * @returns size_t - size of partition table in blocks
136 */
137 size_t blocks() const
138 {
139 return capacity() / blockSize;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030140 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500141
Andrew Jefferyf34db312018-03-09 15:27:03 +1030142 /** @brief Return a partition table having byte-ordering
143 * that the host expects.
144 *
145 * The host needs the partion table in big-endian.
146 *
147 * @returns const reference to host partition table.
148 */
149 const pnor_partition_table& getHostTable() const
150 {
151 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
152 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500153
Andrew Jefferyf34db312018-03-09 15:27:03 +1030154 /** @brief Return a little-endian partition table
155 *
156 * @returns const reference to native partition table
157 */
158 const pnor_partition_table& getNativeTable() const
159 {
160 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
161 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500162
Andrew Jefferyf34db312018-03-09 15:27:03 +1030163 /** @brief Return partition corresponding to PNOR offset, the offset
164 * is within returned partition.
165 *
166 * @param[in] offset - PNOR offset in bytes
167 *
168 * @returns const reference to pnor_partition, if found, else an
169 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030170 *
171 * Throws: UnmappedOffset
Andrew Jefferyf34db312018-03-09 15:27:03 +1030172 */
173 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500174
Andrew Jefferyf34db312018-03-09 15:27:03 +1030175 /** @brief Return partition corresponding to input partition name.
176 *
177 * @param[in] name - PNOR partition name
178 *
179 * @returns const reference to pnor_partition, if found, else an
180 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030181 *
182 * Throws: UnknownPartition
Andrew Jefferyf34db312018-03-09 15:27:03 +1030183 */
184 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500185
Andrew Jefferyf34db312018-03-09 15:27:03 +1030186 private:
187 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030188 *
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030189 * @param[in] ctx - An mbox context providing partition locations
190 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030191 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030192 */
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030193 void preparePartitions(const struct vpnor_data* ctx);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500194
Andrew Jefferyf34db312018-03-09 15:27:03 +1030195 /** @brief Prepares the PNOR header.
196 */
197 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500198
Andrew Jefferyf34db312018-03-09 15:27:03 +1030199 /** @brief Allocate memory to hold the partion table. Determine the
200 * amount needed based on the partition files in the toc file.
201 *
202 * @param[in] tocFile - Table of contents file path.
203 */
204 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500205
Andrew Jefferyf34db312018-03-09 15:27:03 +1030206 /** @brief Return a little-endian partition table
207 *
208 * @returns reference to native partition table
209 */
210 pnor_partition_table& getNativeTable()
211 {
212 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
213 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500214
Andrew Jefferyf34db312018-03-09 15:27:03 +1030215 /** @brief Size of the PNOR partition table -
216 * sizeof(pnor_partition_table) +
217 * (no. of partitions * sizeof(pnor_partition)),
Andrew Jefferyf34db312018-03-09 15:27:03 +1030218 */
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030219 size_t szBytes;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500220
Andrew Jefferyf34db312018-03-09 15:27:03 +1030221 /** @brief Partition table */
222 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500223
Andrew Jefferyf34db312018-03-09 15:27:03 +1030224 /** @brief Partition table with host byte ordering */
225 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500226
Andrew Jefferyf34db312018-03-09 15:27:03 +1030227 /** @brief Directory housing generated PNOR partition files */
228 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500229
Andrew Jefferyf34db312018-03-09 15:27:03 +1030230 /** @brief Number of partitions */
231 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500232
Andrew Jefferyf34db312018-03-09 15:27:03 +1030233 /** @brief PNOR block size, in bytes */
234 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500235
Andrew Jefferyf34db312018-03-09 15:27:03 +1030236 /** @brief PNOR size, in bytes */
237 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500238};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500239} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030240
241/** @brief An exception type storing a reason string.
242 *
243 * This looks a lot like how std::runtime_error might be implemented however
244 * we want to avoid extending it, as exceptions extending ReasonedError have
245 * an expectation of being handled (can be predicted and are inside the scope
246 * of the program).
247 *
248 * From std::runtime_error documentation[1]:
249 *
250 * > Defines a type of object to be thrown as exception. It reports errors
251 * > that are due to events beyond the scope of the program and can not be
252 * > easily predicted.
253 *
254 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
255 *
256 * We need to keep the inheritance hierarchy separate: This avoids the
257 * introduction of code that overzealously catches std::runtime_error to
258 * handle exceptions that would otherwise derive ReasonedError, and in the
259 * process swallows genuine runtime failures.
260 */
261class ReasonedError : public std::exception
262{
263 public:
264 ReasonedError(const std::string&& what) : _what(what)
265 {
266 }
267 const char* what() const noexcept
268 {
269 return _what.c_str();
270 };
271
272 private:
273 const std::string _what;
274};
275
276/** @brief Base exception type for errors related to ToC entry parsing.
277 *
278 * Callers of parseTocEntry() may not be concerned with the specifics and
279 * rather just want to extract and log what().
280 */
281class TocEntryError : public ReasonedError
282{
283 public:
284 TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
285 {
286 }
287};
288
289/** @brief The exception thrown on finding a syntax error in the ToC entry
290 *
291 * If the syntax is wrong, or expected values are missing, the ToC entry is
292 * malformed
293 */
294class MalformedTocEntry : public TocEntryError
295{
296 public:
297 MalformedTocEntry(const std::string&& reason) :
298 TocEntryError(std::move(reason))
299 {
300 }
301};
302
303/** @brief The exception thrown on finding a semantic error in the ToC entry
304 *
305 * If the syntax of the ToC entry is correct but the semantics are broken,
306 * then we have an invalid ToC entry.
307 */
308class InvalidTocEntry : public TocEntryError
309{
310 public:
311 InvalidTocEntry(const std::string&& reason) :
312 TocEntryError(std::move(reason))
313 {
314 }
315};
316
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030317class UnmappedOffset : public std::exception
318{
319 public:
320 UnmappedOffset(size_t base, size_t next) : base(base), next(next)
321 {
322 }
323
324 const size_t base;
325 const size_t next;
326};
327
328class OutOfBoundsOffset : public ReasonedError
329{
330 public:
331 OutOfBoundsOffset(const std::string&& reason) :
332 ReasonedError(std::move(reason))
333 {
334 }
335};
336
337class UnknownPartition : public ReasonedError
338{
339 public:
340 UnknownPartition(const std::string&& reason) :
341 ReasonedError(std::move(reason))
342 {
343 }
344};
345
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500346} // namespace virtual_pnor
347} // namespace openpower
Andrew Jeffery2ceba892018-02-28 17:44:54 +1030348
349struct vpnor_partition_table
350{
351 openpower::virtual_pnor::partition::Table* table;
352};