1de08ca2dSAndrew Jeffery /* SPDX-License-Identifier: Apache-2.0 */
2de08ca2dSAndrew Jeffery /* Copyright (C) 2018 IBM Corp. */
3de08ca2dSAndrew Jeffery #pragma once
4de08ca2dSAndrew Jeffery
5032fb300SAndrew Jeffery #include <cstring>
6*150be912SPatrick Williams #include <filesystem>
7de08ca2dSAndrew Jeffery #include <memory>
8de08ca2dSAndrew Jeffery #include <numeric>
9de08ca2dSAndrew Jeffery #include <vector>
10de08ca2dSAndrew Jeffery
11fab4020dSEd Tanous extern "C" {
12de08ca2dSAndrew Jeffery #include "backend.h"
13de08ca2dSAndrew Jeffery #include "common.h"
14de08ca2dSAndrew Jeffery #include "vpnor/backend.h"
15de08ca2dSAndrew Jeffery #include "vpnor/ffs.h"
16de08ca2dSAndrew Jeffery }
17de08ca2dSAndrew Jeffery
18de08ca2dSAndrew Jeffery struct mbox_context;
19de08ca2dSAndrew Jeffery
20de08ca2dSAndrew Jeffery namespace openpower
21de08ca2dSAndrew Jeffery {
22de08ca2dSAndrew Jeffery namespace virtual_pnor
23de08ca2dSAndrew Jeffery {
24de08ca2dSAndrew Jeffery
25*150be912SPatrick Williams namespace fs = std::filesystem;
26de08ca2dSAndrew Jeffery
27de08ca2dSAndrew Jeffery using PartitionTable = std::vector<uint8_t>;
28de08ca2dSAndrew Jeffery using checksum_t = uint32_t;
29de08ca2dSAndrew Jeffery
30de08ca2dSAndrew Jeffery /** @brief Convert the input partition table to big endian.
31de08ca2dSAndrew Jeffery *
32de08ca2dSAndrew Jeffery * @param[in] src - reference to the pnor partition table
33de08ca2dSAndrew Jeffery *
34de08ca2dSAndrew Jeffery * @returns converted partition table
35de08ca2dSAndrew Jeffery */
36de08ca2dSAndrew Jeffery PartitionTable endianFixup(const PartitionTable& src);
37de08ca2dSAndrew Jeffery
38de08ca2dSAndrew Jeffery /** @brief Parse a ToC line (entry) into the corresponding FFS partition
39de08ca2dSAndrew Jeffery * object.
40de08ca2dSAndrew Jeffery *
41de08ca2dSAndrew Jeffery * @param[in] line - The ToC line to parse
42de08ca2dSAndrew Jeffery * @param[in] blockSize - The flash block size in bytes
43de08ca2dSAndrew Jeffery * @param[out] part - The partition object to populate with the information
44de08ca2dSAndrew Jeffery * parsed from the provided ToC line
45de08ca2dSAndrew Jeffery *
46de08ca2dSAndrew Jeffery * Throws: MalformedTocEntry, InvalidTocEntry
47de08ca2dSAndrew Jeffery */
48de08ca2dSAndrew Jeffery void parseTocLine(const std::string& line, size_t blockSize,
49de08ca2dSAndrew Jeffery pnor_partition& part);
50de08ca2dSAndrew Jeffery
51de08ca2dSAndrew Jeffery namespace details
52de08ca2dSAndrew Jeffery {
53de08ca2dSAndrew Jeffery
54de08ca2dSAndrew Jeffery /** @brief Compute XOR-based checksum, by XORing consecutive words
55032fb300SAndrew Jeffery * in the input data.
56de08ca2dSAndrew Jeffery *
57de08ca2dSAndrew Jeffery * @param[in] data - input data on which checksum is computed
58de08ca2dSAndrew Jeffery *
59de08ca2dSAndrew Jeffery * @returns computed checksum
60de08ca2dSAndrew Jeffery */
61de08ca2dSAndrew Jeffery template <class T>
checksum(const T & data)62de08ca2dSAndrew Jeffery checksum_t checksum(const T& data)
63de08ca2dSAndrew Jeffery {
64de08ca2dSAndrew Jeffery static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
65de08ca2dSAndrew Jeffery "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
66de08ca2dSAndrew Jeffery
67032fb300SAndrew Jeffery /* Shut the compiler up about alignment, consider alternatives */
68032fb300SAndrew Jeffery const size_t n_elems = sizeof(decltype(data)) / sizeof(checksum_t);
69032fb300SAndrew Jeffery checksum_t csdata[n_elems];
70032fb300SAndrew Jeffery memcpy(csdata, &data, sizeof(csdata));
71032fb300SAndrew Jeffery auto end = csdata + n_elems;
72032fb300SAndrew Jeffery return std::accumulate(csdata, end, 0, std::bit_xor<checksum_t>());
73de08ca2dSAndrew Jeffery }
74de08ca2dSAndrew Jeffery
75de08ca2dSAndrew Jeffery } // namespace details
76de08ca2dSAndrew Jeffery
77de08ca2dSAndrew Jeffery namespace partition
78de08ca2dSAndrew Jeffery {
79de08ca2dSAndrew Jeffery
80de08ca2dSAndrew Jeffery /** @class Table
81de08ca2dSAndrew Jeffery * @brief Generates virtual PNOR partition table.
82de08ca2dSAndrew Jeffery *
83de08ca2dSAndrew Jeffery * Generates virtual PNOR partition table upon construction. Reads
84de08ca2dSAndrew Jeffery * the PNOR information generated by this tool :
8581d27b04SLei YU * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-tar,
86de08ca2dSAndrew Jeffery * which generates a minimalistic table-of-contents (toc) file and
87de08ca2dSAndrew Jeffery * individual files to represent various partitions that are of interest -
88de08ca2dSAndrew Jeffery * these help form the "virtual" PNOR, which is typically a subset of the full
89de08ca2dSAndrew Jeffery * PNOR image.
90de08ca2dSAndrew Jeffery * These files are stored in a well-known location on the PNOR.
91de08ca2dSAndrew Jeffery * Based on this information, this class prepares the partition table whose
92de08ca2dSAndrew Jeffery * structure is as outlined in partition.hpp.
93de08ca2dSAndrew Jeffery *
94de08ca2dSAndrew Jeffery * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
95de08ca2dSAndrew Jeffery * this size.
96de08ca2dSAndrew Jeffery */
97de08ca2dSAndrew Jeffery class Table
98de08ca2dSAndrew Jeffery {
99de08ca2dSAndrew Jeffery public:
100de08ca2dSAndrew Jeffery /** @brief Constructor accepting the path of the directory
101de08ca2dSAndrew Jeffery * that houses the PNOR partition files.
102de08ca2dSAndrew Jeffery *
103de08ca2dSAndrew Jeffery * @param[in] be - Acquire sizes and paths relevant to the table
104de08ca2dSAndrew Jeffery *
105de08ca2dSAndrew Jeffery * Throws MalformedTocEntry, InvalidTocEntry
106de08ca2dSAndrew Jeffery */
107de08ca2dSAndrew Jeffery Table(const struct backend* be);
108de08ca2dSAndrew Jeffery
109de08ca2dSAndrew Jeffery Table(const Table&) = delete;
110de08ca2dSAndrew Jeffery Table& operator=(const Table&) = delete;
111de08ca2dSAndrew Jeffery Table(Table&&) = delete;
112de08ca2dSAndrew Jeffery Table& operator=(Table&&) = delete;
113de08ca2dSAndrew Jeffery ~Table() = default;
114de08ca2dSAndrew Jeffery
115de08ca2dSAndrew Jeffery /** @brief Return the exact size of partition table in bytes
116de08ca2dSAndrew Jeffery *
117de08ca2dSAndrew Jeffery * @returns size_t - size of partition table in bytes
118de08ca2dSAndrew Jeffery */
size() const119de08ca2dSAndrew Jeffery size_t size() const
120de08ca2dSAndrew Jeffery {
121de08ca2dSAndrew Jeffery return szBytes;
122de08ca2dSAndrew Jeffery }
123de08ca2dSAndrew Jeffery
124de08ca2dSAndrew Jeffery /** @brief Return aligned size of partition table in bytes
125de08ca2dSAndrew Jeffery *
126de08ca2dSAndrew Jeffery * The value returned will be greater-than or equal to size(), and
127de08ca2dSAndrew Jeffery * aligned to blockSize.
128de08ca2dSAndrew Jeffery *
129de08ca2dSAndrew Jeffery * @returns size_t - capacity of partition table in bytes
130de08ca2dSAndrew Jeffery */
capacity() const131de08ca2dSAndrew Jeffery size_t capacity() const
132de08ca2dSAndrew Jeffery {
133de08ca2dSAndrew Jeffery return align_up(szBytes, blockSize);
134de08ca2dSAndrew Jeffery }
135de08ca2dSAndrew Jeffery
136de08ca2dSAndrew Jeffery /** @brief Return the size of partition table in blocks
137de08ca2dSAndrew Jeffery *
138de08ca2dSAndrew Jeffery * @returns size_t - size of partition table in blocks
139de08ca2dSAndrew Jeffery */
blocks() const140de08ca2dSAndrew Jeffery size_t blocks() const
141de08ca2dSAndrew Jeffery {
142de08ca2dSAndrew Jeffery return capacity() / blockSize;
143de08ca2dSAndrew Jeffery }
144de08ca2dSAndrew Jeffery
145de08ca2dSAndrew Jeffery /** @brief Return a partition table having byte-ordering
146de08ca2dSAndrew Jeffery * that the host expects.
147de08ca2dSAndrew Jeffery *
148de08ca2dSAndrew Jeffery * The host needs the partion table in big-endian.
149de08ca2dSAndrew Jeffery *
150de08ca2dSAndrew Jeffery * @returns const reference to host partition table.
151de08ca2dSAndrew Jeffery */
getHostTable() const152de08ca2dSAndrew Jeffery const pnor_partition_table& getHostTable() const
153de08ca2dSAndrew Jeffery {
154de08ca2dSAndrew Jeffery return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
155de08ca2dSAndrew Jeffery }
156de08ca2dSAndrew Jeffery
157de08ca2dSAndrew Jeffery /** @brief Return a little-endian partition table
158de08ca2dSAndrew Jeffery *
159de08ca2dSAndrew Jeffery * @returns const reference to native partition table
160de08ca2dSAndrew Jeffery */
getNativeTable() const161de08ca2dSAndrew Jeffery const pnor_partition_table& getNativeTable() const
162de08ca2dSAndrew Jeffery {
163de08ca2dSAndrew Jeffery return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
164de08ca2dSAndrew Jeffery }
165de08ca2dSAndrew Jeffery
166de08ca2dSAndrew Jeffery /** @brief Return partition corresponding to PNOR offset, the offset
167de08ca2dSAndrew Jeffery * is within returned partition.
168de08ca2dSAndrew Jeffery *
169de08ca2dSAndrew Jeffery * @param[in] offset - PNOR offset in bytes
170de08ca2dSAndrew Jeffery *
171de08ca2dSAndrew Jeffery * @returns const reference to pnor_partition, if found, else an
172de08ca2dSAndrew Jeffery * exception will be thrown.
173de08ca2dSAndrew Jeffery *
174de08ca2dSAndrew Jeffery * Throws: UnmappedOffset
175de08ca2dSAndrew Jeffery */
176de08ca2dSAndrew Jeffery const pnor_partition& partition(size_t offset) const;
177de08ca2dSAndrew Jeffery
178de08ca2dSAndrew Jeffery /** @brief Return partition corresponding to input partition name.
179de08ca2dSAndrew Jeffery *
180de08ca2dSAndrew Jeffery * @param[in] name - PNOR partition name
181de08ca2dSAndrew Jeffery *
182de08ca2dSAndrew Jeffery * @returns const reference to pnor_partition, if found, else an
183de08ca2dSAndrew Jeffery * exception will be thrown.
184de08ca2dSAndrew Jeffery *
185de08ca2dSAndrew Jeffery * Throws: UnknownPartition
186de08ca2dSAndrew Jeffery */
187de08ca2dSAndrew Jeffery const pnor_partition& partition(const std::string& name) const;
188de08ca2dSAndrew Jeffery
189de08ca2dSAndrew Jeffery private:
190de08ca2dSAndrew Jeffery /** @brief Prepares a vector of PNOR partition structures.
191de08ca2dSAndrew Jeffery *
192de08ca2dSAndrew Jeffery * @param[in] ctx - An mbox context providing partition locations
193de08ca2dSAndrew Jeffery *
194de08ca2dSAndrew Jeffery * Throws: MalformedTocEntry, InvalidTocEntry
195de08ca2dSAndrew Jeffery */
196de08ca2dSAndrew Jeffery void preparePartitions(const struct vpnor_data* ctx);
197de08ca2dSAndrew Jeffery
198de08ca2dSAndrew Jeffery /** @brief Prepares the PNOR header.
199de08ca2dSAndrew Jeffery */
200de08ca2dSAndrew Jeffery void prepareHeader();
201de08ca2dSAndrew Jeffery
202de08ca2dSAndrew Jeffery /** @brief Allocate memory to hold the partion table. Determine the
203de08ca2dSAndrew Jeffery * amount needed based on the partition files in the toc file.
204de08ca2dSAndrew Jeffery *
205de08ca2dSAndrew Jeffery * @param[in] tocFile - Table of contents file path.
206de08ca2dSAndrew Jeffery */
207de08ca2dSAndrew Jeffery void allocateMemory(const fs::path& tocFile);
208de08ca2dSAndrew Jeffery
209de08ca2dSAndrew Jeffery /** @brief Return a little-endian partition table
210de08ca2dSAndrew Jeffery *
211de08ca2dSAndrew Jeffery * @returns reference to native partition table
212de08ca2dSAndrew Jeffery */
getNativeTable()213de08ca2dSAndrew Jeffery pnor_partition_table& getNativeTable()
214de08ca2dSAndrew Jeffery {
215de08ca2dSAndrew Jeffery return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
216de08ca2dSAndrew Jeffery }
217de08ca2dSAndrew Jeffery
218de08ca2dSAndrew Jeffery /** @brief Size of the PNOR partition table -
219de08ca2dSAndrew Jeffery * sizeof(pnor_partition_table) +
220de08ca2dSAndrew Jeffery * (no. of partitions * sizeof(pnor_partition)),
221de08ca2dSAndrew Jeffery */
222de08ca2dSAndrew Jeffery size_t szBytes;
223de08ca2dSAndrew Jeffery
224de08ca2dSAndrew Jeffery /** @brief Partition table */
225de08ca2dSAndrew Jeffery PartitionTable tbl;
226de08ca2dSAndrew Jeffery
227de08ca2dSAndrew Jeffery /** @brief Partition table with host byte ordering */
228de08ca2dSAndrew Jeffery PartitionTable hostTbl;
229de08ca2dSAndrew Jeffery
230de08ca2dSAndrew Jeffery /** @brief Directory housing generated PNOR partition files */
231de08ca2dSAndrew Jeffery fs::path directory;
232de08ca2dSAndrew Jeffery
233de08ca2dSAndrew Jeffery /** @brief Number of partitions */
234de08ca2dSAndrew Jeffery size_t numParts;
235de08ca2dSAndrew Jeffery
236de08ca2dSAndrew Jeffery /** @brief PNOR block size, in bytes */
237de08ca2dSAndrew Jeffery size_t blockSize;
238de08ca2dSAndrew Jeffery
239de08ca2dSAndrew Jeffery /** @brief PNOR size, in bytes */
240de08ca2dSAndrew Jeffery size_t pnorSize;
241de08ca2dSAndrew Jeffery };
242de08ca2dSAndrew Jeffery } // namespace partition
243de08ca2dSAndrew Jeffery
244de08ca2dSAndrew Jeffery /** @brief An exception type storing a reason string.
245de08ca2dSAndrew Jeffery *
246de08ca2dSAndrew Jeffery * This looks a lot like how std::runtime_error might be implemented however
247de08ca2dSAndrew Jeffery * we want to avoid extending it, as exceptions extending ReasonedError have
248de08ca2dSAndrew Jeffery * an expectation of being handled (can be predicted and are inside the scope
249de08ca2dSAndrew Jeffery * of the program).
250de08ca2dSAndrew Jeffery *
251de08ca2dSAndrew Jeffery * From std::runtime_error documentation[1]:
252de08ca2dSAndrew Jeffery *
253de08ca2dSAndrew Jeffery * > Defines a type of object to be thrown as exception. It reports errors
254de08ca2dSAndrew Jeffery * > that are due to events beyond the scope of the program and can not be
255de08ca2dSAndrew Jeffery * > easily predicted.
256de08ca2dSAndrew Jeffery *
257de08ca2dSAndrew Jeffery * [1] http://en.cppreference.com/w/cpp/error/runtime_error
258de08ca2dSAndrew Jeffery *
259de08ca2dSAndrew Jeffery * We need to keep the inheritance hierarchy separate: This avoids the
260de08ca2dSAndrew Jeffery * introduction of code that overzealously catches std::runtime_error to
261de08ca2dSAndrew Jeffery * handle exceptions that would otherwise derive ReasonedError, and in the
262de08ca2dSAndrew Jeffery * process swallows genuine runtime failures.
263de08ca2dSAndrew Jeffery */
264de08ca2dSAndrew Jeffery class ReasonedError : public std::exception
265de08ca2dSAndrew Jeffery {
266de08ca2dSAndrew Jeffery public:
ReasonedError(const std::string && what)267de08ca2dSAndrew Jeffery ReasonedError(const std::string&& what) : _what(what)
268fab4020dSEd Tanous {
269fab4020dSEd Tanous }
what() const270de08ca2dSAndrew Jeffery const char* what() const noexcept
271de08ca2dSAndrew Jeffery {
272de08ca2dSAndrew Jeffery return _what.c_str();
273de08ca2dSAndrew Jeffery };
274de08ca2dSAndrew Jeffery
275de08ca2dSAndrew Jeffery private:
276de08ca2dSAndrew Jeffery const std::string _what;
277de08ca2dSAndrew Jeffery };
278de08ca2dSAndrew Jeffery
279de08ca2dSAndrew Jeffery /** @brief Base exception type for errors related to ToC entry parsing.
280de08ca2dSAndrew Jeffery *
281de08ca2dSAndrew Jeffery * Callers of parseTocEntry() may not be concerned with the specifics and
282de08ca2dSAndrew Jeffery * rather just want to extract and log what().
283de08ca2dSAndrew Jeffery */
284de08ca2dSAndrew Jeffery class TocEntryError : public ReasonedError
285de08ca2dSAndrew Jeffery {
286de08ca2dSAndrew Jeffery public:
TocEntryError(const std::string && reason)287de08ca2dSAndrew Jeffery TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
288fab4020dSEd Tanous {
289fab4020dSEd Tanous }
290de08ca2dSAndrew Jeffery };
291de08ca2dSAndrew Jeffery
292de08ca2dSAndrew Jeffery /** @brief The exception thrown on finding a syntax error in the ToC entry
293de08ca2dSAndrew Jeffery *
294de08ca2dSAndrew Jeffery * If the syntax is wrong, or expected values are missing, the ToC entry is
295de08ca2dSAndrew Jeffery * malformed
296de08ca2dSAndrew Jeffery */
297de08ca2dSAndrew Jeffery class MalformedTocEntry : public TocEntryError
298de08ca2dSAndrew Jeffery {
299de08ca2dSAndrew Jeffery public:
MalformedTocEntry(const std::string && reason)300de08ca2dSAndrew Jeffery MalformedTocEntry(const std::string&& reason) :
301de08ca2dSAndrew Jeffery TocEntryError(std::move(reason))
302fab4020dSEd Tanous {
303fab4020dSEd Tanous }
304de08ca2dSAndrew Jeffery };
305de08ca2dSAndrew Jeffery
306de08ca2dSAndrew Jeffery /** @brief The exception thrown on finding a semantic error in the ToC entry
307de08ca2dSAndrew Jeffery *
308de08ca2dSAndrew Jeffery * If the syntax of the ToC entry is correct but the semantics are broken,
309de08ca2dSAndrew Jeffery * then we have an invalid ToC entry.
310de08ca2dSAndrew Jeffery */
311de08ca2dSAndrew Jeffery class InvalidTocEntry : public TocEntryError
312de08ca2dSAndrew Jeffery {
313de08ca2dSAndrew Jeffery public:
InvalidTocEntry(const std::string && reason)314de08ca2dSAndrew Jeffery InvalidTocEntry(const std::string&& reason) :
315de08ca2dSAndrew Jeffery TocEntryError(std::move(reason))
316fab4020dSEd Tanous {
317fab4020dSEd Tanous }
318de08ca2dSAndrew Jeffery };
319de08ca2dSAndrew Jeffery
320de08ca2dSAndrew Jeffery class UnmappedOffset : public std::exception
321de08ca2dSAndrew Jeffery {
322de08ca2dSAndrew Jeffery public:
UnmappedOffset(size_t base,size_t next)323de08ca2dSAndrew Jeffery UnmappedOffset(size_t base, size_t next) : base(base), next(next)
324fab4020dSEd Tanous {
325fab4020dSEd Tanous }
326de08ca2dSAndrew Jeffery
327de08ca2dSAndrew Jeffery const size_t base;
328de08ca2dSAndrew Jeffery const size_t next;
329de08ca2dSAndrew Jeffery };
330de08ca2dSAndrew Jeffery
331de08ca2dSAndrew Jeffery class OutOfBoundsOffset : public ReasonedError
332de08ca2dSAndrew Jeffery {
333de08ca2dSAndrew Jeffery public:
OutOfBoundsOffset(const std::string && reason)334de08ca2dSAndrew Jeffery OutOfBoundsOffset(const std::string&& reason) :
335de08ca2dSAndrew Jeffery ReasonedError(std::move(reason))
336fab4020dSEd Tanous {
337fab4020dSEd Tanous }
338de08ca2dSAndrew Jeffery };
339de08ca2dSAndrew Jeffery
340de08ca2dSAndrew Jeffery class UnknownPartition : public ReasonedError
341de08ca2dSAndrew Jeffery {
342de08ca2dSAndrew Jeffery public:
UnknownPartition(const std::string && reason)343de08ca2dSAndrew Jeffery UnknownPartition(const std::string&& reason) :
344de08ca2dSAndrew Jeffery ReasonedError(std::move(reason))
345fab4020dSEd Tanous {
346fab4020dSEd Tanous }
347de08ca2dSAndrew Jeffery };
348de08ca2dSAndrew Jeffery
349de08ca2dSAndrew Jeffery } // namespace virtual_pnor
350de08ca2dSAndrew Jeffery } // namespace openpower
351de08ca2dSAndrew Jeffery
352de08ca2dSAndrew Jeffery struct vpnor_partition_table
353de08ca2dSAndrew Jeffery {
354de08ca2dSAndrew Jeffery openpower::virtual_pnor::partition::Table* table;
355de08ca2dSAndrew Jeffery };
356