diff --git a/common/ratp/Makefile b/common/ratp/Makefile index 2fa9d63..d4cfdf9 100644 --- a/common/ratp/Makefile +++ b/common/ratp/Makefile @@ -1,3 +1,5 @@ obj-y += ratp.o obj-y += ping.o obj-y += getenv.o +obj-y += md.o +obj-y += mw.o diff --git a/common/ratp/md.c b/common/ratp/md.c new file mode 100644 index 0000000..9b8fc2b --- /dev/null +++ b/common/ratp/md.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2011-2018 Sascha Hauer , Pengutronix + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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_md_request { + struct ratp_bb header; + uint16_t buffer_offset; + uint16_t addr; + uint16_t size; + uint16_t path_size; + uint16_t path_offset; + uint8_t buffer[]; +} __attribute__((packed)); + +struct ratp_bb_md_response { + struct ratp_bb header; + uint16_t buffer_offset; + uint32_t errno; + uint16_t data_size; + uint16_t data_offset; + uint8_t buffer[]; +} __attribute__((packed)); + +extern char *mem_rw_buf; + +static int do_ratp_mem_md(const char *filename, + loff_t start, + loff_t size, + uint8_t *output) +{ + int r, now, t; + int ret = 0; + int fd; + void *map; + + fd = open_and_lseek(filename, O_RWSIZE_1 | O_RDONLY, start); + if (fd < 0) + return -errno; + + map = memmap(fd, PROT_READ); + if (map != (void *)-1) { + memcpy(output, (uint8_t *)(map + start), size); + goto out; + } + + t = 0; + do { + now = min(size, (loff_t)RW_BUF_SIZE); + r = read(fd, mem_rw_buf, now); + if (r < 0) { + ret = -errno; + perror("read"); + goto out; + } + if (!r) + goto out; + + memcpy(output + t, (uint8_t *)(mem_rw_buf), r); + + size -= r; + t += r; + } while (size); + +out: + close(fd); + + return ret; +} + +static int ratp_cmd_md(const struct ratp_bb *req, int req_len, + struct ratp_bb **rsp, int *rsp_len) +{ + struct ratp_bb_md_request *md_req = (struct ratp_bb_md_request *)req; + struct ratp_bb_md_response *md_rsp; + uint8_t *buffer; + uint16_t buffer_offset; + uint16_t buffer_size; + int md_rsp_len; + uint16_t addr; + uint16_t size; + uint16_t path_size; + uint16_t path_offset; + char *path = NULL; + int ret = 0; + + /* At least message header should be valid */ + if (req_len < sizeof(*md_req)) { + printf("ratp md ignored: size mismatch (%d < %zu)\n", + req_len, sizeof (*md_req)); + ret = -EINVAL; + goto out; + } + + /* Validate buffer position and size */ + buffer_offset = be16_to_cpu(md_req->buffer_offset); + if (req_len < buffer_offset) { + printf("ratp md ignored: invalid buffer offset (%d < %hu)\n", + req_len, buffer_offset); + ret = -EINVAL; + goto out; + } + buffer_size = req_len - buffer_offset; + buffer = ((uint8_t *)md_req) + buffer_offset; + + /* Validate path position and size */ + path_offset = be16_to_cpu(md_req->path_offset); + if (path_offset != 0) { + printf("ratp md ignored: invalid path offset\n"); + ret = -EINVAL; + goto out; + } + path_size = be16_to_cpu(md_req->path_size); + if (!path_size) { + printf("ratp md ignored: no filepath given\n"); + ret = -EINVAL; + goto out; + } + + /* Validate buffer size */ + if (buffer_size < path_size) { + printf("ratp mw ignored: size mismatch (%d < %hu): path may not be fully given\n", + req_len, path_size); + ret = -EINVAL; + goto out; + } + + addr = be16_to_cpu (md_req->addr); + size = be16_to_cpu (md_req->size); + path = xstrndup((const char *)&buffer[path_offset], path_size); + +out: + /* Avoid reading anything on error */ + if (ret != 0) + size = 0; + + md_rsp_len = sizeof(*md_rsp) + size; + md_rsp = xzalloc(md_rsp_len); + md_rsp->header.type = cpu_to_be16(BB_RATP_TYPE_MD_RETURN); + md_rsp->buffer_offset = cpu_to_be16(sizeof(*md_rsp)); + md_rsp->data_offset = 0; + + /* Don't read anything on error or if 0 bytes were requested */ + if (size > 0) + ret = do_ratp_mem_md(path, addr, size, md_rsp->buffer); + + if (ret != 0) { + md_rsp->data_size = 0; + md_rsp->errno = cpu_to_be32(ret); + md_rsp_len = sizeof(*md_rsp); + } else { + md_rsp->data_size = cpu_to_be16(size); + md_rsp->errno = 0; + } + + *rsp = (struct ratp_bb *)md_rsp; + *rsp_len = md_rsp_len; + + free (path); + return ret; +} + +BAREBOX_RATP_CMD_START(MD) + .request_id = BB_RATP_TYPE_MD, + .response_id = BB_RATP_TYPE_MD_RETURN, + .cmd = ratp_cmd_md +BAREBOX_RATP_CMD_END diff --git a/common/ratp/mw.c b/common/ratp/mw.c new file mode 100644 index 0000000..7d6df3d --- /dev/null +++ b/common/ratp/mw.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2011-2018 Sascha Hauer , 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 diff --git a/include/ratp_bb.h b/include/ratp_bb.h index 75aabed..00b165f 100644 --- a/include/ratp_bb.h +++ b/include/ratp_bb.h @@ -12,6 +12,10 @@ #define BB_RATP_TYPE_GETENV_RETURN 7 #define BB_RATP_TYPE_FS 8 #define BB_RATP_TYPE_FS_RETURN 9 +#define BB_RATP_TYPE_MD 10 +#define BB_RATP_TYPE_MD_RETURN 11 +#define BB_RATP_TYPE_MW 12 +#define BB_RATP_TYPE_MW_RETURN 13 struct ratp_bb { uint16_t type; diff --git a/scripts/remote/controller.py b/scripts/remote/controller.py index a7257ec..eaab9f8 100644 --- a/scripts/remote/controller.py +++ b/scripts/remote/controller.py @@ -46,6 +46,18 @@ elif p_type == BBType.fs_return: logging.debug("received: fs_return") return BBPacketFSReturn(raw=data) + elif p_type == BBType.md: + logging.debug("received: md") + return BBPacketMd(raw=data) + elif p_type == BBType.md_return: + logging.debug("received: md_return") + return BBPacketMdReturn(raw=data) + elif p_type == BBType.mw: + logging.debug("received: mw") + return BBPacketMw(raw=data) + elif p_type == BBType.mw_return: + logging.debug("received: mw_return") + return BBPacketMwReturn(raw=data) else: logging.debug("received: UNKNOWN") return BBPacket(raw=data) @@ -112,6 +124,18 @@ r = self._expect(BBPacketGetenvReturn) return r.text + def md(self, path, addr, size): + self._send(BBPacketMd(path=path, addr=addr, size=size)) + r = self._expect(BBPacketMdReturn) + logging.info("Md return: %r", r) + return (r.exit_code,r.data) + + def mw(self, path, addr, data): + self._send(BBPacketMw(path=path, addr=addr, data=data)) + r = self._expect(BBPacketMwReturn) + logging.info("Mw return: %r", r) + return (r.exit_code,r.written) + def close(self): self.conn.close() diff --git a/scripts/remote/main.py b/scripts/remote/main.py index 79203df..29f601e 100644 --- a/scripts/remote/main.py +++ b/scripts/remote/main.py @@ -5,6 +5,7 @@ import sys import os import argparse +import binascii import logging from Queue import Queue from .ratp import RatpError @@ -76,6 +77,27 @@ return res +def handle_md(args): + ctrl = get_controller(args) + (res,data) = ctrl.md(args.path, args.address, args.size) + if res == 0: + print(binascii.hexlify(data)) + ctrl.close() + return res + + +def handle_mw(args): + ctrl = get_controller(args) + data=args.data + if ((len(data) % 2) != 0): + data="0"+data + (res,written) = ctrl.mw(args.path, args.address, binascii.unhexlify(data)) + if res == 0: + print("%i bytes written" % written) + ctrl.close() + return res + + def handle_listen(args): port = serial.serial_for_url(args.port, args.baudrate) conn = SerialRatpConnection(port) @@ -118,6 +140,10 @@ ctrl.conn.total_retransmits, ctrl.conn.total_crc_errors)) +# Support base 10 or base 16 numbers automatically +def auto_int(x): + return int(x, 0) + VERBOSITY = { 0: logging.WARN, 1: logging.INFO, @@ -143,6 +169,18 @@ parser_getenv.add_argument('arg', nargs='+', help="variable name") parser_getenv.set_defaults(func=handle_getenv) +parser_md = subparsers.add_parser('md', help="run md command") +parser_md.add_argument('path', help="path") +parser_md.add_argument('address', type=auto_int, help="address") +parser_md.add_argument('size', type=auto_int, help="size") +parser_md.set_defaults(func=handle_md) + +parser_mw = subparsers.add_parser('mw', help="run mw command") +parser_mw.add_argument('path', help="path") +parser_mw.add_argument('address', type=auto_int, help="address") +parser_mw.add_argument('data', help="data") +parser_mw.set_defaults(func=handle_mw) + parser_listen = subparsers.add_parser('listen', help="listen for an incoming connection") parser_listen.set_defaults(func=handle_listen) diff --git a/scripts/remote/messages.py b/scripts/remote/messages.py index 8e8495b..4f4d8e9 100644 --- a/scripts/remote/messages.py +++ b/scripts/remote/messages.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function import struct +import binascii class BBType(object): @@ -16,6 +17,10 @@ getenv_return = 7 fs = 8 fs_return = 9 + md = 10 + md_return = 11 + mw = 12 + mw_return = 13 class BBPacket(object): @@ -152,3 +157,87 @@ def __repr__(self): return "BBPacketFSReturn(payload=%r)" % self.payload + + +class BBPacketMd(BBPacket): + def __init__(self, raw=None, path=None, addr=None, size=None): + self.path = path + self.addr = addr + self.size = size + super(BBPacketMd, self).__init__(BBType.md, raw=raw) + + def __repr__(self): + return "BBPacketMd(path=%r,addr=0x%x,size=%u)" % (self.path, self.addr, self.size) + + def _unpack_payload(self, payload): + buffer_offset, self.addr, self.size, path_size, path_offset = struct.unpack("!HHHHH", payload[:10]) + # header size is always 4 bytes (HH), so adjust the absolute data offset without the header size + absolute_path_offset = buffer_offset + path_offset - 4 + self.path = payload[absolute_path_offset:absolute_path_offset+path_size] + + def _pack_payload(self): + # header size is always 4 bytes (HH) and we have 10 bytes of fixed data (HHHHH), so buffer offset is 14 + return struct.pack("!HHHHH%ds" % len(self.path), 14, self.addr, self.size, len(self.path), 0, self.path) + + +class BBPacketMdReturn(BBPacket): + def __init__(self, raw=None, exit_code=None, data=None): + self.exit_code = exit_code + self.data = data + super(BBPacketMdReturn, self).__init__(BBType.md_return, raw=raw) + + def __repr__(self): + return "BBPacketMdReturn(exit_code=%i, data=%s)" % (self.exit_code, binascii.hexlify(self.data)) + + def _unpack_payload(self, payload): + buffer_offset, self.exit_code, data_size, data_offset = struct.unpack("!HLHH", payload[:10]) + # header size is always 4 bytes (HH), so adjust the absolute data offset without the header size + absolute_data_offset = buffer_offset + data_offset - 4 + self.data = payload[absolute_data_offset:absolute_data_offset + data_size] + + def _pack_payload(self): + # header size is always 4 bytes (HH) and we have 10 bytes of fixed data (HLHH), so buffer offset is 14 + return struct.pack("!HLHH%ds" % len(self.data), 14, self.exit_code, len(self.data), 0, self.data) + return self.text + + +class BBPacketMw(BBPacket): + def __init__(self, raw=None, path=None, addr=None, data=None): + self.path = path + self.addr = addr + self.data = data + super(BBPacketMw, self).__init__(BBType.mw, raw=raw) + + def __repr__(self): + return "BBPacketMw(path=%r,addr=0x%x,data=%r)" % (self.path, self.addr, self.data) + + def _unpack_payload(self, payload): + buffer_offset, self.addr, path_size, path_offset, data_size, data_offset = struct.unpack("!HHHHHH", payload[:12]) + # header size is always 4 bytes (HH), so adjust the absolute data offset without the header size + absolute_path_offset = buffer_offset + path_offset - 4 + self.path = payload[absolute_path_offset:absolute_path_offset+path_size] + absolute_data_offset = buffer_offset + data_offset - 4 + self.data = payload[absolute_data_offset:absolute_data_offset+data_size] + + def _pack_payload(self): + # header size is always 4 bytes (HH) and we have 12 bytes of fixed data (HHHHHH), so buffer offset is 16 + path_size = len(self.path) + data_size = len(self.data) + return struct.pack("!HHHHHH%ds%ds" % (path_size, path_size), 16, self.addr, path_size, 0, data_size, path_size, self.path, self.data) + + +class BBPacketMwReturn(BBPacket): + def __init__(self, raw=None, exit_code=None, written=None): + self.exit_code = exit_code + self.written = written + super(BBPacketMwReturn, self).__init__(BBType.mw_return, raw=raw) + + def __repr__(self): + return "BBPacketMwReturn(exit_code=%i, written=%i)" % (self.exit_code, self.written) + + def _unpack_payload(self, payload): + buffer_offset, self.exit_code, self.written = struct.unpack("!HLH", payload[:8]) + + def _pack_payload(self): + # header size is always 4 bytes (HH) and we have 8 bytes of fixed data (HLH), so buffer offset is 14 + return struct.pack("!HLH", 12, self.exit_code, self.written)