1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2018 IBM Corp. 3 // Copyright (C) 2018 Evan Lojewski. 4 5 #define _GNU_SOURCE 6 #include <assert.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <getopt.h> 10 #include <inttypes.h> 11 #include <limits.h> 12 #include <mtd/mtd-abi.h> 13 #include <poll.h> 14 #include <signal.h> 15 #include <stdbool.h> 16 #include <stdint.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <sys/ioctl.h> 21 #include <sys/mman.h> 22 #include <sys/stat.h> 23 #include <sys/timerfd.h> 24 #include <sys/types.h> 25 #include <syslog.h> 26 #include <time.h> 27 #include <unistd.h> 28 29 #include "common.h" 30 #include "backend.h" 31 #include "lpc.h" 32 #include "mboxd.h" 33 34 #define MIN(__x__, __y__) (((__x__) < (__y__)) ? (__x__) : (__y__)) 35 36 #define FILE_ERASE_SIZE (4 * 1024) 37 38 #pragma GCC diagnostic push 39 #pragma GCC diagnostic ignored "-Wpointer-arith" 40 41 struct file_data { 42 int fd; 43 }; 44 45 static int file_dev_init(struct backend *backend, void *data) 46 { 47 struct mtd_info_user info; 48 const char *path = data; 49 struct file_data *priv; 50 struct stat statbuf; 51 int rc = 0; 52 53 if (!path) { 54 MSG_ERR("No PNOR file specified\n"); 55 return -EINVAL; 56 } 57 58 priv = malloc(sizeof(*priv)); 59 if (!priv) 60 return -errno; 61 62 MSG_DBG("Opening %s\n", path); 63 64 priv->fd = open(path, O_RDWR); 65 if (priv->fd < 0) { 66 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", path, 67 strerror(errno)); 68 rc = -errno; 69 goto cleanup_data; 70 } 71 72 /* Don't attach to mtd devices. */ 73 rc = ioctl(priv->fd, MEMGETINFO, &info); 74 if (rc != -1) { 75 rc = -errno; 76 goto cleanup_fd; 77 } 78 79 rc = fstat(priv->fd, &statbuf); 80 if (rc < 0) { 81 rc = -errno; 82 goto cleanup_fd; 83 } 84 85 if (backend->flash_size == 0) { 86 MSG_INFO("Flash size should be supplied on the commandline.\n"); 87 backend->flash_size = statbuf.st_size; 88 } 89 90 /* Pick an erase size congruent with partition alignment */ 91 backend->erase_size_shift = log_2(FILE_ERASE_SIZE); 92 backend->block_size_shift = backend->erase_size_shift; 93 MSG_DBG("Flash erase size: 0x%.8x\n", FILE_ERASE_SIZE); 94 95 backend->priv = priv; 96 return rc; 97 98 cleanup_fd: 99 close(priv->fd); 100 cleanup_data: 101 free(priv); 102 return rc; 103 } 104 105 static void file_dev_free(struct backend *backend) 106 { 107 struct file_data *priv = backend->priv; 108 109 close(priv->fd); 110 free(priv); 111 } 112 113 /* Flash Functions */ 114 115 /* 116 * file_erase() - Erase the flash 117 * @context: The mbox context pointer 118 * @offset: The flash offset to erase (bytes) 119 * @size: The number of bytes to erase 120 * 121 * Return: 0 on success otherwise negative error code 122 */ 123 static int file_erase(struct backend *backend, uint32_t offset, uint32_t count) 124 { 125 const uint32_t erase_size = 1 << backend->erase_size_shift; 126 struct file_data *priv = backend->priv; 127 struct erase_info_user erase_info = {0}; 128 int rc; 129 130 MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", offset, count); 131 132 uint8_t* erase_buf = (uint8_t*)malloc(count); 133 if (!erase_buf) { 134 MSG_ERR("Couldn't malloc erase buffer. %s\n", strerror(errno)); 135 return -1; 136 } 137 memset(erase_buf, 0xFF, erase_size); 138 rc = pwrite(priv->fd, erase_buf, count, offset); 139 free(erase_buf); 140 141 if (rc < 0) { 142 MSG_ERR("Couldn't erase flash at 0x%.8x\n", erase_info.start); 143 return -errno; 144 } 145 146 147 return 0; 148 } 149 150 #define CHUNKSIZE (64 * 1024) 151 152 /* 153 * file_copy() - Copy data from the flash device into a provided buffer 154 * @context: The backend context pointer 155 * @offset: The flash offset to copy from (bytes) 156 * @mem: The buffer to copy into (must be of atleast 'size' bytes) 157 * @size: The number of bytes to copy 158 * Return: Number of bytes copied on success, otherwise negative error 159 * code. file_copy will copy at most 'size' bytes, but it may 160 * copy less. 161 */ 162 static int64_t file_copy(struct backend *backend, uint32_t offset, 163 void *mem, uint32_t size) 164 { 165 struct file_data *priv = backend->priv; 166 int32_t size_read; 167 void *start = mem; 168 169 MSG_DBG("Copy flash to %p for size 0x%.8x from offset 0x%.8x\n", mem, 170 size, offset); 171 if (lseek(priv->fd, offset, SEEK_SET) != offset) { 172 MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset, 173 strerror(errno)); 174 return -errno; 175 } 176 177 do { 178 size_read = read(priv->fd, mem, min_u32(CHUNKSIZE, size)); 179 if (size_read < 0) { 180 MSG_ERR("Couldn't copy file into ram: %s\n", 181 strerror(errno)); 182 return -errno; 183 } 184 185 size -= size_read; 186 mem += size_read; 187 } while (size && size_read); 188 189 return size_read ? mem - start : -EIO; 190 } 191 192 /* 193 * file_write() - Write the flash from a provided buffer 194 * @context: The mbox context pointer 195 * @offset: The flash offset to write to (bytes) 196 * @buf: The buffer to write from (must be of atleast size) 197 * @size: The number of bytes to write 198 * 199 * Return: 0 on success otherwise negative error code 200 */ 201 static int file_write(struct backend *backend, uint32_t offset, void *buf, 202 uint32_t count) 203 { 204 struct file_data *priv = backend->priv; 205 uint32_t buf_offset = 0; 206 int rc; 207 208 MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count, 209 buf); 210 211 if (lseek(priv->fd, offset, SEEK_SET) != offset) { 212 MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset, 213 strerror(errno)); 214 return -errno; 215 } 216 217 while (count) { 218 rc = write(priv->fd, buf + buf_offset, count); 219 if (rc < 0) { 220 MSG_ERR("Couldn't write to file, write lost: %s\n", 221 strerror(errno)); 222 return -errno; 223 } 224 count -= rc; 225 buf_offset += rc; 226 } 227 228 return 0; 229 } 230 231 /* 232 * file_reset() - Reset the lpc bus mapping 233 * @context: The backend context pointer 234 * @buf: Pointer to the LPC reserved memory 235 * @count: The size of the LPC reserved memory 236 * 237 * Return: 0 on success otherwise negative error code 238 */ 239 static int file_reset(struct backend *backend, void *buf, uint32_t count) 240 { 241 struct file_data *priv = backend->priv; 242 size_t len; 243 int rc; 244 245 len = MIN(backend->flash_size, count); 246 247 /* Ugh, otherwise we need to parse the FFS image */ 248 assert(len == backend->flash_size); 249 250 /* Preload Flash contents into memory window */ 251 rc = pread(priv->fd, buf, len, 0); 252 if (rc < 0) 253 return -errno; 254 255 return reset_lpc_memory; 256 } 257 258 static const struct backend_ops file_ops = { 259 .init = file_dev_init, 260 .free = file_dev_free, 261 .copy = file_copy, 262 .erase = file_erase, 263 .write = file_write, 264 .reset = file_reset, 265 .validate = NULL, 266 .align_offset = NULL, 267 }; 268 269 struct backend backend_get_file(void) 270 { 271 struct backend be = {0}; 272 273 be.ops = &file_ops; 274 275 return be; 276 } 277 278 int backend_probe_file(struct backend *master, const char *path) 279 { 280 struct backend with; 281 282 assert(master); 283 with = backend_get_file(); 284 285 return backend_init(master, &with, (void *)path); 286 } 287 288 #pragma GCC diagnostic pop 289