blob: d3ccb5516939ac50232112f7e8d40165b029c872 [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
Andrew Jeffery032fb302020-01-28 13:10:50 +10305#include <cstring>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -07006#include <experimental/filesystem>
Deepak Kodihalli393821d2017-04-28 04:44:38 -05007#include <memory>
8#include <numeric>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -07009#include <vector>
10
Andrew Geissler0ad17212021-05-14 14:01:28 -050011extern "C"
12{
Evan Lojewskif1e547c2019-03-14 14:34:33 +103013#include "backend.h"
Andrew Jeffery7f9c3432018-03-01 12:07:13 +103014#include "common.h"
Andrew Jefferyf4bc3352019-03-18 12:09:48 +103015#include "vpnor/backend.h"
Andrew Jefferydec59b42019-03-18 13:09:59 +103016#include "vpnor/ffs.h"
Evan Lojewskif1e547c2019-03-14 14:34:33 +103017}
Deepak Kodihalli393821d2017-04-28 04:44:38 -050018
Andrew Jeffery26558db2018-08-10 00:22:38 +093019struct mbox_context;
20
Deepak Kodihalli393821d2017-04-28 04:44:38 -050021namespace openpower
22{
23namespace virtual_pnor
24{
25
26namespace fs = std::experimental::filesystem;
27
28using PartitionTable = std::vector<uint8_t>;
29using checksum_t = uint32_t;
30
31/** @brief Convert the input partition table to big endian.
32 *
33 * @param[in] src - reference to the pnor partition table
34 *
35 * @returns converted partition table
36 */
37PartitionTable endianFixup(const PartitionTable& src);
38
Andrew Jefferyd394a782018-02-21 16:16:14 +103039/** @brief Parse a ToC line (entry) into the corresponding FFS partition
40 * object.
41 *
42 * @param[in] line - The ToC line to parse
43 * @param[in] blockSize - The flash block size in bytes
44 * @param[out] part - The partition object to populate with the information
45 * parsed from the provided ToC line
46 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103047 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103048 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103049void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103050 pnor_partition& part);
51
Deepak Kodihalli393821d2017-04-28 04:44:38 -050052namespace details
53{
54
55/** @brief Compute XOR-based checksum, by XORing consecutive words
Andrew Jeffery032fb302020-01-28 13:10:50 +103056 * in the input data.
Deepak Kodihalli393821d2017-04-28 04:44:38 -050057 *
58 * @param[in] data - input data on which checksum is computed
59 *
60 * @returns computed checksum
61 */
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070062template <class T>
63checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050064{
65 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
66 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
67
Andrew Jeffery032fb302020-01-28 13:10:50 +103068 /* Shut the compiler up about alignment, consider alternatives */
69 const size_t n_elems = sizeof(decltype(data)) / sizeof(checksum_t);
70 checksum_t csdata[n_elems];
71 memcpy(csdata, &data, sizeof(csdata));
72 auto end = csdata + n_elems;
73 return std::accumulate(csdata, end, 0, std::bit_xor<checksum_t>());
Deepak Kodihalli393821d2017-04-28 04:44:38 -050074}
75
76} // namespace details
77
78namespace partition
79{
80
81/** @class Table
82 * @brief Generates virtual PNOR partition table.
83 *
84 * Generates virtual PNOR partition table upon construction. Reads
85 * the PNOR information generated by this tool :
Lei YU81d27b02019-03-08 13:56:53 +080086 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-tar,
Deepak Kodihalli393821d2017-04-28 04:44:38 -050087 * which generates a minimalistic table-of-contents (toc) file and
88 * individual files to represent various partitions that are of interest -
89 * these help form the "virtual" PNOR, which is typically a subset of the full
90 * PNOR image.
91 * These files are stored in a well-known location on the PNOR.
92 * Based on this information, this class prepares the partition table whose
Andrew Jefferyfb01e142019-03-18 13:17:08 +103093 * structure is as outlined in partition.hpp.
Deepak Kodihalli393821d2017-04-28 04:44:38 -050094 *
95 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
96 * this size.
97 */
98class Table
99{
Andrew Jefferyf34db312018-03-09 15:27:03 +1030100 public:
101 /** @brief Constructor accepting the path of the directory
102 * that houses the PNOR partition files.
103 *
Andrew Jeffery035ad762019-03-18 13:02:01 +1030104 * @param[in] be - Acquire sizes and paths relevant to the table
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030105 *
106 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030107 */
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030108 Table(const struct backend* be);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500109
Andrew Jefferyf34db312018-03-09 15:27:03 +1030110 Table(const Table&) = delete;
111 Table& operator=(const Table&) = delete;
112 Table(Table&&) = delete;
113 Table& operator=(Table&&) = delete;
114 ~Table() = default;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500115
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030116 /** @brief Return the exact size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030117 *
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030118 * @returns size_t - size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030119 */
120 size_t size() const
121 {
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030122 return szBytes;
123 }
124
125 /** @brief Return aligned size of partition table in bytes
126 *
127 * The value returned will be greater-than or equal to size(), and
128 * aligned to blockSize.
129 *
130 * @returns size_t - capacity of partition table in bytes
131 */
132 size_t capacity() const
133 {
134 return align_up(szBytes, blockSize);
135 }
136
137 /** @brief Return the size of partition table in blocks
138 *
139 * @returns size_t - size of partition table in blocks
140 */
141 size_t blocks() const
142 {
143 return capacity() / blockSize;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030144 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500145
Andrew Jefferyf34db312018-03-09 15:27:03 +1030146 /** @brief Return a partition table having byte-ordering
147 * that the host expects.
148 *
149 * The host needs the partion table in big-endian.
150 *
151 * @returns const reference to host partition table.
152 */
153 const pnor_partition_table& getHostTable() const
154 {
155 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
156 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500157
Andrew Jefferyf34db312018-03-09 15:27:03 +1030158 /** @brief Return a little-endian partition table
159 *
160 * @returns const reference to native partition table
161 */
162 const pnor_partition_table& getNativeTable() const
163 {
164 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
165 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500166
Andrew Jefferyf34db312018-03-09 15:27:03 +1030167 /** @brief Return partition corresponding to PNOR offset, the offset
168 * is within returned partition.
169 *
170 * @param[in] offset - PNOR offset in bytes
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: UnmappedOffset
Andrew Jefferyf34db312018-03-09 15:27:03 +1030176 */
177 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500178
Andrew Jefferyf34db312018-03-09 15:27:03 +1030179 /** @brief Return partition corresponding to input partition name.
180 *
181 * @param[in] name - PNOR partition name
182 *
183 * @returns const reference to pnor_partition, if found, else an
184 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030185 *
186 * Throws: UnknownPartition
Andrew Jefferyf34db312018-03-09 15:27:03 +1030187 */
188 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500189
Andrew Jefferyf34db312018-03-09 15:27:03 +1030190 private:
191 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030192 *
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030193 * @param[in] ctx - An mbox context providing partition locations
194 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030195 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030196 */
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030197 void preparePartitions(const struct vpnor_data* ctx);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500198
Andrew Jefferyf34db312018-03-09 15:27:03 +1030199 /** @brief Prepares the PNOR header.
200 */
201 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500202
Andrew Jefferyf34db312018-03-09 15:27:03 +1030203 /** @brief Allocate memory to hold the partion table. Determine the
204 * amount needed based on the partition files in the toc file.
205 *
206 * @param[in] tocFile - Table of contents file path.
207 */
208 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500209
Andrew Jefferyf34db312018-03-09 15:27:03 +1030210 /** @brief Return a little-endian partition table
211 *
212 * @returns reference to native partition table
213 */
214 pnor_partition_table& getNativeTable()
215 {
216 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
217 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500218
Andrew Jefferyf34db312018-03-09 15:27:03 +1030219 /** @brief Size of the PNOR partition table -
220 * sizeof(pnor_partition_table) +
221 * (no. of partitions * sizeof(pnor_partition)),
Andrew Jefferyf34db312018-03-09 15:27:03 +1030222 */
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030223 size_t szBytes;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500224
Andrew Jefferyf34db312018-03-09 15:27:03 +1030225 /** @brief Partition table */
226 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500227
Andrew Jefferyf34db312018-03-09 15:27:03 +1030228 /** @brief Partition table with host byte ordering */
229 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500230
Andrew Jefferyf34db312018-03-09 15:27:03 +1030231 /** @brief Directory housing generated PNOR partition files */
232 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500233
Andrew Jefferyf34db312018-03-09 15:27:03 +1030234 /** @brief Number of partitions */
235 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500236
Andrew Jefferyf34db312018-03-09 15:27:03 +1030237 /** @brief PNOR block size, in bytes */
238 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500239
Andrew Jefferyf34db312018-03-09 15:27:03 +1030240 /** @brief PNOR size, in bytes */
241 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500242};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500243} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030244
245/** @brief An exception type storing a reason string.
246 *
247 * This looks a lot like how std::runtime_error might be implemented however
248 * we want to avoid extending it, as exceptions extending ReasonedError have
249 * an expectation of being handled (can be predicted and are inside the scope
250 * of the program).
251 *
252 * From std::runtime_error documentation[1]:
253 *
254 * > Defines a type of object to be thrown as exception. It reports errors
255 * > that are due to events beyond the scope of the program and can not be
256 * > easily predicted.
257 *
258 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
259 *
260 * We need to keep the inheritance hierarchy separate: This avoids the
261 * introduction of code that overzealously catches std::runtime_error to
262 * handle exceptions that would otherwise derive ReasonedError, and in the
263 * process swallows genuine runtime failures.
264 */
265class ReasonedError : public std::exception
266{
267 public:
268 ReasonedError(const std::string&& what) : _what(what)
Andrew Geissler0ad17212021-05-14 14:01:28 -0500269 {}
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030270 const char* what() const noexcept
271 {
272 return _what.c_str();
273 };
274
275 private:
276 const std::string _what;
277};
278
279/** @brief Base exception type for errors related to ToC entry parsing.
280 *
281 * Callers of parseTocEntry() may not be concerned with the specifics and
282 * rather just want to extract and log what().
283 */
284class TocEntryError : public ReasonedError
285{
286 public:
287 TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
Andrew Geissler0ad17212021-05-14 14:01:28 -0500288 {}
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030289};
290
291/** @brief The exception thrown on finding a syntax error in the ToC entry
292 *
293 * If the syntax is wrong, or expected values are missing, the ToC entry is
294 * malformed
295 */
296class MalformedTocEntry : public TocEntryError
297{
298 public:
299 MalformedTocEntry(const std::string&& reason) :
300 TocEntryError(std::move(reason))
Andrew Geissler0ad17212021-05-14 14:01:28 -0500301 {}
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030302};
303
304/** @brief The exception thrown on finding a semantic error in the ToC entry
305 *
306 * If the syntax of the ToC entry is correct but the semantics are broken,
307 * then we have an invalid ToC entry.
308 */
309class InvalidTocEntry : public TocEntryError
310{
311 public:
312 InvalidTocEntry(const std::string&& reason) :
313 TocEntryError(std::move(reason))
Andrew Geissler0ad17212021-05-14 14:01:28 -0500314 {}
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030315};
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)
Andrew Geissler0ad17212021-05-14 14:01:28 -0500321 {}
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030322
323 const size_t base;
324 const size_t next;
325};
326
327class OutOfBoundsOffset : public ReasonedError
328{
329 public:
330 OutOfBoundsOffset(const std::string&& reason) :
331 ReasonedError(std::move(reason))
Andrew Geissler0ad17212021-05-14 14:01:28 -0500332 {}
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030333};
334
335class UnknownPartition : public ReasonedError
336{
337 public:
338 UnknownPartition(const std::string&& reason) :
339 ReasonedError(std::move(reason))
Andrew Geissler0ad17212021-05-14 14:01:28 -0500340 {}
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030341};
342
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500343} // namespace virtual_pnor
344} // namespace openpower
Andrew Jeffery2ceba892018-02-28 17:44:54 +1030345
346struct vpnor_partition_table
347{
348 openpower::virtual_pnor::partition::Table* table;
349};