xref: /openbmc/hiomapd/vpnor/table.hpp (revision 150be912a3f9f718d4ec69b756449906f392e2cd)
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