summaryrefslogtreecommitdiffstats
path: root/pnor_partition_table.hpp
blob: 730e75b6eeb07530387ba698b0f981885742e230 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/* SPDX-License-Identifier: Apache-2.0 */
/* Copyright (C) 2018 IBM Corp. */
#pragma once

#include <vector>
#include <memory>
#include <numeric>
#include <experimental/filesystem>
#include "common.h"
#include "pnor_partition_defs.h"

namespace openpower
{
namespace virtual_pnor
{

namespace fs = std::experimental::filesystem;

using PartitionTable = std::vector<uint8_t>;
using checksum_t = uint32_t;

/** @brief Convert the input partition table to big endian.
 *
 *  @param[in] src - reference to the pnor partition table
 *
 *  @returns converted partition table
 */
PartitionTable endianFixup(const PartitionTable& src);

/** @brief Parse a ToC line (entry) into the corresponding FFS partition
 * object.
 *
 * @param[in] line - The ToC line to parse
 * @param[in] blockSize - The flash block size in bytes
 * @param[out] part - The partition object to populate with the information
 *                    parsed from the provided ToC line
 *
 * Throws: MalformedTocEntry, InvalidTocEntry
 */
void parseTocLine(const std::string& line, size_t blockSize,
                  pnor_partition& part);

namespace details
{

/** @brief Compute XOR-based checksum, by XORing consecutive words
 *         in the input data. Input must be aligned to word boundary.
 *
 *  @param[in] data - input data on which checksum is computed
 *
 *  @returns computed checksum
 */
template <class T> checksum_t checksum(const T& data)
{
    static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
                  "sizeof(data) is not aligned to sizeof(checksum_t) boundary");

    auto begin = reinterpret_cast<const checksum_t*>(&data);
    auto end = begin + (sizeof(decltype(data)) / sizeof(checksum_t));

    return std::accumulate(begin, end, 0, std::bit_xor<checksum_t>());
}

} // namespace details

namespace partition
{

/** @class Table
 *  @brief Generates virtual PNOR partition table.
 *
 *  Generates virtual PNOR partition table upon construction. Reads
 *  the PNOR information generated by this tool :
 *  github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-squashfs,
 *  which generates a minimalistic table-of-contents (toc) file and
 *  individual files to represent various partitions that are of interest -
 *  these help form the "virtual" PNOR, which is typically a subset of the full
 *  PNOR image.
 *  These files are stored in a well-known location on the PNOR.
 *  Based on this information, this class prepares the partition table whose
 *  structure is as outlined in pnor_partition.h.
 *
 *  The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
 *  this size.
 */
class Table
{
  public:
    /** @brief Constructor accepting the path of the directory
     *         that houses the PNOR partition files.
     *
     *  @param[in] directory - path of the directory housing PNOR partitions
     *  @param[in] blockSize - PNOR block size, in bytes. See
     *             open-power/hostboot/blob/master/src/usr/pnor/ffs.h for
     *             the PNOR FFS structure.
     *  @param[in] pnorSize - PNOR size, in bytes
     *
     * Throws MalformedTocEntry, InvalidTocEntry
     */
    Table(fs::path&& directory, size_t blockSize, size_t pnorSize);

    Table(const Table&) = delete;
    Table& operator=(const Table&) = delete;
    Table(Table&&) = delete;
    Table& operator=(Table&&) = delete;
    ~Table() = default;

    /** @brief Return the exact size of partition table in bytes
     *
     *  @returns size_t - size of partition table in bytes
     */
    size_t size() const
    {
        return szBytes;
    }

    /** @brief Return aligned size of partition table in bytes
     *
     *  The value returned will be greater-than or equal to size(), and
     *  aligned to blockSize.
     *
     *  @returns size_t - capacity of partition table in bytes
     */
    size_t capacity() const
    {
        return align_up(szBytes, blockSize);
    }

    /** @brief Return the size of partition table in blocks
     *
     *  @returns size_t - size of partition table in blocks
     */
    size_t blocks() const
    {
        return capacity() / blockSize;
    }

    /** @brief Return a partition table having byte-ordering
     *         that the host expects.
     *
     *  The host needs the partion table in big-endian.
     *
     *  @returns const reference to host partition table.
     */
    const pnor_partition_table& getHostTable() const
    {
        return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
    }

