blob: 8ba432aed1a440af76abafeff4fa487b3bf8ae08 [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
Andrew Jeffery7f9c3432018-03-01 12:07:13 +103010#include "common.h"
Deepak Kodihalli393821d2017-04-28 04:44:38 -050011#include "pnor_partition_defs.h"
12
Andrew Jeffery26558db2018-08-10 00:22:38 +093013struct mbox_context;
14
Deepak Kodihalli393821d2017-04-28 04:44:38 -050015namespace openpower
16{
17namespace virtual_pnor
18{
19
20namespace fs = std::experimental::filesystem;
21
22using PartitionTable = std::vector<uint8_t>;
23using checksum_t = uint32_t;
24
25/** @brief Convert the input partition table to big endian.
26 *
27 * @param[in] src - reference to the pnor partition table
28 *
29 * @returns converted partition table
30 */
31PartitionTable endianFixup(const PartitionTable& src);
32
Andrew Jefferyd394a782018-02-21 16:16:14 +103033/** @brief Parse a ToC line (entry) into the corresponding FFS partition
34 * object.
35 *
36 * @param[in] line - The ToC line to parse
37 * @param[in] blockSize - The flash block size in bytes
38 * @param[out] part - The partition object to populate with the information
39 * parsed from the provided ToC line
40 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103041 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103042 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103043void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103044 pnor_partition& part);
45
Deepak Kodihalli393821d2017-04-28 04:44:38 -050046namespace details
47{
48
49/** @brief Compute XOR-based checksum, by XORing consecutive words
50 * in the input data. Input must be aligned to word boundary.
51 *
52 * @param[in] data - input data on which checksum is computed
53 *
54 * @returns computed checksum
55 */
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070056template <class T>
57checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050058{
59 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
60 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
61
62 auto begin = reinterpret_cast<const checksum_t*>(&data);
63 auto end = begin + (sizeof(decltype(data)) / sizeof(checksum_t));
64
65 return std::accumulate(begin, end, 0, std::bit_xor<checksum_t>());
66}
67
68} // namespace details
69
70namespace partition
71{
72
73/** @class Table
74 * @brief Generates virtual PNOR partition table.
75 *
76 * Generates virtual PNOR partition table upon construction. Reads
77 * the PNOR information generated by this tool :
78 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-squashfs,
79 * which generates a minimalistic table-of-contents (toc) file and
80 * individual files to represent various partitions that are of interest -
81 * these help form the "virtual" PNOR, which is typically a subset of the full
82 * PNOR image.
83 * These files are stored in a well-known location on the PNOR.
84 * Based on this information, this class prepares the partition table whose
85 * structure is as outlined in pnor_partition.h.
86 *
87 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
88 * this size.
89 */
90class Table
91{
Andrew Jefferyf34db312018-03-09 15:27:03 +103092 public:
93 /** @brief Constructor accepting the path of the directory
94 * that houses the PNOR partition files.
95 *
Andrew Jeffery742a1f62018-03-02 09:26:03 +103096 * @param[in] ctx - Acquire sizes and paths relevant to the table
Andrew Jefferyf96bd162018-02-26 13:05:00 +103097 *
98 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +103099 */
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030100 Table(const struct mbox_context* ctx);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500101
Andrew Jefferyf34db312018-03-09 15:27:03 +1030102 Table(const Table&) = delete;
103 Table& operator=(const Table&) = delete;
104 Table(Table&&) = delete;
105 Table& operator=(Table&&) = delete;
106 ~Table() = default;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500107
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030108 /** @brief Return the exact size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030109 *
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030110 * @returns size_t - size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030111 */
112 size_t size() const
113 {
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030114 return szBytes;
115 }
116
117 /** @brief Return aligned size of partition table in bytes
118 *
119 * The value returned will be greater-than or equal to size(), and
120 * aligned to blockSize.
121 *
122 * @returns size_t - capacity of partition table in bytes
123 */
124 size_t capacity() const
125 {
126 return align_up(szBytes, blockSize);
127 }
128
129 /** @brief Return the size of partition table in blocks
130 *
131 * @returns size_t - size of partition table in blocks
132 */
133 size_t blocks() const
134 {
135 return capacity() / blockSize;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030136 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500137
Andrew Jefferyf34db312018-03-09 15:27:03 +1030138 /** @brief Return a partition table having byte-ordering
139 * that the host expects.
140 *
141 * The host needs the partion table in big-endian.
142 *
143 * @returns const reference to host partition table.
144 */
145 const pnor_partition_table& getHostTable() const
146 {
147 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
148 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500149
Andrew Jefferyf34db312018-03-09 15:27:03 +1030150 /** @brief Return a little-endian partition table
151 *
152 * @returns const reference to native partition table
153 */
154 const pnor_partition_table& getNativeTable() const
155 {
156 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
157 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500158
Andrew Jefferyf34db312018-03-09 15:27:03 +1030159 /** @brief Return partition corresponding to PNOR offset, the offset
160 * is within returned partition.
161 *
162 * @param[in] offset - PNOR offset in bytes
163 *
164 * @returns const reference to pnor_partition, if found, else an
165 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030166 *
167 * Throws: UnmappedOffset
Andrew Jefferyf34db312018-03-09 15:27:03 +1030168 */
169 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500170
Andrew Jefferyf34db312018-03-09 15:27:03 +1030171 /** @brief Return partition corresponding to input partition name.
172 *
173 * @param[in] name - PNOR partition name
174 *
175 * @returns const reference to pnor_partition, if found, else an
176 * exception will be thrown.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030177 *
178 * Throws: UnknownPartition
Andrew Jefferyf34db312018-03-09 15:27:03 +1030179 */
180 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500181
Andrew Jefferyf34db312018-03-09 15:27:03 +1030182 private:
183 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030184 *
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030185 * @param[in] ctx - An mbox context providing partition locations
186 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030187 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030188 */
Andrew Jeffery742a1f62018-03-02 09:26:03 +1030189 void preparePartitions(const struct mbox_context* ctx);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500190
Andrew Jefferyf34db312018-03-09 15:27:03 +1030191 /** @brief Prepares the PNOR header.
192 */
193 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500194
Andrew Jefferyf34db312018-03-09 15:27:03 +1030195 /** @brief Allocate memory to hold the partion table. Determine the
196 * amount needed based on the partition files in the toc file.
197 *
198 * @param[in] tocFile - Table of contents file path.
199 */
200 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500201
Andrew Jefferyf34db312018-03-09 15:27:03 +1030202 /** @brief Return a little-endian partition table
203 *
204 * @returns reference to native partition table
205 */
206 pnor_partition_table& getNativeTable()
207 {
208 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
209 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500210
Andrew Jefferyf34db312018-03-09 15:27:03 +1030211 /** @brief Size of the PNOR partition table -
212 * sizeof(pnor_partition_table) +
213 * (no. of partitions * sizeof(pnor_partition)),
Andrew Jefferyf34db312018-03-09 15:27:03 +1030214 */
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030215 size_t szBytes;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500216
Andrew Jefferyf34db312018-03-09 15:27:03 +1030217 /** @brief Partition table */
218 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500219
Andrew Jefferyf34db312018-03-09 15:27:03 +1030220 /** @brief Partition table with host byte ordering */
221 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500222
Andrew Jefferyf34db312018-03-09 15:27:03 +1030223 /** @brief Directory housing generated PNOR partition files */
224 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500225
Andrew Jefferyf34db312018-03-09 15:27:03 +1030226 /** @brief Number of partitions */
227 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500228
Andrew Jefferyf34db312018-03-09 15:27:03 +1030229 /** @brief PNOR block size, in bytes */
230 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500231
Andrew Jefferyf34db312018-03-09 15:27:03 +1030232 /** @brief PNOR size, in bytes */
233 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500234};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500235} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030236
237/** @brief An exception type storing a reason string.
238 *
239 * This looks a lot like how std::runtime_error might be implemented however
240 * we want to avoid extending it, as exceptions extending ReasonedError have
241 * an expectation of being handled (can be predicted and are inside the scope
242 * of the program).
243 *
244 * From std::runtime_error documentation[1]:
245 *
246 * > Defines a type of object to be thrown as exception. It reports errors
247 * > that are due to events beyond the scope of the program and can not be
248 * > easily predicted.
249 *
250 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
251 *
252 * We need to keep the inheritance hierarchy separate: This avoids the
253 * introduction of code that overzealously catches std::runtime_error to
254 * handle exceptions that would otherwise derive ReasonedError, and in the
255 * process swallows genuine runtime failures.
256 */
257class ReasonedError : public std::exception
258{
259 public:
260 ReasonedError(const std::string&& what) : _what(what)
261 {
262 }
263 const char* what() const noexcept
264 {
265 return _what.c_str();
266 };
267
268 private:
269 const std::string _what;
270};
271
272/** @brief Base exception type for errors related to ToC entry parsing.
273 *
274 * Callers of parseTocEntry() may not be concerned with the specifics and
275 * rather just want to extract and log what().
276 */
277class TocEntryError : public ReasonedError
278{
279 public:
280 TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
281 {
282 }
283};
284
285/** @brief The exception thrown on finding a syntax error in the ToC entry
286 *
287 * If the syntax is wrong, or expected values are missing, the ToC entry is
288 * malformed
289 */
290class MalformedTocEntry : public TocEntryError
291{
292 public:
293 MalformedTocEntry(const std::string&& reason) :
294 TocEntryError(std::move(reason))
295 {
296 }
297};
298
299/** @brief The exception thrown on finding a semantic error in the ToC entry
300 *
301 * If the syntax of the ToC entry is correct but the semantics are broken,
302 * then we have an invalid ToC entry.
303 */
304class InvalidTocEntry : public TocEntryError
305{
306 public:
307 InvalidTocEntry(const std::string&& reason) :
308 TocEntryError(std::move(reason))
309 {
310 }
311};
312
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030313class UnmappedOffset : public std::exception
314{
315 public:
316 UnmappedOffset(size_t base, size_t next) : base(base), next(next)
317 {
318 }
319
320 const size_t base;
321 const size_t next;
322};
323
324class OutOfBoundsOffset : public ReasonedError
325{
326 public:
327 OutOfBoundsOffset(const std::string&& reason) :
328 ReasonedError(std::move(reason))
329 {
330 }
331};
332
333class UnknownPartition : public ReasonedError
334{
335 public:
336 UnknownPartition(const std::string&& reason) :
337 ReasonedError(std::move(reason))
338 {
339 }
340};
341
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500342} // namespace virtual_pnor
343} // namespace openpower
Andrew Jeffery2ceba892018-02-28 17:44:54 +1030344
345struct vpnor_partition_table
346{
347 openpower::virtual_pnor::partition::Table* table;
348};