blob: 442593b701672889bebb0e1c6181f572c996b7f3 [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 Kodihalli7ee307c2017-07-12 03:41:08 -050027#include <algorithm>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050028
29extern "C" {
30#include "common.h"
31}
32
Ratan Gupta8441a392017-05-05 21:42:53 +053033#include "config.h"
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050034#include "mboxd_flash.h"
35#include "mboxd_pnor_partition_table.h"
Ratan Gupta6a98e182017-06-06 15:04:23 +053036#include "pnor_partition.hpp"
37#include "xyz/openbmc_project/Common/error.hpp"
38#include <phosphor-logging/log.hpp>
39#include <phosphor-logging/elog-errors.hpp>
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050040
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050041#include <memory>
Ratan Gupta8441a392017-05-05 21:42:53 +053042#include <string>
43#include <exception>
44#include <stdexcept>
Ratan Gupta8441a392017-05-05 21:42:53 +053045
Deepak Kodihalliabd52a72017-07-13 12:04:06 -050046/** @brief unique_ptr functor to release a char* reference. */
47struct StringDeleter
48{
49 void operator()(char* ptr) const
50 {
51 free(ptr);
52 }
53};
54using StringPtr = std::unique_ptr<char, StringDeleter>;
55
56int init_flash_dev(struct mbox_context *context)
57{
58 StringPtr filename(get_dev_mtd());
59 int fd = 0;
60 int rc = 0;
61
62 if (!filename)
63 {
64 MSG_ERR("Couldn't find the flash /dev/mtd partition\n");
65 return -1;
66 }
67
68 MSG_DBG("Opening %s\n", filename.get());
69
70 fd = open(filename.get(), O_RDWR);
71 if (fd < 0)
72 {
73 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
74 filename.get(), strerror(errno));
75 return -errno;
76 }
77
78 // Read the Flash Info
79 if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1)
80 {
81 MSG_ERR("Couldn't get information about MTD: %s\n",
82 strerror(errno));
83 close(fd);
84 return -errno;
85 }
86
87 if (context->flash_size == 0)
88 {
89 // See comment in mboxd_flash_physical.c on why
90 // this is needed.
91 context->flash_size = context->mtd_info.size;
92 }
93
94 // Hostboot requires a 4K block-size to be used in the FFS flash structure
95 context->mtd_info.erasesize = 4096;
96 context->erase_size_shift = log_2(context->mtd_info.erasesize);
97 context->flash_bmap = NULL;
98 context->fds[MTD_FD].fd = -1;
99
100 close(fd);
101 return rc;
102}
103
104void free_flash_dev(struct mbox_context *context)
105{
106 // No-op
107}
108
109int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
110 uint32_t count, uint8_t val)
111{
112 // No-op
113 return 0;
114}
115
116int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
117{
118 // No-op
119 return 0;
120}
121
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500122/*
123 * copy_flash() - Copy data from the virtual pnor into a provided buffer
124 * @context: The mbox context pointer
125 * @offset: The pnor offset to copy from (bytes)
126 * @mem: The buffer to copy into (must be of atleast 'size' bytes)
127 * @size: The number of bytes to copy
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500128 * Return: Number of bytes copied on success, otherwise negative error
129 * code. copy_flash will copy at most 'size' bytes, but it may
130 * copy less.
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500131 */
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500132int64_t copy_flash(struct mbox_context* context, uint32_t offset, void* mem,
133 uint32_t size)
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500134{
Ratan Gupta6a98e182017-06-06 15:04:23 +0530135 using namespace phosphor::logging;
136 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
137 using namespace std::string_literals;
138
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500139 int rc = size;
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500140
141 MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n",
142 mem, size, offset);
143
144 /* The virtual PNOR partition table starts at offset 0 in the virtual
145 * pnor image. Check if host asked for an offset that lies within the
146 * partition table.
147 */
Ratan Gupta8441a392017-05-05 21:42:53 +0530148 try
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500149 {
Ratan Gupta8441a392017-05-05 21:42:53 +0530150 size_t sz =
151 vpnor_get_partition_table_size(context) << context->block_size_shift;
152 if (offset < sz)
153 {
154 const struct pnor_partition_table* table =
155 vpnor_get_partition_table(context);
Deepak Kodihalli7ee307c2017-07-12 03:41:08 -0500156 rc = std::min(sz - offset, static_cast<size_t>(size));
157 memcpy(mem, ((uint8_t*)table) + offset, rc);
Ratan Gupta8441a392017-05-05 21:42:53 +0530158 }
159 else
160 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530161 openpower::virtual_pnor::RORequest roRequest;
162 auto partitionInfo = roRequest.getPartitionInfo(context, offset);
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500163
Ratan Gupta6a98e182017-06-06 15:04:23 +0530164 auto mapped_mem = mmap(NULL, partitionInfo->data.actual,
165 PROT_READ, MAP_PRIVATE, roRequest.fd(), 0);
Ratan Gupta8441a392017-05-05 21:42:53 +0530166
Adriana Kobylak0a2cc952017-10-12 11:13:06 -0500167 if (mapped_mem == MAP_FAILED)
Ratan Gupta8441a392017-05-05 21:42:53 +0530168 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530169 MSG_ERR("Failed to map partition=%s:Error=%s\n",
170 partitionInfo->data.name, strerror(errno));
171
172 elog<InternalFailure>();
173 }
174
175 // if the asked offset + no of bytes to read is greater
176 // then size of the partition file then throw error.
177
178 uint32_t baseOffset = partitionInfo->data.base << context->block_size_shift;
Ratan Gupta8441a392017-05-05 21:42:53 +0530179 //copy to the reserved memory area
Ratan Gupta6a98e182017-06-06 15:04:23 +0530180 auto diffOffset = offset - baseOffset;
Deepak Kodihallib100fb82017-07-12 04:44:41 -0500181 rc = std::min(partitionInfo->data.actual - diffOffset, size);
182 memcpy(mem, (char*)mapped_mem + diffOffset , rc);
Ratan Gupta6a98e182017-06-06 15:04:23 +0530183 munmap(mapped_mem, partitionInfo->data.actual);
Ratan Gupta8441a392017-05-05 21:42:53 +0530184 }
185 }
Ratan Gupta6a98e182017-06-06 15:04:23 +0530186 catch (InternalFailure& e)
Ratan Gupta8441a392017-05-05 21:42:53 +0530187 {
Ratan Gupta6a98e182017-06-06 15:04:23 +0530188 commit<InternalFailure>();
Deepak Kodihallif9abed02017-07-17 06:23:08 -0500189 rc = -MBOX_R_SYSTEM_ERROR;
Ratan Gupta8441a392017-05-05 21:42:53 +0530190 }
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500191 return rc;
192}
Ratan Guptadc50ce52017-05-31 15:47:55 +0530193
194/*
195 * write_flash() - Write to the virtual pnor from a provided buffer
196 * @context: The mbox context pointer
197 * @offset: The flash offset to write to (bytes)
198 * @buf: The buffer to write from (must be of atleast size)
199 * @size: The number of bytes to write
200 *
201 * Return: 0 on success otherwise negative error code
202 */
203
204int write_flash(struct mbox_context* context, uint32_t offset, void* buf,
205 uint32_t count)
206{
207 using namespace phosphor::logging;
208 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
209 using namespace std::string_literals;
210
211 int rc = 0;
212 MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count, buf);
213 try
214 {
215 openpower::virtual_pnor::RWRequest rwRequest;
216 auto partitionInfo = rwRequest.getPartitionInfo(context, offset);
217
218
219 auto mapped_mem = mmap(NULL, partitionInfo->data.actual,
220 PROT_READ | PROT_WRITE,
221 MAP_SHARED, rwRequest.fd(), 0);
222 if (mapped_mem == MAP_FAILED)
223 {
224 MSG_ERR("Failed to map partition=%s:Error=%s\n",
225 partitionInfo->data.name, strerror(errno));
226
227 elog<InternalFailure>();
228 }
229 //copy to the mapped memory.
230
231 uint32_t baseOffset = partitionInfo->data.base << context->block_size_shift;
232
233 // if the asked offset + no of bytes to write is greater
234 // then size of the partition file then throw error.
235 if ((offset + count) > (baseOffset + partitionInfo->data.actual))
236 {
237 MSG_ERR("Offset is beyond the partition file length[0x%.8x]\n",
238 partitionInfo->data.actual);
239 munmap(mapped_mem, partitionInfo->data.actual);
240 elog<InternalFailure>();
241 }
242
243 auto diffOffset = offset - baseOffset;
244 memcpy((char*)mapped_mem + diffOffset , buf, count);
245 munmap(mapped_mem, partitionInfo->data.actual);
246
247 set_flash_bytemap(context, offset, count, FLASH_DIRTY);
248 }
249 catch (InternalFailure & e)
250 {
251 rc = -1;
252 }
253 return rc;
254}