backend.cpp (f4bc335b4fc899509c92c230f746fe90a5aa43d2) backend.cpp (035ad76b8b45a01cc7fcc184e7e72eed69c0ece5)
1// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
3
1// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
3
4#include "config.h"
5
4#include <fcntl.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include <sys/ioctl.h>
8#include <sys/mman.h>
9#include <syslog.h>
10#include <unistd.h>
11
12#include <algorithm>
13
14extern "C" {
6#include <fcntl.h>
7#include <stdint.h>
8#include <stdlib.h>
9#include <sys/ioctl.h>
10#include <sys/mman.h>
11#include <syslog.h>
12#include <unistd.h>
13
14#include <algorithm>
15
16extern "C" {
17#include "backend.h"
15#include "common.h"
16#include "lpc.h"
17#include "mboxd.h"
18#include "protocol.h"
18#include "common.h"
19#include "lpc.h"
20#include "mboxd.h"
21#include "protocol.h"
22#include "vpnor/backend.h"
19}
20
23}
24
21#include "config.h"
22
23#include "pnor_partition.hpp"
24#include "pnor_partition_table.hpp"
25#include "xyz/openbmc_project/Common/error.hpp"
26
25#include "pnor_partition.hpp"
26#include "pnor_partition_table.hpp"
27#include "xyz/openbmc_project/Common/error.hpp"
28
29#include <cassert>
27#include <exception>
30#include <exception>
31#include <experimental/filesystem>
28#include <memory>
29#include <phosphor-logging/elog-errors.hpp>
30#include <phosphor-logging/log.hpp>
31#include <stdexcept>
32#include <string>
33
34#include "vpnor/backend.h"
35
36namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
37namespace fs = std::experimental::filesystem;
38namespace vpnor = openpower::virtual_pnor;
39
40static constexpr uint32_t VPNOR_ERASE_SIZE = 4 * 1024;
41
32#include <memory>
33#include <phosphor-logging/elog-errors.hpp>
34#include <phosphor-logging/log.hpp>
35#include <stdexcept>
36#include <string>
37
38#include "vpnor/backend.h"
39
40namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
41namespace fs = std::experimental::filesystem;
42namespace vpnor = openpower::virtual_pnor;
43
44static constexpr uint32_t VPNOR_ERASE_SIZE = 4 * 1024;
45
46void vpnor_default_paths(vpnor_partition_paths* paths)
47{
48 strncpy(paths->ro_loc, PARTITION_FILES_RO_LOC, PATH_MAX);
49 paths->ro_loc[PATH_MAX - 1] = '\0';
50 strncpy(paths->rw_loc, PARTITION_FILES_RW_LOC, PATH_MAX);
51 paths->rw_loc[PATH_MAX - 1] = '\0';
52 strncpy(paths->prsv_loc, PARTITION_FILES_PRSV_LOC, PATH_MAX);
53 paths->prsv_loc[PATH_MAX - 1] = '\0';
54 strncpy(paths->patch_loc, PARTITION_FILES_PATCH_LOC, PATH_MAX);
55 paths->prsv_loc[PATH_MAX - 1] = '\0';
56}
57
58/** @brief Create a virtual PNOR partition table.
59 *
60 * @param[in] backend - The backend context pointer
61 * @param[in] paths - A paths object pointer to initialise vpnor
62 *
63 * This API should be called before calling any other APIs below. If a table
64 * already exists, this function will not do anything further. This function
65 * will not do anything if the context is NULL.
66 *
67 * The content of the paths object is copied out, ownership is retained by the
68 * caller.
69 *
70 * Returns 0 if the call succeeds, else a negative error code.
71 */
72static int vpnor_init(struct backend* backend,
73 const vpnor_partition_paths* paths)
74{
75 namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
76 namespace fs = std::experimental::filesystem;
77 namespace vpnor = openpower::virtual_pnor;
78
79 vpnor_data* priv = new vpnor_data;
80 assert(priv);
81
82 priv->paths = *paths;
83 backend->priv = priv;
84
85 try
86 {
87 priv->vpnor = new vpnor_partition_table;
88 priv->vpnor->table =
89 new openpower::virtual_pnor::partition::Table(backend);
90 }
91 catch (vpnor::TocEntryError& e)
92 {
93 MSG_ERR("%s\n", e.what());
94 try
95 {
96 phosphor::logging::commit<err::InternalFailure>();
97 }
98 catch (const std::exception& e)
99 {
100 MSG_ERR("Failed to commit InternalFailure: %s\n", e.what());
101 }
102 return -EINVAL;
103 }
104
105 return 0;
106}
107
108/** @brief Copy bootloader partition (alongwith TOC) to LPC memory
109 *
110 * @param[in] backend - The backend context pointer
111 *
112 * @returns 0 on success, negative error code on failure
113 */
114int vpnor_copy_bootloader_partition(const struct backend* backend, void* buf,
115 uint32_t count)
116{
117 // The hostboot bootloader has certain size/offset assumptions, so
118 // we need a special partition table here.
119 // It assumes the PNOR is 64M, the TOC size is 32K, the erase block is
120 // 4K, the page size is 4K.
121 // It also assumes the TOC is at the 'end of pnor - toc size - 1 page size'
122 // offset, and first looks for the TOC here, before proceeding to move up
123 // page by page looking for the TOC. So it is optimal to place the TOC at
124 // this offset.
125 constexpr size_t eraseSize = 0x1000;
126 constexpr size_t pageSize = 0x1000;
127 constexpr size_t pnorSize = 0x4000000;
128 constexpr size_t tocMaxSize = 0x8000;
129 constexpr size_t tocStart = pnorSize - tocMaxSize - pageSize;
130 constexpr auto blPartitionName = "HBB";
131
132 namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
133 namespace fs = std::experimental::filesystem;
134 namespace vpnor = openpower::virtual_pnor;
135
136 try
137 {
138 vpnor_partition_table vtbl{};
139 struct vpnor_data priv;
140 struct backend local = *backend;
141
142 priv.vpnor = &vtbl;
143 priv.paths = ((struct vpnor_data*)backend->priv)->paths;
144 local.priv = &priv;
145 local.block_size_shift = log_2(eraseSize);
146
147 openpower::virtual_pnor::partition::Table blTable(&local);
148
149 vtbl.table = &blTable;
150
151 size_t tocOffset = 0;
152
153 const pnor_partition& partition = blTable.partition(blPartitionName);
154 size_t hbbOffset = partition.data.base * eraseSize;
155 uint32_t hbbSize = partition.data.actual;
156
157 if (count < tocStart + blTable.capacity() ||
158 count < hbbOffset + hbbSize)
159 {
160 MSG_ERR("Reserved memory too small for dumb bootstrap\n");
161 return -EINVAL;
162 }
163
164 uint8_t* buf8 = static_cast<uint8_t*>(buf);
165 backend_copy(&local, tocOffset, buf8 + tocStart, blTable.capacity());
166 backend_copy(&local, hbbOffset, buf8 + hbbOffset, hbbSize);
167 }
168 catch (err::InternalFailure& e)
169 {
170 phosphor::logging::commit<err::InternalFailure>();
171 return -EIO;
172 }
173 catch (vpnor::ReasonedError& e)
174 {
175 MSG_ERR("%s\n", e.what());
176 phosphor::logging::commit<err::InternalFailure>();
177 return -EIO;
178 }
179
180 return 0;
181}
182
42int vpnor_dev_init(struct backend* backend, void* data)
43{
44 vpnor_partition_paths* paths = (vpnor_partition_paths*)data;
45 struct mtd_info_user mtd_info;
46 const char* filename = NULL;
47 int fd;
48 int rc = 0;
49

--- 56 unchanged lines hidden (view full) ---

106cleanup_filename:
107 free((void*)filename);
108
109 return rc;
110}
111
112static void vpnor_free(struct backend* backend)
113{
183int vpnor_dev_init(struct backend* backend, void* data)
184{
185 vpnor_partition_paths* paths = (vpnor_partition_paths*)data;
186 struct mtd_info_user mtd_info;
187 const char* filename = NULL;
188 int fd;
189 int rc = 0;
190

--- 56 unchanged lines hidden (view full) ---

247cleanup_filename:
248 free((void*)filename);
249
250 return rc;
251}
252
253static void vpnor_free(struct backend* backend)
254{
114 vpnor_destroy(backend);
255 struct vpnor_data* priv = (struct vpnor_data*)backend->priv;
256
257 if (priv)
258 {
259 if (priv->vpnor)
260 {
261 delete priv->vpnor->table;
262 }
263 delete priv->vpnor;
264 }
265 delete priv;
115}
116
117/*
118 * vpnor_copy() - Copy data from the virtual pnor into a provided buffer
119 * @context: The backend context pointer
120 * @offset: The pnor offset to copy from (bytes)
121 * @mem: The buffer to copy into (must be of atleast 'size' bytes)
122 * @size: The number of bytes to copy

--- 170 unchanged lines hidden (view full) ---

293 */
294static int vpnor_reset(struct backend* backend, void* buf, uint32_t count)
295{
296 const struct vpnor_data* priv = (const struct vpnor_data*)backend->priv;
297 int rc;
298
299 vpnor_partition_paths paths = priv->paths;
300
266}
267
268/*
269 * vpnor_copy() - Copy data from the virtual pnor into a provided buffer
270 * @context: The backend context pointer
271 * @offset: The pnor offset to copy from (bytes)
272 * @mem: The buffer to copy into (must be of atleast 'size' bytes)
273 * @size: The number of bytes to copy

--- 170 unchanged lines hidden (view full) ---

444 */
445static int vpnor_reset(struct backend* backend, void* buf, uint32_t count)
446{
447 const struct vpnor_data* priv = (const struct vpnor_data*)backend->priv;
448 int rc;
449
450 vpnor_partition_paths paths = priv->paths;
451
301 vpnor_destroy(backend);
452 vpnor_free(backend);
302
303 rc = vpnor_init(backend, &paths);
304 if (rc < 0)
305 return rc;
306
307 rc = vpnor_copy_bootloader_partition(backend, buf, count);
308 if (rc < 0)
309 return rc;

--- 34 unchanged lines hidden ---
453
454 rc = vpnor_init(backend, &paths);
455 if (rc < 0)
456 return rc;
457
458 rc = vpnor_copy_bootloader_partition(backend, buf, count);
459 if (rc < 0)
460 return rc;

--- 34 unchanged lines hidden ---