summaryrefslogtreecommitdiffstats
path: root/common/ratp/mw.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2018-02-24 16:01:19 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2018-03-01 09:39:42 +0100
commitbfcdef33add4f58ebd7f6a9621c94b1fb2caabd5 (patch)
tree0d97784763bcaae6059e405673bfaae3d45f880d /common/ratp/mw.c
parent706328c33fc8e9e680f37ee4cdac9ecbf3127f23 (diff)
downloadbarebox-bfcdef33add4f58ebd7f6a9621c94b1fb2caabd5.tar.gz
barebox-bfcdef33add4f58ebd7f6a9621c94b1fb2caabd5.tar.xz
ratp: new md and mw commands
This commit introduces support for running the md and mw commands using the binary interface provided by RATP. This allows clients to read and write memory files without needing to do custom string parsing on the data returned by the console 'md' and 'mw' operations. The request and response messages used for these new operations are structured in the same way: * An initial fixed-sized section includes the fixed-sized variables (e.g. integers), as well as the size and offset of the variable-length variables. * After the initial fixed-sized section, the buffer is given, which contains the variable-length variables in the offsets previously defined and with the size previously defined. The message also defines separately the offset of the buffer w.r.t. the start of the message. The endpoint reading the message will use this information to decide where the buffer starts. This allows to extend the message format in the future without needing to break the message API, as new fields can be appended to the fixed-sized section as long as the buffer offset is also updated to report the new position of the buffer. E.g.: $ ./bbremote --port /dev/ttyUSB2 md /dev/pic_eeprom_rdu 0x107 5 0000000000 $ ./bbremote --port /dev/ttyUSB2 mw /dev/pic_eeprom_rdu 0x107 0102030405 5 bytes written $ ./bbremote --port /dev/ttyUSB2 md /dev/pic_eeprom_rdu 0x107 5 0102030405 $ ./bbremote --port /dev/ttyUSB2 mw /dev/pic_eeprom_rdu 0x107 0000000000 5 bytes written $ ./bbremote --port /dev/ttyUSB2 md /dev/pic_eeprom_rdu 0x107 5 0000000000 Signed-off-by: Aleksander Morgado <aleksander@aleksander.es> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'common/ratp/mw.c')
-rw-r--r--common/ratp/mw.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/common/ratp/mw.c b/common/ratp/mw.c
new file mode 100644
index 0000000000..7d6df3d0a0
--- /dev/null
+++ b/common/ratp/mw.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2011-2018 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ * Copyright (c) 2018 Zodiac Inflight Innovations
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <ratp_bb.h>
+#include <init.h>
+#include <driver.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fs.h>
+#include <libfile.h>
+#include <fcntl.h>
+#include <xfuncs.h>
+
+/* NOTE:
+ * - Fixed-size fields (e.g. integers) are given just after the header.
+ * - Variable-length fields are stored inside the buffer[] and their position
+ * within the buffer[] and their size are given as fixed-sized fields after
+ * the header.
+ * The message may be extended at any time keeping backwards compatibility,
+ * as the position of the buffer[] is given by the buffer_offset field. i.e.
+ * increasing the buffer_offset field we can extend the fixed-sized section
+ * to add more fields.
+ */
+
+struct ratp_bb_mw_request {
+ struct ratp_bb header;
+ uint16_t buffer_offset;
+ uint16_t addr;
+ uint16_t path_size;
+ uint16_t path_offset;
+ uint16_t data_size;
+ uint16_t data_offset;
+ uint8_t buffer[];
+} __attribute__((packed));
+
+struct ratp_bb_mw_response {
+ struct ratp_bb header;
+ uint16_t buffer_offset;
+ uint32_t errno;
+ uint16_t written;
+ uint8_t buffer[];
+} __attribute__((packed));
+
+static int ratp_cmd_mw(const struct ratp_bb *req, int req_len,
+ struct ratp_bb **rsp, int *rsp_len)
+{
+ struct ratp_bb_mw_request *mw_req = (struct ratp_bb_mw_request *)req;
+ struct ratp_bb_mw_response *mw_rsp;
+ uint8_t *buffer;
+ uint16_t buffer_offset;
+ uint16_t buffer_size;
+ uint16_t addr;
+ uint16_t path_size;
+ uint16_t path_offset;
+ uint16_t data_size;
+ uint16_t data_offset;
+ ssize_t written = 0;
+ char *path = NULL;
+ int fd;
+ int ret = 0;
+
+ /* At least message header should be valid */
+ if (req_len < sizeof(*mw_req)) {
+ printf("ratp mw ignored: size mismatch (%d < %zu)\n",
+ req_len, sizeof (*mw_req));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Validate buffer position and size */
+ buffer_offset = be16_to_cpu(mw_req->buffer_offset);
+ if (req_len < buffer_offset) {
+ printf("ratp mw ignored: invalid buffer offset (%d < %hu)\n",
+ req_len, buffer_offset);
+ ret = -EINVAL;
+ goto out;
+ }
+ buffer_size = req_len - buffer_offset;
+ buffer = ((uint8_t *)mw_req) + buffer_offset;
+
+ /* Validate path position and size */
+ path_offset = be16_to_cpu(mw_req->path_offset);
+ if (path_offset != 0) {
+ printf("ratp mw ignored: invalid path offset\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ path_size = be16_to_cpu(mw_req->path_size);
+ if (!path_size) {
+ printf("ratp mw ignored: no filepath given\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Validate data position and size */
+ data_offset = be16_to_cpu(mw_req->data_offset);
+ if (data_offset != (path_offset + path_size)) {
+ printf("ratp mw ignored: invalid path offset\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ data_size = be16_to_cpu(mw_req->data_size);
+ if (!data_size) {
+ /* Success */
+ goto out;
+ }
+
+ /* Validate buffer size */
+ if (buffer_size < (path_size + data_size)) {
+ printf("ratp mw ignored: size mismatch (%d < %hu): path or data not be fully given\n",
+ req_len, path_size + data_size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ addr = be16_to_cpu (mw_req->addr);
+ path = xstrndup((const char *)&buffer[path_offset], path_size);
+
+ fd = open_and_lseek(path, O_RWSIZE_1 | O_WRONLY, addr);
+ if (fd < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ written = write(fd, &buffer[data_offset], data_size);
+ if (written < 0) {
+ ret = -errno;
+ perror("write");
+ }
+
+ close(fd);
+
+out:
+ mw_rsp = xzalloc(sizeof(*mw_rsp));
+ mw_rsp->header.type = cpu_to_be16(BB_RATP_TYPE_MW_RETURN);
+ mw_rsp->buffer_offset = cpu_to_be16(sizeof(*mw_rsp)); /* n/a */
+
+ if (ret != 0) {
+ mw_rsp->written = 0;
+ mw_rsp->errno = cpu_to_be32(ret);
+ } else {
+ mw_rsp->written = cpu_to_be16((uint16_t)written);
+ mw_rsp->errno = 0;
+ }
+
+ *rsp = (struct ratp_bb *)mw_rsp;
+ *rsp_len = sizeof(*mw_rsp);
+
+ free (path);
+ return ret;
+}
+
+BAREBOX_RATP_CMD_START(MW)
+ .request_id = BB_RATP_TYPE_MW,
+ .response_id = BB_RATP_TYPE_MW_RETURN,
+ .cmd = ratp_cmd_mw
+BAREBOX_RATP_CMD_END