blob: 1b94ca95b5963de97a689852c1d45ba04002c2f1 [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>
7#include <syslog.h>
Ratan Gupta8441a392017-05-05 21:42:53 +05308#include <sys/mman.h>
9#include <unistd.h>
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050010#include <sys/ioctl.h>
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -050011#include <algorithm>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050012
13extern "C" {
14#include "common.h"
15}
16
Ratan Gupta8441a392017-05-05 21:42:53 +053017#include "config.h"
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050018#include "mboxd_flash.h"
19#include "mboxd_pnor_partition_table.h"
Ratan Gupta6a98e182017-06-06 15:04:23 +053020#include "pnor_partition.hpp"
21#include "xyz/openbmc_project/Common/error.hpp"
22#include <phosphor-logging/log.hpp>
23#include <phosphor-logging/elog-errors.hpp>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050024
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050025#include <memory>
Ratan Gupta8441a392017-05-05 21:42:53 +053026#include <string>
27#include <exception>
28#include <stdexcept>
Ratan Gupta8441a392017-05-05 21:42:53 +053029
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050030/** @brief unique_ptr functor to release a char* reference. */
31struct StringDeleter
32{
33 void operator()(char* ptr) const
34 {
35 free(ptr);
36 }
37};
38using StringPtr = std::unique_ptr<char, StringDeleter>;
39
Andrew Jefferyf34db312018-03-09 15:27:03 +103040int init_flash_dev(struct mbox_context* context)
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050041{
42 StringPtr filename(get_dev_mtd());
43 int fd = 0;
44 int rc = 0;
45
46 if (!filename)
47 {
48 MSG_ERR("Couldn't find the flash /dev/mtd partition\n");
49 return -1;
50 }
51
52 MSG_DBG("Opening %s\n", filename.get());
53
54 fd = open(filename.get(), O_RDWR);
55 if (fd < 0)
56 {
Andrew Jefferyf34db312018-03-09 15:27:03 +103057 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", filename.get(),
58 strerror(errno));
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050059 return -errno;
60 }
61
62 // Read the Flash Info
63 if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1)
64 {
Andrew Jefferyf34db312018-03-09 15:27:03 +103065 MSG_ERR("Couldn't get information about MTD: %s\n", strerror(errno));
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050066 close(fd);
67 return -errno;
68 }
69
70 if (context->flash_size == 0)
71 {
72 // See comment in mboxd_flash_physical.c on why
73 // this is needed.
74 context->flash_size = context->mtd_info.size;
75 }
76
77 // Hostboot requires a 4K block-size to be used in the FFS flash structure
78 context->mtd_info.erasesize = 4096;
79 context->erase_size_shift = log_2(context->mtd_info.erasesize);
80 context->flash_bmap = NULL;
81 context->fds[MTD_FD].fd = -1;
82
83 close(fd);
84 return rc;
85}
86
Andrew Jefferyf34db312018-03-09 15:27:03 +103087void free_flash_dev(struct mbox_context* context)
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050088{
89 // No-op
90}
91
Andrew Jefferyf34db312018-03-09 15:27:03 +103092int set_flash_bytemap(struct mbox_context* context, uint32_t offset,
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050093 uint32_t count, uint8_t val)
94{
95 // No-op
96 return 0;
97}
98
Andrew Jefferyf34db312018-03-09 15:27:03 +103099int erase_flash(struct mbox_context* context, uint32_t offset, uint32_t count)
Deepak Kodihalliabd52a72017-07-13 12:04:06 -0500100{
101 // No-op
102 return 0;
103}
104
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500105/*
106 * copy_flash() - Copy data from the virtual pnor into a provided buffer
107 * @context: The mbox context pointer
108 * @offset: The pnor offset to copy from (bytes)
109 * @mem: The buffer to copy into (must be of atleast 'size' bytes)
110 * @size: The number of bytes to copy
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500111 * Return: Number of bytes copied on success, otherwise negative error
112 * code. copy_flash will copy at most 'size' bytes, but it may
113 * copy less.
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500114 */
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500115int64_t copy_flash(struct mbox_context* context, uint32_t offset, void* mem,
116 uint32_t size)
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500117{
Ratan Gupta6a98e182017-06-06 15:04:23 +0530118 using namespace phosphor::logging;
119 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
120 using namespace std::string_literals;
121
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500122 int rc = size;
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500123
Andrew Jefferyf34db312018-03-09 15:27:03 +1030124 MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n", mem,
125 size, offset);
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500126
127 /* The virtual PNOR partition table starts at offset 0 in the virtual
128 * pnor image. Check if host asked for an offset that lies within the
129 * partition table.
130 */
Ratan Gupta8441a392017-05-05 21:42:53 +0530131 try
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500132 {
Andrew Jefferyf34db312018-03-09 15:27:03 +1030133 size_t sz = vpnor_get_partition_table_size(context)
134 << context->block_size_shift;
Ratan Gupta8441a392017-05-05 21:42:53 +0530135 if (offset < sz)
136 {
137 const struct pnor_partition_table* table =
138 vpnor_get_partition_table(context);
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500139 rc = std::min(sz - offset, static_cast<size_t>(size));
140 memcpy(mem, ((uint8_t*)table) + offset, rc);
Ratan Gupta8441a392017-05-05 21:42:53 +0530141 }
142 else
143 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530144 openpower::virtual_pnor::RORequest roRequest;
145 auto partitionInfo = roRequest.getPartitionInfo(context, offset);
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500146
Andrew Jefferyf34db312018-03-09 15:27:03 +1030147 auto mapped_mem = mmap(NULL, partitionInfo->data.actual, PROT_READ,
148 MAP_PRIVATE, roRequest.fd(), 0);
Ratan Gupta8441a392017-05-05 21:42:53 +0530149
Adriana Kobylak0a2cc952017-10-12 11:13:06 -0500150 if (mapped_mem == MAP_FAILED)
Ratan Gupta8441a392017-05-05 21:42:53 +0530151 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530152 MSG_ERR("Failed to map partition=%s:Error=%s\n",
153 partitionInfo->data.name, strerror(errno));
154
155 elog<InternalFailure>();
156 }
157
158 // if the asked offset + no of bytes to read is greater
159 // then size of the partition file then throw error.
160
Andrew Jefferyf34db312018-03-09 15:27:03 +1030161 uint32_t baseOffset = partitionInfo->data.base
162 << context->block_size_shift;
163 // copy to the reserved memory area
Ratan Gupta6a98e182017-06-06 15:04:23 +0530164 auto diffOffset = offset - baseOffset;
Deepak Kodihallib100fb82017-07-12 04:44:41 -0500165 rc = std::min(partitionInfo->data.actual - diffOffset, size);
Andrew Jefferyf34db312018-03-09 15:27:03 +1030166 memcpy(mem, (char*)mapped_mem + diffOffset, rc);
Ratan Gupta6a98e182017-06-06 15:04:23 +0530167 munmap(mapped_mem, partitionInfo->data.actual);
Ratan Gupta8441a392017-05-05 21:42:53 +0530168 }
169 }
Ratan Gupta6a98e182017-06-06 15:04:23 +0530170 catch (InternalFailure& e)
Ratan Gupta8441a392017-05-05 21:42:53 +0530171 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530172 commit<InternalFailure>();
Deepak Kodihallif9abed02017-07-17 06:23:08 -0500173 rc = -MBOX_R_SYSTEM_ERROR;
Ratan Gupta8441a392017-05-05 21:42:53 +0530174 }
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500175 return rc;
176}
Ratan Guptadc50ce52017-05-31 15:47:55 +0530177
178/*
179 * write_flash() - Write to the virtual pnor from a provided buffer
180 * @context: The mbox context pointer
181 * @offset: The flash offset to write to (bytes)
182 * @buf: The buffer to write from (must be of atleast size)
183 * @size: The number of bytes to write
184 *
185 * Return: 0 on success otherwise negative error code
186 */
187
188int write_flash(struct mbox_context* context, uint32_t offset, void* buf,
189 uint32_t count)
190{
191 using namespace phosphor::logging;
192 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
193 using namespace std::string_literals;
194
195 int rc = 0;
196 MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count, buf);
197 try
198 {
199 openpower::virtual_pnor::RWRequest rwRequest;
200 auto partitionInfo = rwRequest.getPartitionInfo(context, offset);
201
Andrew Jefferyf34db312018-03-09 15:27:03 +1030202 auto mapped_mem =
203 mmap(NULL, partitionInfo->data.actual, PROT_READ | PROT_WRITE,
204 MAP_SHARED, rwRequest.fd(), 0);
Ratan Guptadc50ce52017-05-31 15:47:55 +0530205 if (mapped_mem == MAP_FAILED)
206 {
207 MSG_ERR("Failed to map partition=%s:Error=%s\n",
208 partitionInfo->data.name, strerror(errno));
209
210 elog<InternalFailure>();
211 }
Andrew Jefferyf34db312018-03-09 15:27:03 +1030212 // copy to the mapped memory.
Ratan Guptadc50ce52017-05-31 15:47:55 +0530213
Andrew Jefferyf34db312018-03-09 15:27:03 +1030214 uint32_t baseOffset = partitionInfo->data.base
215 << context->block_size_shift;
Ratan Guptadc50ce52017-05-31 15:47:55 +0530216
217 // if the asked offset + no of bytes to write is greater
218 // then size of the partition file then throw error.
219 if ((offset + count) > (baseOffset + partitionInfo->data.actual))
220 {
221 MSG_ERR("Offset is beyond the partition file length[0x%.8x]\n",
Andrew Jefferyf34db312018-03-09 15:27:03 +1030222 partitionInfo->data.actual);
Ratan Guptadc50ce52017-05-31 15:47:55 +0530223 munmap(mapped_mem, partitionInfo->data.actual);
224 elog<InternalFailure>();
225 }
226
227 auto diffOffset = offset - baseOffset;
Andrew Jefferyf34db312018-03-09 15:27:03 +1030228 memcpy((char*)mapped_mem + diffOffset, buf, count);
Ratan Guptadc50ce52017-05-31 15:47:55 +0530229 munmap(mapped_mem, partitionInfo->data.actual);
230
231 set_flash_bytemap(context, offset, count, FLASH_DIRTY);
232 }
Andrew Jefferyf34db312018-03-09 15:27:03 +1030233 catch (InternalFailure& e)
Ratan Guptadc50ce52017-05-31 15:47:55 +0530234 {
235 rc = -1;
236 }
237 return rc;
238}