blob: 6e3af71b100473dc28e2932182ecc543dd5bc0fd [file] [log] [blame]
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -05001/*
2 * Mailbox Daemon Window Helpers
3 *
4 * Copyright 2017 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 */
19
Ratan Gupta8441a392017-05-05 21:42:53 +053020#include <fcntl.h>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050021#include <stdint.h>
22#include <stdlib.h>
23#include <syslog.h>
Ratan Gupta8441a392017-05-05 21:42:53 +053024#include <sys/mman.h>
25#include <unistd.h>
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050026#include <sys/ioctl.h>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050027
28extern "C" {
29#include "common.h"
30}
31
Ratan Gupta8441a392017-05-05 21:42:53 +053032#include "config.h"
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050033#include "mboxd_flash.h"
34#include "mboxd_pnor_partition_table.h"
Ratan Gupta6a98e182017-06-06 15:04:23 +053035#include "pnor_partition.hpp"
36#include "xyz/openbmc_project/Common/error.hpp"
37#include <phosphor-logging/log.hpp>
38#include <phosphor-logging/elog-errors.hpp>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050039
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050040#include <memory>
Ratan Gupta8441a392017-05-05 21:42:53 +053041#include <string>
42#include <exception>
43#include <stdexcept>
Ratan Gupta8441a392017-05-05 21:42:53 +053044
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050045/** @brief unique_ptr functor to release a char* reference. */
46struct StringDeleter
47{
48 void operator()(char* ptr) const
49 {
50 free(ptr);
51 }
52};
53using StringPtr = std::unique_ptr<char, StringDeleter>;
54
55int init_flash_dev(struct mbox_context *context)
56{
57 StringPtr filename(get_dev_mtd());
58 int fd = 0;
59 int rc = 0;
60
61 if (!filename)
62 {
63 MSG_ERR("Couldn't find the flash /dev/mtd partition\n");
64 return -1;
65 }
66
67 MSG_DBG("Opening %s\n", filename.get());
68
69 fd = open(filename.get(), O_RDWR);
70 if (fd < 0)
71 {
72 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
73 filename.get(), strerror(errno));
74 return -errno;
75 }
76
77 // Read the Flash Info
78 if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1)
79 {
80 MSG_ERR("Couldn't get information about MTD: %s\n",
81 strerror(errno));
82 close(fd);
83 return -errno;
84 }
85
86 if (context->flash_size == 0)
87 {
88 // See comment in mboxd_flash_physical.c on why
89 // this is needed.
90 context->flash_size = context->mtd_info.size;
91 }
92
93 // Hostboot requires a 4K block-size to be used in the FFS flash structure
94 context->mtd_info.erasesize = 4096;
95 context->erase_size_shift = log_2(context->mtd_info.erasesize);
96 context->flash_bmap = NULL;
97 context->fds[MTD_FD].fd = -1;
98
99 close(fd);
100 return rc;
101}
102
103void free_flash_dev(struct mbox_context *context)
104{
105 // No-op
106}
107
108int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
109 uint32_t count, uint8_t val)
110{
111 // No-op
112 return 0;
113}
114
115int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
116{
117 // No-op
118 return 0;
119}
120
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500121/*
122 * copy_flash() - Copy data from the virtual pnor into a provided buffer
123 * @context: The mbox context pointer
124 * @offset: The pnor offset to copy from (bytes)
125 * @mem: The buffer to copy into (must be of atleast 'size' bytes)
126 * @size: The number of bytes to copy
127 *
128 * Return: 0 on success otherwise negative error code
129 */
130int copy_flash(struct mbox_context* context, uint32_t offset, void* mem,
131 uint32_t size)
132{
Ratan Gupta6a98e182017-06-06 15:04:23 +0530133 using namespace phosphor::logging;
134 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
135 using namespace std::string_literals;
136
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500137 int rc = 0;
138
139 MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n",
140 mem, size, offset);
141
142 /* The virtual PNOR partition table starts at offset 0 in the virtual
143 * pnor image. Check if host asked for an offset that lies within the
144 * partition table.
145 */
Ratan Gupta8441a392017-05-05 21:42:53 +0530146 try
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500147 {
Ratan Gupta8441a392017-05-05 21:42:53 +0530148 size_t sz =
149 vpnor_get_partition_table_size(context) << context->block_size_shift;
150 if (offset < sz)
151 {
152 const struct pnor_partition_table* table =
153 vpnor_get_partition_table(context);
154 memcpy(mem,
155 ((uint8_t*)table) + offset,
156 min_u32(sz - offset, size));
157 }
158 else
159 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530160 openpower::virtual_pnor::RORequest roRequest;
161 auto partitionInfo = roRequest.getPartitionInfo(context, offset);
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500162
Ratan Gupta6a98e182017-06-06 15:04:23 +0530163 auto mapped_mem = mmap(NULL, partitionInfo->data.actual,
164 PROT_READ, MAP_PRIVATE, roRequest.fd(), 0);
Ratan Gupta8441a392017-05-05 21:42:53 +0530165
Ratan Gupta8441a392017-05-05 21:42:53 +0530166 if (mem == MAP_FAILED)
167 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530168 MSG_ERR("Failed to map partition=%s:Error=%s\n",
169 partitionInfo->data.name, strerror(errno));
170
171 elog<InternalFailure>();
172 }
173
174 // if the asked offset + no of bytes to read is greater
175 // then size of the partition file then throw error.
176
177 uint32_t baseOffset = partitionInfo->data.base << context->block_size_shift;
178
179 if ((offset + size) > (baseOffset + partitionInfo->data.actual))
180 {
181 MSG_ERR("Offset is beyond the partition file length[0x%.8x]\n",
182 partitionInfo->data.actual);
183 munmap(mapped_mem, partitionInfo->data.actual);
184 elog<InternalFailure>();
Ratan Gupta8441a392017-05-05 21:42:53 +0530185 }
186
187 //copy to the reserved memory area
Ratan Gupta6a98e182017-06-06 15:04:23 +0530188 auto diffOffset = offset - baseOffset;
189 memcpy(mem, (char*)mapped_mem + diffOffset , size);
190 munmap(mapped_mem, partitionInfo->data.actual);
Ratan Gupta8441a392017-05-05 21:42:53 +0530191 }
192 }
Ratan Gupta6a98e182017-06-06 15:04:23 +0530193 catch (InternalFailure& e)
Ratan Gupta8441a392017-05-05 21:42:53 +0530194 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530195 commit<InternalFailure>();
Ratan Gupta8441a392017-05-05 21:42:53 +0530196 rc = -1;
197 }
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500198 return rc;
199}
Ratan Guptadc50ce52017-05-31 15:47:55 +0530200
201/*
202 * write_flash() - Write to the virtual pnor from a provided buffer
203 * @context: The mbox context pointer
204 * @offset: The flash offset to write to (bytes)
205 * @buf: The buffer to write from (must be of atleast size)
206 * @size: The number of bytes to write
207 *
208 * Return: 0 on success otherwise negative error code
209 */
210
211int write_flash(struct mbox_context* context, uint32_t offset, void* buf,
212 uint32_t count)
213{
214 using namespace phosphor::logging;
215 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
216 using namespace std::string_literals;
217
218 int rc = 0;
219 MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count, buf);
220 try
221 {
222 openpower::virtual_pnor::RWRequest rwRequest;
223 auto partitionInfo = rwRequest.getPartitionInfo(context, offset);
224
225
226 auto mapped_mem = mmap(NULL, partitionInfo->data.actual,
227 PROT_READ | PROT_WRITE,
228 MAP_SHARED, rwRequest.fd(), 0);
229 if (mapped_mem == MAP_FAILED)
230 {
231 MSG_ERR("Failed to map partition=%s:Error=%s\n",
232 partitionInfo->data.name, strerror(errno));
233
234 elog<InternalFailure>();
235 }
236 //copy to the mapped memory.
237
238 uint32_t baseOffset = partitionInfo->data.base << context->block_size_shift;
239
240 // if the asked offset + no of bytes to write is greater
241 // then size of the partition file then throw error.
242 if ((offset + count) > (baseOffset + partitionInfo->data.actual))
243 {
244 MSG_ERR("Offset is beyond the partition file length[0x%.8x]\n",
245 partitionInfo->data.actual);
246 munmap(mapped_mem, partitionInfo->data.actual);
247 elog<InternalFailure>();
248 }
249
250 auto diffOffset = offset - baseOffset;
251 memcpy((char*)mapped_mem + diffOffset , buf, count);
252 munmap(mapped_mem, partitionInfo->data.actual);
253
254 set_flash_bytemap(context, offset, count, FLASH_DIRTY);
255 }
256 catch (InternalFailure & e)
257 {
258 rc = -1;
259 }
260 return rc;
261}