blob: 1b932a1a812bd1e485214e6ef2c5e041ed3af4c2 [file] [log] [blame]
Andrew Jefferyacee6832018-02-21 22:17:08 +10301/*
2 * Mailbox Daemon Implementation
3 *
4 * Copyright 2018 IBM
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
Deepak Kodihalli393821d2017-04-28 04:44:38 -050019#pragma once
20
21#include <vector>
22#include <memory>
23#include <numeric>
24#include <experimental/filesystem>
Andrew Jeffery7f9c3432018-03-01 12:07:13 +103025#include "common.h"
Deepak Kodihalli393821d2017-04-28 04:44:38 -050026#include "pnor_partition_defs.h"
27
28namespace openpower
29{
30namespace virtual_pnor
31{
32
33namespace fs = std::experimental::filesystem;
34
35using PartitionTable = std::vector<uint8_t>;
36using checksum_t = uint32_t;
37
38/** @brief Convert the input partition table to big endian.
39 *
40 * @param[in] src - reference to the pnor partition table
41 *
42 * @returns converted partition table
43 */
44PartitionTable endianFixup(const PartitionTable& src);
45
Andrew Jefferyd394a782018-02-21 16:16:14 +103046/** @brief Parse a ToC line (entry) into the corresponding FFS partition
47 * object.
48 *
49 * @param[in] line - The ToC line to parse
50 * @param[in] blockSize - The flash block size in bytes
51 * @param[out] part - The partition object to populate with the information
52 * parsed from the provided ToC line
53 *
Andrew Jefferyf96bd162018-02-26 13:05:00 +103054 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyd394a782018-02-21 16:16:14 +103055 */
Andrew Jefferyf96bd162018-02-26 13:05:00 +103056void parseTocLine(const std::string& line, size_t blockSize,
Andrew Jefferyd394a782018-02-21 16:16:14 +103057 pnor_partition& part);
58
Deepak Kodihalli393821d2017-04-28 04:44:38 -050059namespace details
60{
61
62/** @brief Compute XOR-based checksum, by XORing consecutive words
63 * in the input data. Input must be aligned to word boundary.
64 *
65 * @param[in] data - input data on which checksum is computed
66 *
67 * @returns computed checksum
68 */
Andrew Jefferyf34db312018-03-09 15:27:03 +103069template <class T> checksum_t checksum(const T& data)
Deepak Kodihalli393821d2017-04-28 04:44:38 -050070{
71 static_assert(sizeof(decltype(data)) % sizeof(checksum_t) == 0,
72 "sizeof(data) is not aligned to sizeof(checksum_t) boundary");
73
74 auto begin = reinterpret_cast<const checksum_t*>(&data);
75 auto end = begin + (sizeof(decltype(data)) / sizeof(checksum_t));
76
77 return std::accumulate(begin, end, 0, std::bit_xor<checksum_t>());
78}
79
80} // namespace details
81
82namespace partition
83{
84
85/** @class Table
86 * @brief Generates virtual PNOR partition table.
87 *
88 * Generates virtual PNOR partition table upon construction. Reads
89 * the PNOR information generated by this tool :
90 * github.com/openbmc/openpower-pnor-code-mgmt/blob/master/generate-squashfs,
91 * which generates a minimalistic table-of-contents (toc) file and
92 * individual files to represent various partitions that are of interest -
93 * these help form the "virtual" PNOR, which is typically a subset of the full
94 * PNOR image.
95 * These files are stored in a well-known location on the PNOR.
96 * Based on this information, this class prepares the partition table whose
97 * structure is as outlined in pnor_partition.h.
98 *
99 * The virtual PNOR supports 4KB erase blocks - partitions must be aligned to
100 * this size.
101 */
102class Table
103{
Andrew Jefferyf34db312018-03-09 15:27:03 +1030104 public:
105 /** @brief Constructor accepting the path of the directory
106 * that houses the PNOR partition files.
107 *
108 * @param[in] directory - path of the directory housing PNOR partitions
109 * @param[in] blockSize - PNOR block size, in bytes. See
110 * open-power/hostboot/blob/master/src/usr/pnor/ffs.h for
111 * the PNOR FFS structure.
112 * @param[in] pnorSize - PNOR size, in bytes
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030113 *
114 * Throws MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030115 */
116 Table(fs::path&& directory, size_t blockSize, size_t pnorSize);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500117
Andrew Jefferyf34db312018-03-09 15:27:03 +1030118 Table(const Table&) = delete;
119 Table& operator=(const Table&) = delete;
120 Table(Table&&) = delete;
121 Table& operator=(Table&&) = delete;
122 ~Table() = default;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500123
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030124 /** @brief Return the exact size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030125 *
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030126 * @returns size_t - size of partition table in bytes
Andrew Jefferyf34db312018-03-09 15:27:03 +1030127 */
128 size_t size() const
129 {
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030130 return szBytes;
131 }
132
133 /** @brief Return aligned size of partition table in bytes
134 *
135 * The value returned will be greater-than or equal to size(), and
136 * aligned to blockSize.
137 *
138 * @returns size_t - capacity of partition table in bytes
139 */
140 size_t capacity() const
141 {
142 return align_up(szBytes, blockSize);
143 }
144
145 /** @brief Return the size of partition table in blocks
146 *
147 * @returns size_t - size of partition table in blocks
148 */
149 size_t blocks() const
150 {
151 return capacity() / blockSize;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030152 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500153
Andrew Jefferyf34db312018-03-09 15:27:03 +1030154 /** @brief Return a partition table having byte-ordering
155 * that the host expects.
156 *
157 * The host needs the partion table in big-endian.
158 *
159 * @returns const reference to host partition table.
160 */
161 const pnor_partition_table& getHostTable() const
162 {
163 return *(reinterpret_cast<const pnor_partition_table*>(hostTbl.data()));
164 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500165
Andrew Jefferyf34db312018-03-09 15:27:03 +1030166 /** @brief Return a little-endian partition table
167 *
168 * @returns const reference to native partition table
169 */
170 const pnor_partition_table& getNativeTable() const
171 {
172 return *(reinterpret_cast<const pnor_partition_table*>(tbl.data()));
173 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500174
Andrew Jefferyf34db312018-03-09 15:27:03 +1030175 /** @brief Return partition corresponding to PNOR offset, the offset
176 * is within returned partition.
177 *
178 * @param[in] offset - PNOR offset in bytes
179 *
180 * @returns const reference to pnor_partition, if found, else an
181 * exception will be thrown.
182 */
183 const pnor_partition& partition(size_t offset) const;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500184
Andrew Jefferyf34db312018-03-09 15:27:03 +1030185 /** @brief Return partition corresponding to input partition name.
186 *
187 * @param[in] name - PNOR partition name
188 *
189 * @returns const reference to pnor_partition, if found, else an
190 * exception will be thrown.
191 */
192 const pnor_partition& partition(const std::string& name) const;
Deepak Kodihalli8a899692017-07-11 23:17:19 -0500193
Andrew Jefferyf34db312018-03-09 15:27:03 +1030194 private:
195 /** @brief Prepares a vector of PNOR partition structures.
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030196 *
197 * Throws: MalformedTocEntry, InvalidTocEntry
Andrew Jefferyf34db312018-03-09 15:27:03 +1030198 */
199 void preparePartitions();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500200
Andrew Jefferyf34db312018-03-09 15:27:03 +1030201 /** @brief Prepares the PNOR header.
202 */
203 void prepareHeader();
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500204
Andrew Jefferyf34db312018-03-09 15:27:03 +1030205 /** @brief Allocate memory to hold the partion table. Determine the
206 * amount needed based on the partition files in the toc file.
207 *
208 * @param[in] tocFile - Table of contents file path.
209 */
210 void allocateMemory(const fs::path& tocFile);
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500211
Andrew Jefferyf34db312018-03-09 15:27:03 +1030212 /** @brief Return a little-endian partition table
213 *
214 * @returns reference to native partition table
215 */
216 pnor_partition_table& getNativeTable()
217 {
218 return *(reinterpret_cast<pnor_partition_table*>(tbl.data()));
219 }
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500220
Andrew Jefferyf34db312018-03-09 15:27:03 +1030221 /** @brief Size of the PNOR partition table -
222 * sizeof(pnor_partition_table) +
223 * (no. of partitions * sizeof(pnor_partition)),
Andrew Jefferyf34db312018-03-09 15:27:03 +1030224 */
Andrew Jeffery7f9c3432018-03-01 12:07:13 +1030225 size_t szBytes;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500226
Andrew Jefferyf34db312018-03-09 15:27:03 +1030227 /** @brief Partition table */
228 PartitionTable tbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500229
Andrew Jefferyf34db312018-03-09 15:27:03 +1030230 /** @brief Partition table with host byte ordering */
231 PartitionTable hostTbl;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500232
Andrew Jefferyf34db312018-03-09 15:27:03 +1030233 /** @brief Directory housing generated PNOR partition files */
234 fs::path directory;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500235
Andrew Jefferyf34db312018-03-09 15:27:03 +1030236 /** @brief Number of partitions */
237 size_t numParts;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500238
Andrew Jefferyf34db312018-03-09 15:27:03 +1030239 /** @brief PNOR block size, in bytes */
240 size_t blockSize;
Deepak Kodihallid1d79302017-07-11 23:01:39 -0500241
Andrew Jefferyf34db312018-03-09 15:27:03 +1030242 /** @brief PNOR size, in bytes */
243 size_t pnorSize;
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500244};
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500245} // namespace partition
Andrew Jefferyf96bd162018-02-26 13:05:00 +1030246
247/** @brief An exception type storing a reason string.
248 *
249 * This looks a lot like how std::runtime_error might be implemented however
250 * we want to avoid extending it, as exceptions extending ReasonedError have
251 * an expectation of being handled (can be predicted and are inside the scope
252 * of the program).
253 *
254 * From std::runtime_error documentation[1]:
255 *
256 * > Defines a type of object to be thrown as exception. It reports errors
257 * > that are due to events beyond the scope of the program and can not be
258 * > easily predicted.
259 *
260 * [1] http://en.cppreference.com/w/cpp/error/runtime_error
261 *
262 * We need to keep the inheritance hierarchy separate: This avoids the
263 * introduction of code that overzealously catches std::runtime_error to
264 * handle exceptions that would otherwise derive ReasonedError, and in the
265 * process swallows genuine runtime failures.
266 */
267class ReasonedError : public std::exception
268{
269 public:
270 ReasonedError(const std::string&& what) : _what(what)
271 {
272 }
273 const char* what() const noexcept
274 {
275 return _what.c_str();
276 };
277
278 private:
279 const std::string _what;
280};
281
282/** @brief Base exception type for errors related to ToC entry parsing.
283 *
284 * Callers of parseTocEntry() may not be concerned with the specifics and
285 * rather just want to extract and log what().
286 */
287class TocEntryError : public ReasonedError
288{
289 public:
290 TocEntryError(const std::string&& reason) : ReasonedError(std::move(reason))
291 {
292 }
293};
294
295/** @brief The exception thrown on finding a syntax error in the ToC entry
296 *
297 * If the syntax is wrong, or expected values are missing, the ToC entry is
298 * malformed
299 */
300class MalformedTocEntry : public TocEntryError
301{
302 public:
303 MalformedTocEntry(const std::string&& reason) :
304 TocEntryError(std::move(reason))
305 {
306 }
307};
308
309/** @brief The exception thrown on finding a semantic error in the ToC entry
310 *
311 * If the syntax of the ToC entry is correct but the semantics are broken,
312 * then we have an invalid ToC entry.
313 */
314class InvalidTocEntry : public TocEntryError
315{
316 public:
317 InvalidTocEntry(const std::string&& reason) :
318 TocEntryError(std::move(reason))
319 {
320 }
321};
322
Deepak Kodihalli393821d2017-04-28 04:44:38 -0500323} // namespace virtual_pnor
324} // namespace openpower