    /** @brief Return a little-endian partition table
     *
     *  @returns const reference to native partition table
     */
    const pnor_partition_table& getNativeTable() const
    {
        return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
    }

    /** @brief Return partition corresponding to PNOR offset, the offset
     *         is within returned partition.
     *
     *  @param[in] offset - PNOR offset in bytes
     *
     *  @returns const reference to pnor_partition, if found, else an
     *           exception will be thrown.
     */
    const pnor_partition& partition(size_t offset) const;

    /** @brief Return partition corresponding to input partition name.
     *
     *  @param[in] name - PNOR partition name
     *
     *  @returns const reference to pnor_partition, if found, else an
     *           exception will be thrown.
     */
    const pnor_partition& partition(const std::string& name) const;

  private:
    /** @brief Prepares a vector of PNOR partition structures.
     *
     * Throws: MalformedTocEntry, InvalidTocEntry
     */
    void preparePartitions();

    /** @brief Prepares the PNOR header.
     */
    void prepareHeader();

    /** @brief Allocate memory to hold the partion table. Determine the
     *         amount needed based on the partition files in the toc file.
     *
     *  @param[in] tocFile - Table of contents file path.
     */
    void allocateMemory(const fs::path& tocFile);

    /** @brief Return a little-endian partition table
     *
     *  @returns reference to native partition table
     */
    pnor_partition_table& getNativeTable()
    {
        return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
    }

    /** @brief Size of the PNOR partition table -
     *         sizeof(pnor_partition_table) +
     *         (no. of partitions * sizeof(pnor_partition)),
     */
    size_t szBytes;

    /** @brief Partition table */
    PartitionTable tbl;

    /** @brief Partition table with host byte ordering */
    PartitionTable hostTbl;

    /** @brief Directory housing generated PNOR partition files */
    fs::path directory;

    /** @brief Number of partitions */
    size_t numParts;

    /** @brief PNOR block size, in bytes */
    size_t blockSize;

    /** @brief PNOR size, in bytes */
    size_t pnorSize;
};
} // namespace partition

/** @brief An exception type storing a reason string.
 *
 *  This looks a lot like how std::runtime_error might be implemented however
 *  we want to avoid extending it, as exceptions extending ReasonedError have
 *  an expectation of being handled (can be predicted and are inside the scope
 *  of the program).
 *
 *  From std::runtime_error documentation[1]:
 *
 *  > Defines a type of object to be thrown as exception. It reports errors
 *  > that are due to events beyond the scope of the program and can not be
 *  > easily predicted.
 *
 *  [1] http://en.cppreference.com/w/cpp/error/runtime_error
 *
 *  We need to keep the inheritance hierarchy separate: This avoids the
 *  introduction of code that overzealously catches std::runtime_error to
 *  handle exceptions that would otherwise derive ReasonedError, and in the
 *  process swallows genuine runtime failures.
 */
class ReasonedError : public std::exception
{
  public:
    ReasonedError(const std::string&& what) : _what(what)
    {
    }
    const char* what() const noexcept
    {
        return _what.c_str();
    };

  private:
    const std::string _what;
};

/** @brief Base exception type for errors related to ToC entry parsing.
 *
 *  Callers of parseTocEntry() may not be concerned with the specifics and
 *  rather just want to extract and log what().
 */
class TocEntryError : public ReasonedError
{
  public:
    TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
    {
    }
};

/** @brief The exception thrown on finding a syntax error in the ToC entry
 *
 *  If the syntax is wrong, or expected values are missing, the ToC entry is
 *  malformed
 */
class MalformedTocEntry : public TocEntryError
{
  public:
    MalformedTocEntry(const std::string&& reason) :
        TocEntryError(std::move(reason))
    {
    }
};

/** @brief The exception thrown on finding a semantic error in the ToC entry
 *
 *  If the syntax of the ToC entry is correct but the semantics are broken,
 *  then we have an invalid ToC entry.
 */
class InvalidTocEntry : public TocEntryError
{
  public:
    InvalidTocEntry(const std::string&& reason) :
        TocEntryError(std::move(reason))
    {
    }
};

} // namespace virtual_pnor
} // namespace openpower

struct vpnor_partition_table
{
    openpower::virtual_pnor::partition::Table* table;
};
OpenPOWER on IntegriCloud