blob: cd2a37f2c5adc8b995bf93e91b743933afbc8051 [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -05003
Ratan Gupta8441a392017-05-05 21:42:53 +05304#include <fcntl.h>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -05005#include <stdint.h>
6#include <stdlib.h>
Deepak Kodihalliabd52a72017-07-13 12:04:06 -05007#include <sys/ioctl.h>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -07008#include <sys/mman.h>
9#include <syslog.h>
10#include <unistd.h>
11
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -050012#include <algorithm>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050013
14extern "C" {
15#include "common.h"
Andrew Jeffery71eaa732018-08-08 16:44:24 +093016#include "flash.h"
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050017}
18
Ratan Gupta8441a392017-05-05 21:42:53 +053019#include "config.h"
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070020
Ratan Gupta6a98e182017-06-06 15:04:23 +053021#include "pnor_partition.hpp"
Andrew Jefferyae1edb92018-02-28 23:16:48 +103022#include "pnor_partition_table.hpp"
Ratan Gupta6a98e182017-06-06 15:04:23 +053023#include "xyz/openbmc_project/Common/error.hpp"
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050024
Ratan Gupta8441a392017-05-05 21:42:53 +053025#include <exception>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070026#include <memory>
27#include <phosphor-logging/elog-errors.hpp>
28#include <phosphor-logging/log.hpp>
Ratan Gupta8441a392017-05-05 21:42:53 +053029#include <stdexcept>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070030#include <string>
31
32#include "mboxd_pnor_partition_table.h"
Ratan Gupta8441a392017-05-05 21:42:53 +053033
Andrew Jefferyae1edb92018-02-28 23:16:48 +103034namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
Andrew Jefferyad343102018-02-28 00:35:50 +103035namespace fs = std::experimental::filesystem;
Andrew Jefferyae1edb92018-02-28 23:16:48 +103036namespace vpnor = openpower::virtual_pnor;
37
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050038/** @brief unique_ptr functor to release a char* reference. */
39struct StringDeleter
40{
41 void operator()(char* ptr) const
42 {
43 free(ptr);
44 }
45};
46using StringPtr = std::unique_ptr<char, StringDeleter>;
47
Andrew Jefferyd6b09bc2018-08-08 16:47:54 +093048int flash_dev_init(struct mbox_context* context)
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050049{
50 StringPtr filename(get_dev_mtd());
51 int fd = 0;
52 int rc = 0;
53
54 if (!filename)
55 {
56 MSG_ERR("Couldn't find the flash /dev/mtd partition\n");
57 return -1;
58 }
59
60 MSG_DBG("Opening %s\n", filename.get());
61
62 fd = open(filename.get(), O_RDWR);
63 if (fd < 0)
64 {
Andrew Jefferyf34db312018-03-09 15:27:03 +103065 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", filename.get(),
66 strerror(errno));
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050067 return -errno;
68 }
69
70 // Read the Flash Info
71 if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1)
72 {
Andrew Jefferyf34db312018-03-09 15:27:03 +103073 MSG_ERR("Couldn't get information about MTD: %s\n", strerror(errno));
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050074 close(fd);
75 return -errno;
76 }
77
78 if (context->flash_size == 0)
79 {
80 // See comment in mboxd_flash_physical.c on why
81 // this is needed.
82 context->flash_size = context->mtd_info.size;
83 }
84
85 // Hostboot requires a 4K block-size to be used in the FFS flash structure
86 context->mtd_info.erasesize = 4096;
87 context->erase_size_shift = log_2(context->mtd_info.erasesize);
88 context->flash_bmap = NULL;
89 context->fds[MTD_FD].fd = -1;
90
91 close(fd);
92 return rc;
93}
94
Andrew Jefferydec6ca62018-08-08 16:49:43 +093095void flash_dev_free(struct mbox_context* context)
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050096{
97 // No-op
98}
99
Andrew Jefferyf953f792018-08-08 16:56:03 +0930100int flash_set_bytemap(struct mbox_context* context, uint32_t offset,
Deepak Kodihalliabd52a72017-07-13 12:04:06 -0500101 uint32_t count, uint8_t val)
102{
103 // No-op
104 return 0;
105}
106
Andrew Jeffery4f5d29c2018-08-08 16:58:04 +0930107int flash_erase(struct mbox_context* context, uint32_t offset, uint32_t count)
Deepak Kodihalliabd52a72017-07-13 12:04:06 -0500108{
109 // No-op
110 return 0;
111}
112
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500113/*
Andrew Jefferye0cdd3e2018-08-08 16:51:44 +0930114 * flash_copy() - Copy data from the virtual pnor into a provided buffer
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500115 * @context: The mbox context pointer
116 * @offset: The pnor offset to copy from (bytes)
117 * @mem: The buffer to copy into (must be of atleast 'size' bytes)
118 * @size: The number of bytes to copy
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500119 * Return: Number of bytes copied on success, otherwise negative error
Andrew Jefferye0cdd3e2018-08-08 16:51:44 +0930120 * code. flash_copy will copy at most 'size' bytes, but it may
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500121 * copy less.
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500122 */
Andrew Jefferye0cdd3e2018-08-08 16:51:44 +0930123int64_t flash_copy(struct mbox_context* context, uint32_t offset, void* mem,
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500124 uint32_t size)
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500125{
Andrew Jefferyfc621582018-02-28 22:20:19 +1030126 vpnor::partition::Table* table;
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500127 int rc = size;
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500128
Andrew Jefferyfc621582018-02-28 22:20:19 +1030129 if (!(context && context->vpnor && context->vpnor->table))
130 {
131 MSG_ERR("Trying to copy data with uninitialised context!\n");
Andrew Jeffery8eab2152018-08-09 23:47:29 +0930132 return -EINVAL;
Andrew Jefferyfc621582018-02-28 22:20:19 +1030133 }
134
135 table = context->vpnor->table;
136
Andrew Jefferyf34db312018-03-09 15:27:03 +1030137 MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n", mem,
138 size, offset);
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500139
140 /* The virtual PNOR partition table starts at offset 0 in the virtual
141 * pnor image. Check if host asked for an offset that lies within the
142 * partition table.
143 */
Andrew Jefferyfc621582018-02-28 22:20:19 +1030144 size_t sz = table->size();
145 if (offset < sz)
146 {
147 const pnor_partition_table& toc = table->getHostTable();
148 rc = std::min(sz - offset, static_cast<size_t>(size));
149 memcpy(mem, ((uint8_t*)&toc) + offset, rc);
150 return rc;
151 }
152
Ratan Gupta8441a392017-05-05 21:42:53 +0530153 try
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500154 {
Andrew Jefferyad343102018-02-28 00:35:50 +1030155 vpnor::Request req(context, offset);
156 rc = req.read(mem, size);
Ratan Gupta8441a392017-05-05 21:42:53 +0530157 }
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030158 catch (vpnor::UnmappedOffset& e)
Ratan Gupta8441a392017-05-05 21:42:53 +0530159 {
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030160 /*
161 * Hooo boy. Pretend that this is valid flash so we don't have
162 * discontiguous regions presented to the host. Instead, fill a window
163 * with 0xff so the 'flash' looks erased. Writes to such regions are
Andrew Jeffery0293f2f2018-08-08 16:59:45 +0930164 * dropped on the floor, see the implementation of flash_write() below.
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030165 */
166 MSG_INFO("Host requested unmapped region of %" PRId32
167 " bytes at offset 0x%" PRIx32 "\n",
168 size, offset);
169 uint32_t span = e.next - e.base;
170 rc = std::min(size, span);
171 memset(mem, 0xff, rc);
172 }
173 catch (std::exception& e)
174 {
175 MSG_ERR("%s\n", e.what());
176 phosphor::logging::commit<err::InternalFailure>();
Andrew Jeffery8eab2152018-08-09 23:47:29 +0930177 rc = -EIO;
Ratan Gupta8441a392017-05-05 21:42:53 +0530178 }
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500179 return rc;
180}
Ratan Guptadc50ce52017-05-31 15:47:55 +0530181
182/*
Andrew Jeffery0293f2f2018-08-08 16:59:45 +0930183 * flash_write() - Write to the virtual pnor from a provided buffer
Ratan Guptadc50ce52017-05-31 15:47:55 +0530184 * @context: The mbox context pointer
185 * @offset: The flash offset to write to (bytes)
186 * @buf: The buffer to write from (must be of atleast size)
187 * @size: The number of bytes to write
188 *
189 * Return: 0 on success otherwise negative error code
190 */
191
Andrew Jeffery0293f2f2018-08-08 16:59:45 +0930192int flash_write(struct mbox_context* context, uint32_t offset, void* buf,
Ratan Guptadc50ce52017-05-31 15:47:55 +0530193 uint32_t count)
194{
Ratan Guptadc50ce52017-05-31 15:47:55 +0530195
Andrew Jefferyad343102018-02-28 00:35:50 +1030196 if (!(context && context->vpnor && context->vpnor->table))
197 {
198 MSG_ERR("Trying to write data with uninitialised context!\n");
Andrew Jeffery8eab2152018-08-09 23:47:29 +0930199 return -EINVAL;
Andrew Jefferyad343102018-02-28 00:35:50 +1030200 }
201
202 vpnor::partition::Table* table = context->vpnor->table;
203
Ratan Guptadc50ce52017-05-31 15:47:55 +0530204 try
205 {
Andrew Jefferyad343102018-02-28 00:35:50 +1030206 const struct pnor_partition& part = table->partition(offset);
207 if (part.data.user.data[1] & PARTITION_READONLY)
Ratan Guptadc50ce52017-05-31 15:47:55 +0530208 {
Andrew Jeffery52a83192018-03-27 10:35:31 +1030209 MSG_ERR("Unreachable: Host attempted to write to read-only "
210 "partition %s\n",
211 part.data.name);
Andrew Jeffery8eab2152018-08-09 23:47:29 +0930212 return -EPERM;
Ratan Guptadc50ce52017-05-31 15:47:55 +0530213 }
214
Andrew Jefferyad343102018-02-28 00:35:50 +1030215 MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count,
216 buf);
217 vpnor::Request req(context, offset);
218 req.write(buf, count);
Ratan Guptadc50ce52017-05-31 15:47:55 +0530219 }
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030220 catch (vpnor::UnmappedOffset& e)
Ratan Guptadc50ce52017-05-31 15:47:55 +0530221 {
Andrew Jeffery52a83192018-03-27 10:35:31 +1030222 MSG_ERR("Unreachable: Host attempted to write %" PRIu32
223 " bytes to unmapped offset 0x%" PRIx32 "\n",
224 count, offset);
Andrew Jeffery8eab2152018-08-09 23:47:29 +0930225 return -EACCES;
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030226 }
227 catch (const vpnor::OutOfBoundsOffset& e)
228 {
229 MSG_ERR("%s\n", e.what());
Andrew Jeffery8eab2152018-08-09 23:47:29 +0930230 return -EINVAL;
Andrew Jefferyae1edb92018-02-28 23:16:48 +1030231 }
232 catch (const std::exception& e)
233 {
234 MSG_ERR("%s\n", e.what());
235 phosphor::logging::commit<err::InternalFailure>();
Andrew Jeffery8eab2152018-08-09 23:47:29 +0930236 return -EIO;
Ratan Guptadc50ce52017-05-31 15:47:55 +0530237 }
Andrew Jefferyad343102018-02-28 00:35:50 +1030238 return 0;
Ratan Guptadc50ce52017-05-31 15:47:55 +0530239}