blob: 459538785891cd6f8ce17a19142ba561fa841a8c [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
Andrew Jeffery71eaa732018-08-08 16:44:24 +09303extern "C" {
Evan Lojewskif1e547c2019-03-14 14:34:33 +10304#include "mboxd.h"
Andrew Jeffery71eaa732018-08-08 16:44:24 +09305}
6
William A. Kennington IIId5f1d402018-10-11 13:55:04 -07007#include "config.h"
8
Andrew Jefferyfb01e142019-03-18 13:17:08 +10309#include "vpnor/partition.hpp"
Andrew Jefferyde08ca22019-03-18 13:23:46 +103010#include "vpnor/table.hpp"
Ratan Guptac0ef9872017-06-06 14:31:37 +053011#include "xyz/openbmc_project/Common/error.hpp"
Ratan Guptac0ef9872017-06-06 14:31:37 +053012
Andrew Jefferyad343102018-02-28 00:35:50 +103013#include <assert.h>
Andrew Jeffery1a3f8432018-03-02 10:18:02 +103014#include <fcntl.h>
Ratan Guptac0ef9872017-06-06 14:31:37 +053015#include <stdint.h>
16#include <stdlib.h>
Ratan Guptac0ef9872017-06-06 14:31:37 +053017#include <sys/ioctl.h>
18#include <sys/mman.h>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070019#include <sys/types.h>
20#include <syslog.h>
Andrew Jeffery1a3f8432018-03-02 10:18:02 +103021#include <unistd.h>
Ratan Guptac0ef9872017-06-06 14:31:37 +053022
Ratan Guptac0ef9872017-06-06 14:31:37 +053023#include <exception>
Ratan Guptac0ef9872017-06-06 14:31:37 +053024#include <iostream>
William A. Kennington IIId5f1d402018-10-11 13:55:04 -070025#include <phosphor-logging/elog-errors.hpp>
26#include <phosphor-logging/log.hpp>
27#include <stdexcept>
28#include <string>
29
30#include "common.h"
Andrew Jefferyf4bc3352019-03-18 12:09:48 +103031#include "vpnor/backend.h"
Ratan Guptac0ef9872017-06-06 14:31:37 +053032
33namespace openpower
34{
35namespace virtual_pnor
36{
37
Andrew Jefferyad343102018-02-28 00:35:50 +103038namespace fs = std::experimental::filesystem;
Ratan Guptac0ef9872017-06-06 14:31:37 +053039
Andrew Jefferyad343102018-02-28 00:35:50 +103040fs::path Request::getPartitionFilePath(int flags)
Ratan Guptac0ef9872017-06-06 14:31:37 +053041{
Evan Lojewskif1e547c2019-03-14 14:34:33 +103042 struct vpnor_data* priv = (struct vpnor_data*)backend->priv;
43
Adriana Kobylakc71dfd72017-07-22 11:10:43 -050044 // Check if partition exists in patch location
Evan Lojewskif1e547c2019-03-14 14:34:33 +103045 auto dst = fs::path(priv->paths.patch_loc) / partition.data.name;
Andrew Jefferyad343102018-02-28 00:35:50 +103046 if (fs::is_regular_file(dst))
Adriana Kobylakc71dfd72017-07-22 11:10:43 -050047 {
Andrew Jefferyad343102018-02-28 00:35:50 +103048 return dst;
Adriana Kobylakc71dfd72017-07-22 11:10:43 -050049 }
50
Adriana Kobylak5ff50e32020-11-30 16:25:36 -060051 // Check if partition exists in rw location (default)
52 dst = fs::path(priv->paths.rw_loc) / partition.data.name;
53 if (fs::exists(dst))
54 {
55 return dst;
56 }
57
Andrew Jefferyad343102018-02-28 00:35:50 +103058 switch (partition.data.user.data[1] &
Ratan Guptac0ef9872017-06-06 14:31:37 +053059 (PARTITION_PRESERVED | PARTITION_READONLY))
60 {
61 case PARTITION_PRESERVED:
Evan Lojewskif1e547c2019-03-14 14:34:33 +103062 dst = priv->paths.prsv_loc;
Ratan Guptac0ef9872017-06-06 14:31:37 +053063 break;
64
65 case PARTITION_READONLY:
Evan Lojewskif1e547c2019-03-14 14:34:33 +103066 dst = priv->paths.ro_loc;
Ratan Guptac0ef9872017-06-06 14:31:37 +053067 break;
68
69 default:
Evan Lojewskif1e547c2019-03-14 14:34:33 +103070 dst = priv->paths.rw_loc;
Ratan Guptac0ef9872017-06-06 14:31:37 +053071 }
Andrew Jefferyad343102018-02-28 00:35:50 +103072 dst /= partition.data.name;
Ratan Guptac0ef9872017-06-06 14:31:37 +053073
Andrew Jefferyad343102018-02-28 00:35:50 +103074 if (fs::exists(dst))
Ratan Guptac0ef9872017-06-06 14:31:37 +053075 {
Andrew Jefferyad343102018-02-28 00:35:50 +103076 return dst;
Ratan Guptac0ef9872017-06-06 14:31:37 +053077 }
Andrew Jefferyad343102018-02-28 00:35:50 +103078
79 if (flags == O_RDONLY)
Ratan Guptac0ef9872017-06-06 14:31:37 +053080 {
Evan Lojewskif1e547c2019-03-14 14:34:33 +103081 dst = fs::path(priv->paths.ro_loc) / partition.data.name;
Andrew Jefferyad343102018-02-28 00:35:50 +103082 assert(fs::exists(dst));
83 return dst;
Ratan Guptac0ef9872017-06-06 14:31:37 +053084 }
85
Andrew Jefferyad343102018-02-28 00:35:50 +103086 assert(flags == O_RDWR);
Evan Lojewskif1e547c2019-03-14 14:34:33 +103087 auto src = fs::path(priv->paths.ro_loc) / partition.data.name;
Andrew Jefferyad343102018-02-28 00:35:50 +103088 assert(fs::exists(src));
Ratan Guptac0ef9872017-06-06 14:31:37 +053089
Andrew Jefferye8a79ff2018-02-27 10:56:32 +103090 MSG_DBG("RWRequest: Didn't find '%s' under '%s', copying from '%s'\n",
Andrew Jefferyad343102018-02-28 00:35:50 +103091 partition.data.name, dst.c_str(), src.c_str());
Andrew Jefferye8a79ff2018-02-27 10:56:32 +103092
Evan Lojewskif1e547c2019-03-14 14:34:33 +103093 dst = priv->paths.rw_loc;
Andrew Jefferyad343102018-02-28 00:35:50 +103094 if (partition.data.user.data[1] & PARTITION_PRESERVED)
Ratan Guptac0ef9872017-06-06 14:31:37 +053095 {
Evan Lojewskif1e547c2019-03-14 14:34:33 +103096 dst = priv->paths.prsv_loc;
Ratan Guptac0ef9872017-06-06 14:31:37 +053097 }
98
Andrew Jefferyad343102018-02-28 00:35:50 +103099 dst /= partition.data.name;
100 fs::copy_file(src, dst);
Adriana Kobylak0acc6692019-10-09 13:05:34 -0500101 fs::permissions(dst, fs::perms::add_perms | fs::perms::owner_write);
Ratan Guptac0ef9872017-06-06 14:31:37 +0530102
Andrew Jefferyad343102018-02-28 00:35:50 +1030103 return dst;
104}
105
Andrew Jeffery1a3f8432018-03-02 10:18:02 +1030106size_t Request::clamp(size_t len)
107{
108 size_t maxAccess = offset + len;
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030109 size_t partSize = partition.data.size << backend->block_size_shift;
Andrew Jeffery1a3f8432018-03-02 10:18:02 +1030110 return std::min(maxAccess, partSize) - offset;
111}
112
Andrew Jefferye2744c02020-01-28 15:08:13 +1030113/* Perform reads and writes for an entire buffer's worth of data
114 *
115 * Post-condition: All bytes read or written, or an error has occurred
116 *
117 * Yields 0 if the entire buffer was processed, otherwise -1
118 */
119#define fd_process_all(fn, fd, src, len) \
120 ({ \
121 size_t __len = len; \
122 ssize_t __accessed = 0; \
123 do \
124 { \
125 __len -= __accessed; \
126 __accessed = TEMP_FAILURE_RETRY(fn(fd, src, __len)); \
127 } while (__len > 0 && __accessed > 0); \
128 __len ? -1 : 0; \
129 })
130
131ssize_t Request::read(void* dst, size_t len)
Andrew Jeffery1a3f8432018-03-02 10:18:02 +1030132{
Andrew Jefferye2744c02020-01-28 15:08:13 +1030133 len = clamp(len);
134
135 fs::path path = getPartitionFilePath(O_RDONLY);
136
137 MSG_INFO("Fulfilling read request against %s at offset 0x%zx into %p "
138 "for %zu\n",
139 path.c_str(), offset, dst, len);
140
Andrew Jeffery1a3f8432018-03-02 10:18:02 +1030141 size_t fileSize = fs::file_size(path);
Andrew Jeffery1a3f8432018-03-02 10:18:02 +1030142
Andrew Jeffery5b970442020-01-31 16:49:22 +1030143 size_t access_len = 0;
144 if (offset < fileSize)
Andrew Jefferyad343102018-02-28 00:35:50 +1030145 {
Andrew Jeffery5b970442020-01-31 16:49:22 +1030146 int fd = ::open(path.c_str(), O_RDONLY);
147 if (fd == -1)
148 {
149 MSG_ERR("Failed to open backing file at '%s': %d\n", path.c_str(),
150 errno);
151 throw std::system_error(errno, std::system_category());
152 }
Andrew Jefferyad343102018-02-28 00:35:50 +1030153
Andrew Jeffery5b970442020-01-31 16:49:22 +1030154 int rc = lseek(fd, offset, SEEK_SET);
155 if (rc < 0)
156 {
Andrew Jeffery02821c62020-01-31 16:56:03 +1030157 int lerrno = errno;
158 close(fd);
Andrew Jeffery5b970442020-01-31 16:49:22 +1030159 MSG_ERR("Failed to seek to %zu in %s (%zu bytes): %d\n", offset,
Andrew Jeffery02821c62020-01-31 16:56:03 +1030160 path.c_str(), fileSize, lerrno);
161 throw std::system_error(lerrno, std::system_category());
Andrew Jeffery5b970442020-01-31 16:49:22 +1030162 }
Andrew Jefferyad343102018-02-28 00:35:50 +1030163
Andrew Jeffery5b970442020-01-31 16:49:22 +1030164 access_len = std::min(len, fileSize - offset);
165 rc = fd_process_all(::read, fd, dst, access_len);
166 if (rc < 0)
167 {
Andrew Jeffery02821c62020-01-31 16:56:03 +1030168 int lerrno = errno;
169 close(fd);
Andrew Jeffery5b970442020-01-31 16:49:22 +1030170 MSG_ERR(
171 "Requested %zu bytes but failed to read %zu from %s (%zu) at "
Andrew Jefferye2744c02020-01-28 15:08:13 +1030172 "%zu: %d\n",
Andrew Jeffery02821c62020-01-31 16:56:03 +1030173 len, access_len, path.c_str(), fileSize, offset, lerrno);
174 throw std::system_error(lerrno, std::system_category());
Andrew Jeffery5b970442020-01-31 16:49:22 +1030175 }
176
177 close(fd);
Andrew Jefferyad343102018-02-28 00:35:50 +1030178 }
Andrew Jefferye2744c02020-01-28 15:08:13 +1030179
180 /* Set any remaining buffer space to the erased state */
181 memset((char*)dst + access_len, 0xff, len - access_len);
182
Andrew Jefferye2744c02020-01-28 15:08:13 +1030183 return len;
184}
185
186ssize_t Request::write(void* dst, size_t len)
187{
188 if (len != clamp(len))
Andrew Jefferyad343102018-02-28 00:35:50 +1030189 {
Andrew Jefferye2744c02020-01-28 15:08:13 +1030190 std::stringstream err;
191 err << "Request size 0x" << std::hex << len << " from offset 0x"
192 << std::hex << offset << " exceeds the partition size 0x"
193 << std::hex << (partition.data.size << backend->block_size_shift);
194 throw OutOfBoundsOffset(err.str());
Andrew Jefferyad343102018-02-28 00:35:50 +1030195 }
Andrew Jefferye2744c02020-01-28 15:08:13 +1030196
197 /* Ensure file is at least the size of the maximum access */
198 fs::path path = getPartitionFilePath(O_RDWR);
199
200 MSG_INFO("Fulfilling write request against %s at offset 0x%zx from %p "
201 "for %zu\n",
202 path.c_str(), offset, dst, len);
203
204 int fd = ::open(path.c_str(), O_RDWR);
205 if (fd == -1)
206 {
207 MSG_ERR("Failed to open backing file at '%s': %d\n", path.c_str(),
208 errno);
209 throw std::system_error(errno, std::system_category());
210 }
211
212 int rc = lseek(fd, offset, SEEK_SET);
213 if (rc < 0)
214 {
Andrew Jeffery02821c62020-01-31 16:56:03 +1030215 int lerrno = errno;
216 close(fd);
Andrew Jefferye2744c02020-01-28 15:08:13 +1030217 MSG_ERR("Failed to seek to %zu in %s: %d\n", offset, path.c_str(),
Andrew Jeffery02821c62020-01-31 16:56:03 +1030218 lerrno);
219 throw std::system_error(lerrno, std::system_category());
Andrew Jefferye2744c02020-01-28 15:08:13 +1030220 }
221
222 rc = fd_process_all(::write, fd, dst, len);
223 if (rc < 0)
224 {
Andrew Jeffery02821c62020-01-31 16:56:03 +1030225 int lerrno = errno;
226 close(fd);
Andrew Jefferye2744c02020-01-28 15:08:13 +1030227 MSG_ERR("Failed to write %zu bytes to %s at %zu: %d\n", len,
Andrew Jeffery02821c62020-01-31 16:56:03 +1030228 path.c_str(), offset, lerrno);
229 throw std::system_error(lerrno, std::system_category());
Andrew Jefferye2744c02020-01-28 15:08:13 +1030230 }
231 backend_set_bytemap(backend, base + offset, len, FLASH_DIRTY);
232
Andrew Jefferyad343102018-02-28 00:35:50 +1030233 close(fd);
234
235 return len;
Ratan Guptac0ef9872017-06-06 14:31:37 +0530236}
237
Andrew Jefferyf34db312018-03-09 15:27:03 +1030238} // namespace virtual_pnor
239} // namespace openpower