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