blob: e42e8d82aba62a2b0edee55dcd561d3675ca52b3 [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
Evan Lojewskif1e547c2019-03-14 14:34:33 +103011extern "C" {
12#include "backend.h"
Andrew Jeffery7f9c3432018-03-01 12:07:13 +103013#include "common.h"
Andrew Jefferyf4bc3352019-03-18 12:09:48 +103014#include "vpnor/backend.h"
Andrew Jefferydec59b42019-03-18 13:09:59 +103015#include "vpnor/ffs.h"
Evan Lojewskif1e547c2019-03-14 14:34:33 +103016}
Deepak Kodihalli393821d2017-04-28 04:44:38 -050017
Andrew Jeffery26558db2018-08-10 00:22:38 +093018struct mbox_context;
19
Deepak Kodihalli393821d2017-04-28 04:44:38 -050020namespace openpower
21{
22namespace virtual_pnor
23{
24
25namespace fs = std::experimental::filesystem;
26
27using PartitionTable = std::vector<uint8_t>;
28using checksum_t = uint32_t;
29
30/** @brief Convert the input partition table to big endian.
31 *
32 * @param[in] src - reference to the pnor partition table
33 *
34 * @returns converted partition table
35 */
36PartitionTable endianFixup(const PartitionTable& src);
37
Andrew Jefferyd394a782018-02-21 16:16:14 +103038/** @brief Parse a ToC line (entry) into the corresponding FFS partition
39 * object.
40 *
41 * @param[in] line - The ToC line to parse
42 * @param[in] blockSize - The flash block size in bytes
43 * @param[out] part - The partition object to populate with the information
44 * parsed from the provided ToC line
45 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103046 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103047 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103048void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103049 pnor_partition& part);
50
Deepak Kodihalli393821d2017-04-28 04:44:38 -050051namespace details
52{
53
54/** @brief Compute XOR-based checksum, by XORing consecutive words
Andrew Jeffery032fb302020-01-28 13:10:50 +103055 * in the input data.
Deepak Kodihalli393821d2017-04-28 04:44:38 -050056 *
57 * @param[in] data - input data on which checksum is computed
58 *
59 * @returns computed checksum
60 */
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070061template <class T>
62checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050063{
64 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
65 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
66
Andrew Jeffery032fb302020-01-28 13:10:50 +103067 /* Shut the compiler up about alignment, consider alternatives */
68 const size_t n_elems = sizeof(decltype(data)) / sizeof(checksum_t);
69 checksum_t csdata[n_elems];
70 memcpy(csdata, &data, sizeof(csdata));
71 auto end = csdata + n_elems;
72 return std::accumulate(csdata, end, 0, std::bit_xor<checksum_t>());
Deepak Kodihalli393821d2017-04-28 04:44:38 -050073}
74
75} // namespace details
76
77namespace partition
78{
79
80/** @class Table
81 * @brief Generates virtual PNOR partition table.
82 *
83 * Generates virtual PNOR partition table upon construction. Reads
84 * the PNOR information generated by this tool :
Lei YU81d27b02019-03-08 13:56:53 +080085 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-tar,
Deepak Kodihalli393821d2017-04-28 04:44:38 -050086 * which generates a minimalistic table-of-contents (toc) file and
87 * individual files to represent various partitions that are of interest -
88 * these help form the "virtual" PNOR, which is typically a subset of the full
89 * PNOR image.
90 * These files are stored in a well-known location on the PNOR.
91 * Based on this information, this class prepares the partition table whose
Andrew Jefferyfb01e142019-03-18 13:17:08 +103092 * structure is as outlined in partition.hpp.
Deepak Kodihalli393821d2017-04-28 04:44:38 -050093 *
94 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
95 * this size.
96 */
97class Table
98{
Andrew Jefferyf34db312018-03-09 15:27:03 +103099 public:
100 /** @brief Constructor accepting the path of the directory
101 * that houses the PNOR partition files.
102 *
Andrew Jeffery035ad762019-03-18 13:02:01 +1030103 * @param[in] be - Acquire sizes and paths relevant to the table
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030104 *
105 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030106 */
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030107 Table(const struct backend* be);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500108
Andrew Jefferyf34db312018-03-09 15:27:03 +1030109 Table(const Table&) = delete;
110 Table& operator=(const Table&) = delete;
111 Table(Table&&) = delete;
112 Table& operator=(Table&&) = delete;
113 ~Table() = default;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500114
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030115 /** @brief Return the exact size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030116 *
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030117 * @returns size_t - size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030118 */
119 size_t size() const
120 {
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030121 return szBytes;
122 }
123
124 /** @brief Return aligned size of partition table in bytes
125 *
126 * The value returned will be greater-than or equal to size(), and
127 * aligned to blockSize.
128 *
129 * @returns size_t - capacity of partition table in bytes
130 */
131 size_t capacity() const
132 {
133 return align_up(szBytes, blockSize);
134 }
135
136 /** @brief Return the size of partition table in blocks
137 *
138 * @returns size_t - size of partition table in blocks
139 */
140 size_t blocks() const
141 {
142 return capacity() / blockSize;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030143 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500144
Andrew Jefferyf34db312018-03-09 15:27:03 +1030145 /** @brief Return a partition table having byte-ordering
146 * that the host expects.
147 *
148 * The host needs the partion table in big-endian.
149 *
150 * @returns const reference to host partition table.
151 */
152 const pnor_partition_table& getHostTable() const
153 {
154 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
155 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500156
Andrew Jefferyf34db312018-03-09 15:27:03 +1030157 /** @brief Return a little-endian partition table
158 *
159 * @returns const reference to native partition table
160 */
161 const pnor_partition_table& getNativeTable() const
162 {
163 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
164 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500165
Andrew Jefferyf34db312018-03-09 15:27:03 +1030166 /** @brief Return partition corresponding to PNOR offset, the offset
167 * is within returned partition.
168 *
169 * @param[in] offset - PNOR offset in bytes
170 *
171 * @returns const reference to pnor_partition, if found, else an
172 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030173 *
174 * Throws: UnmappedOffset
Andrew Jefferyf34db312018-03-09 15:27:03 +1030175 */
176 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500177
Andrew Jefferyf34db312018-03-09 15:27:03 +1030178 /** @brief Return partition corresponding to input partition name.
179 *
180 * @param[in] name - PNOR partition name
181 *
182 * @returns const reference to pnor_partition, if found, else an
183 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030184 *
185 * Throws: UnknownPartition
Andrew Jefferyf34db312018-03-09 15:27:03 +1030186 */
187 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500188
Andrew Jefferyf34db312018-03-09 15:27:03 +1030189 private:
190 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030191 *
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030192 * @param[in] ctx - An mbox context providing partition locations
193 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030194 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030195 */
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030196 void preparePartitions(const struct vpnor_data* ctx);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500197
Andrew Jefferyf34db312018-03-09 15:27:03 +1030198 /** @brief Prepares the PNOR header.
199 */
200 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500201
Andrew Jefferyf34db312018-03-09 15:27:03 +1030202 /** @brief Allocate memory to hold the partion table. Determine the
203 * amount needed based on the partition files in the toc file.
204 *
205 * @param[in] tocFile - Table of contents file path.
206 */
207 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500208
Andrew Jefferyf34db312018-03-09 15:27:03 +1030209 /** @brief Return a little-endian partition table
210 *
211 * @returns reference to native partition table
212 */
213 pnor_partition_table& getNativeTable()
214 {
215 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
216 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500217
Andrew Jefferyf34db312018-03-09 15:27:03 +1030218 /** @brief Size of the PNOR partition table -
219 * sizeof(pnor_partition_table) +
220 * (no. of partitions * sizeof(pnor_partition)),
Andrew Jefferyf34db312018-03-09 15:27:03 +1030221 */
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030222 size_t szBytes;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500223
Andrew Jefferyf34db312018-03-09 15:27:03 +1030224 /** @brief Partition table */
225 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500226
Andrew Jefferyf34db312018-03-09 15:27:03 +1030227 /** @brief Partition table with host byte ordering */
228 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500229
Andrew Jefferyf34db312018-03-09 15:27:03 +1030230 /** @brief Directory housing generated PNOR partition files */
231 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500232
Andrew Jefferyf34db312018-03-09 15:27:03 +1030233 /** @brief Number of partitions */
234 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500235
Andrew Jefferyf34db312018-03-09 15:27:03 +1030236 /** @brief PNOR block size, in bytes */
237 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500238
Andrew Jefferyf34db312018-03-09 15:27:03 +1030239 /** @brief PNOR size, in bytes */
240 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500241};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500242} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030243
244/** @brief An exception type storing a reason string.
245 *
246 * This looks a lot like how std::runtime_error might be implemented however
247 * we want to avoid extending it, as exceptions extending ReasonedError have
248 * an expectation of being handled (can be predicted and are inside the scope
249 * of the program).
250 *
251 * From std::runtime_error documentation[1]:
252 *
253 * > Defines a type of object to be thrown as exception. It reports errors
254 * > that are due to events beyond the scope of the program and can not be
255 * > easily predicted.
256 *
257 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
258 *
259 * We need to keep the inheritance hierarchy separate: This avoids the
260 * introduction of code that overzealously catches std::runtime_error to
261 * handle exceptions that would otherwise derive ReasonedError, and in the
262 * process swallows genuine runtime failures.
263 */
264class ReasonedError : public std::exception
265{
266 public:
267 ReasonedError(const std::string&& what) : _what(what)
268 {
269 }
270 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))
288 {
289 }
290};
291
292/** @brief The exception thrown on finding a syntax error in the ToC entry
293 *
294 * If the syntax is wrong, or expected values are missing, the ToC entry is
295 * malformed
296 */
297class MalformedTocEntry : public TocEntryError
298{
299 public:
300 MalformedTocEntry(const std::string&& reason) :
301 TocEntryError(std::move(reason))
302 {
303 }
304};
305
306/** @brief The exception thrown on finding a semantic error in the ToC entry
307 *
308 * If the syntax of the ToC entry is correct but the semantics are broken,
309 * then we have an invalid ToC entry.
310 */
311class InvalidTocEntry : public TocEntryError
312{
313 public:
314 InvalidTocEntry(const std::string&& reason) :
315 TocEntryError(std::move(reason))
316 {
317 }
318};
319
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030320class UnmappedOffset : public std::exception
321{
322 public:
323 UnmappedOffset(size_t base, size_t next) : base(base), next(next)
324 {
325 }
326
327 const size_t base;
328 const size_t next;
329};
330
331class OutOfBoundsOffset : public ReasonedError
332{
333 public:
334 OutOfBoundsOffset(const std::string&& reason) :
335 ReasonedError(std::move(reason))
336 {
337 }
338};
339
340class UnknownPartition : public ReasonedError
341{
342 public:
343 UnknownPartition(const std::string&& reason) :
344 ReasonedError(std::move(reason))
345 {
346 }
347};
348
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500349} // namespace virtual_pnor
350} // namespace openpower
Andrew Jeffery2ceba892018-02-28 17:44:54 +1030351
352struct vpnor_partition_table
353{
354 openpower::virtual_pnor::partition::Table* table;
355};