[PATCH 2/8] barebox remote control
Andrey Smirnov
andrew.smirnov at gmail.com
Sun Jan 17 18:39:19 PST 2016
Discovered some build problems after I was done testing this code:
On Fri, Jan 8, 2016 at 3:13 AM, Sascha Hauer <s.hauer at pengutronix.de> wrote:
> This adds the ability to control barebox over serial lines. The regular
> console is designed for human input and is unsuitable for controlling
> barebox from scripts since characters can be lost on both ends, the data
> stream contains escape sequences and the prompt cannot be easily matched
> upon.
> This approach is based on the RATP protocol. RATP packages start with a
> binary 0x01 which does not occur in normal console data. Whenever a
> 0x01 character is detected in the console barebox goes into RATP mode.
> The RATP packets contain a simple structure with a command/respone
> type and data for that type. Currently defined types are:
>
> BB_RATP_TYPE_COMMAND (host->barebox):
> Execute a command in the shell
> BB_RATP_TYPE_COMMAND_RETURN (barebox->host)
> Sends return value of the command back to the host, also means
> barebox is ready for the next command
> BB_RATP_TYPE_CONSOLEMSG (barebox->host)
> Console message from barebox
>
> Planned but not yet implemented are:
>
> BB_RATP_TYPE_PING (host->barebox)
> BB_RATP_TYPE_PONG (barebox->host)
> For testing purposes
> BB_RATP_TYPE_GETENV (host->barebox)
> BB_RATP_TYPE_GETENV_RETURN (barebox->host)
> Get values of environment variables
>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
> common/Kconfig | 10 ++
> common/Makefile | 2 +
> common/console.c | 26 ++-
> common/ratp.c | 511 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> crypto/Kconfig | 1 +
> fs/Makefile | 1 +
> include/ratp.h | 2 +-
> lib/readline.c | 7 +
> 8 files changed, 556 insertions(+), 4 deletions(-)
> create mode 100644 common/ratp.c
>
> diff --git a/common/Kconfig b/common/Kconfig
> index 8e79509..2b5943b 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -611,6 +611,16 @@ config PBL_CONSOLE
> must be running at the address it's linked at and bss must
> be cleared. On ARM that would be after setup_c().
>
> +config CONSOLE_RATP
> + bool
> + select RATP
> + prompt "RATP console support"
> + help
> + This option adds support for remote controlling barebox via serial
> + port. The regular console is designed for human interaction whereas
> + this option adds a machine readable interface for controlling barebox.
> + Say yes here if you want to control barebox from a remote host.
> +
> config PARTITION
> bool
> prompt "Enable Partitions"
> diff --git a/common/Makefile b/common/Makefile
> index 56e6bec..5eb3c96 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -45,6 +45,7 @@ obj-$(CONFIG_RESET_SOURCE) += reset_source.o
> obj-$(CONFIG_SHELL_HUSH) += hush.o
> obj-$(CONFIG_SHELL_SIMPLE) += parser.o
> obj-$(CONFIG_STATE) += state.o
> +obj-$(CONFIG_RATP) += ratp.o
> obj-$(CONFIG_UIMAGE) += image.o uimage.o
> obj-$(CONFIG_MENUTREE) += menutree.o
> obj-$(CONFIG_EFI_GUID) += efi-guid.o
> @@ -54,6 +55,7 @@ obj-$(CONFIG_IMD) += imd.o
> obj-$(CONFIG_FILE_LIST) += file-list.o
> obj-$(CONFIG_FIRMWARE) += firmware.o
> obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
> +obj-$(CONFIG_CONSOLE_RATP) += ratp.o
>
> quiet_cmd_pwd_h = PWDH $@
> ifdef CONFIG_PASSWORD
> diff --git a/common/console.c b/common/console.c
> index 4a1d257..9924964 100644
> --- a/common/console.c
> +++ b/common/console.c
> @@ -303,6 +303,8 @@ int console_unregister(struct console_device *cdev)
> }
> EXPORT_SYMBOL(console_unregister);
>
> +int barebox_ratp(struct console_device *cdev);
This will break when RATP is not enabled in Kconfig
> +
> static int getc_raw(void)
> {
> struct console_device *cdev;
> @@ -313,8 +315,16 @@ static int getc_raw(void)
> if (!(cdev->f_active & CONSOLE_STDIN))
> continue;
> active = 1;
> - if (cdev->tstc(cdev))
> - return cdev->getc(cdev);
> + if (cdev->tstc(cdev)) {
> + int ch = cdev->getc(cdev);
> +
> + if (ch == 0x01) {
> + barebox_ratp(cdev);
> + return -1;
> + }
> +
> + return ch;
> + }
> }
> if (!active)
> /* no active console found. bail out */
> @@ -349,16 +359,26 @@ int getc(void)
> start = get_time_ns();
> while (1) {
> if (tstc_raw()) {
> - kfifo_putc(console_input_fifo, getc_raw());
> + int c = getc_raw();
> +
> + if (c < 0)
> + break;
> +
> + kfifo_putc(console_input_fifo, c);
>
> start = get_time_ns();
> }
> +
> if (is_timeout(start, 100 * USECOND) &&
> kfifo_len(console_input_fifo))
> break;
> }
>
> + if (!kfifo_len(console_input_fifo))
> + return -1;
> +
> kfifo_getc(console_input_fifo, &ch);
> +
> return ch;
> }
> EXPORT_SYMBOL(getc);
> diff --git a/common/ratp.c b/common/ratp.c
> new file mode 100644
> index 0000000..2fef3cc
> --- /dev/null
> +++ b/common/ratp.c
> @@ -0,0 +1,511 @@
> +/*
> + * Copyright (c) 2015 Sascha Hauer <s.hauer at pengutronix.de>, 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.
> + */
> +
> +#define pr_fmt(fmt) "barebox-ratp: " fmt
> +
> +#include <common.h>
> +#include <command.h>
> +#include <kfifo.h>
> +#include <malloc.h>
> +#include <init.h>
> +#include <ratp.h>
> +#include <command.h>
> +#include <byteorder.h>
> +#include <environment.h>
> +#include <kfifo.h>
> +#include <poller.h>
> +#include <linux/sizes.h>
> +#include <ratp_bb.h>
> +#include <fs.h>
> +
> +#define BB_RATP_TYPE_COMMAND 1
> +#define BB_RATP_TYPE_COMMAND_RETURN 2
> +#define BB_RATP_TYPE_CONSOLEMSG 3
> +#define BB_RATP_TYPE_PING 4
> +#define BB_RATP_TYPE_PONG 5
> +#define BB_RATP_TYPE_GETENV 6
> +#define BB_RATP_TYPE_GETENV_RETURN 7
> +#define BB_RATP_TYPE_FS 8
> +#define BB_RATP_TYPE_FS_RETURN 9
> +
> +struct ratp_bb {
> + uint16_t type;
> + uint16_t flags;
> + uint8_t data[];
> +};
> +
> +struct ratp_bb_command_return {
> + uint32_t errno;
> +};
> +
> +struct ratp_ctx {
> + struct console_device *cdev;
> + struct ratp ratp;
> + int ratp_status;
> + struct console_device ratp_console;
> + int have_synch;
> + int in_ratp_console;
> +
> + u8 sendbuf[256];
> + u8 sendbuf_len;
> +
> + int old_active;
> +
> + struct kfifo *console_recv_fifo;
> + struct kfifo *console_transmit_fifo;
> +
> + struct ratp_bb_pkt *fs_rx;
> +
> + struct poller_struct poller;
> +};
> +
> +static int console_recv(struct ratp *r, uint8_t *data)
> +{
> + struct ratp_ctx *ctx = container_of(r, struct ratp_ctx, ratp);
> + struct console_device *cdev = ctx->cdev;
> +
> + if (ctx->have_synch) {
> + ctx->have_synch = 0;
> + *data = 0x01;
> + return 0;
> + }
> +
> + if (!cdev->tstc(cdev))
> + return -EAGAIN;
> +
> + *data = cdev->getc(cdev);
> +
> + return 0;
> +}
> +
> +static int console_send(struct ratp *r, void *pkt, int len)
> +{
> + struct ratp_ctx *ctx = container_of(r, struct ratp_ctx, ratp);
> + struct console_device *cdev = ctx->cdev;
> + const uint8_t *buf = pkt;
> + int i;
> +
> + for (i = 0; i < len; i++)
> + cdev->putc(cdev, buf[i]);
> +
> + return 0;
> +}
> +
> +static void *xmemdup_add_zero(const void *buf, int len)
> +{
> + void *ret;
> +
> + ret = xzalloc(len + 1);
> + *(uint8_t *)(ret + len) = 0;
> + memcpy(ret, buf, len);
> +
> + return ret;
> +}
> +
> +static void ratp_queue_console_tx(struct ratp_ctx *ctx)
> +{
> + u8 buf[255];
> + struct ratp_bb *rbb = (void *)buf;
> + unsigned int now, maxlen = 255 - sizeof(*rbb);
> + int ret;
> +
> + rbb->type = cpu_to_be16(BB_RATP_TYPE_CONSOLEMSG);
> +
> + while (1) {
> + now = min(maxlen, kfifo_len(ctx->console_transmit_fifo));
> + if (!now)
> + break;
> +
> + kfifo_get(ctx->console_transmit_fifo, rbb->data, now);
> +
> + ret = ratp_send(&ctx->ratp, rbb, now + sizeof(*rbb));
> + if (ret)
> + return;
> + }
> +}
> +
> +static int ratp_bb_send_command_return(struct ratp_ctx *ctx, uint32_t errno)
> +{
> + void *buf;
> + struct ratp_bb *rbb;
> + struct ratp_bb_command_return *rbb_ret;
> + int len = sizeof(*rbb) + sizeof(*rbb_ret);
> + int ret;
> +
> + ratp_queue_console_tx(ctx);
> +
> + buf = xzalloc(len);
> + rbb = buf;
> + rbb_ret = buf + sizeof(*rbb);
> +
> + rbb->type = cpu_to_be16(BB_RATP_TYPE_COMMAND_RETURN);
> + rbb_ret->errno = cpu_to_be32(errno);
> +
> + ret = ratp_send(&ctx->ratp, buf, len);
> +
> + free(buf);
> +
> + return ret;
> +}
> +
> +static int ratp_bb_send_pong(struct ratp_ctx *ctx)
> +{
> + void *buf;
> + struct ratp_bb *rbb;
> + int len = sizeof(*rbb);
> + int ret;
> +
> + buf = xzalloc(len);
> + rbb = buf;
> +
> + rbb->type = cpu_to_be16(BB_RATP_TYPE_PONG);
> +
> + ret = ratp_send(&ctx->ratp, buf, len);
> +
> + free(buf);
> +
> + return ret;
> +}
> +
> +static int ratp_bb_send_getenv_return(struct ratp_ctx *ctx, const char *val)
> +{
> + void *buf;
> + struct ratp_bb *rbb;
> + int len, ret;
> +
> + if (!val)
> + val = "";
> +
> + len = sizeof(*rbb) + strlen(val);
> + buf = xzalloc(len);
> + rbb = buf;
> + strcpy(rbb->data, val);
> +
> + rbb->type = cpu_to_be16(BB_RATP_TYPE_GETENV_RETURN);
> +
> + ret = ratp_send(&ctx->ratp, buf, len);
> +
> + free(buf);
> +
> + return ret;
> +}
> +
> +static char *ratp_command;
> +static struct ratp_ctx *ratp_command_ctx;
> +
> +static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len)
> +{
> + const struct ratp_bb *rbb = buf;
> + struct ratp_bb_pkt *pkt;
> + int dlen = len - sizeof(struct ratp_bb);
> + char *varname;
> + int ret = 0;
> +
> + switch (be16_to_cpu(rbb->type)) {
> + case BB_RATP_TYPE_COMMAND:
> + if (ratp_command)
> + return 0;
> +
> + ratp_command = xmemdup_add_zero(&rbb->data, dlen);
> + ratp_command_ctx = ctx;
> + pr_debug("got command: %s\n", ratp_command);
> +
> + break;
> +
> + case BB_RATP_TYPE_COMMAND_RETURN:
> + case BB_RATP_TYPE_PONG:
> + break;
> +
> + case BB_RATP_TYPE_CONSOLEMSG:
> +
> + kfifo_put(ctx->console_recv_fifo, rbb->data, dlen);
> + break;
> +
> + case BB_RATP_TYPE_PING:
> + ret = ratp_bb_send_pong(ctx);
> + break;
> +
> + case BB_RATP_TYPE_GETENV:
> + varname = xmemdup_add_zero(&rbb->data, dlen);
> +
> + ret = ratp_bb_send_getenv_return(ctx, getenv(varname));
> + break;
> +
> + case BB_RATP_TYPE_FS_RETURN:
> + pkt = xzalloc(sizeof(*pkt) + dlen);
> + pkt->len = dlen;
> + memcpy(pkt->data, &rbb->data, dlen);
> + ctx->fs_rx = pkt;
> + break;
> + default:
> + printf("%s: unhandled packet type 0x%04x\n", __func__, be16_to_cpu(rbb->type));
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static int ratp_console_getc(struct console_device *cdev)
> +{
> + struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
> + unsigned char c;
> +
> + if (!kfifo_len(ctx->console_recv_fifo))
> + return -1;
> +
> + kfifo_getc(ctx->console_recv_fifo, &c);
> +
> + return c;
> +}
> +
> +static int ratp_console_tstc(struct console_device *cdev)
> +{
> + struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
> +
> + return kfifo_len(ctx->console_recv_fifo) ? 1 : 0;
> +}
> +
> +static int ratp_console_puts(struct console_device *cdev, const char *s)
> +{
> + struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
> + int len = 0;
> +
> + len = strlen(s);
> +
> + if (ratp_busy(&ctx->ratp))
> + return len;
> +
> + kfifo_put(ctx->console_transmit_fifo, s, len);
> +
> + return len;
> +}
> +
> +static void ratp_console_putc(struct console_device *cdev, char c)
> +{
> + struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
> +
> + if (ratp_busy(&ctx->ratp))
> + return;
> +
> + kfifo_putc(ctx->console_transmit_fifo, c);
> +}
> +
> +static int ratp_console_register(struct ratp_ctx *ctx)
> +{
> + int ret;
> +
> + ctx->ratp_console.tstc = ratp_console_tstc;
> + ctx->ratp_console.puts = ratp_console_puts;
> + ctx->ratp_console.putc = ratp_console_putc;
> + ctx->ratp_console.getc = ratp_console_getc;
> + ctx->ratp_console.devname = "ratpconsole";
> + ctx->ratp_console.devid = DEVICE_ID_SINGLE;
> +
> + ret = console_register(&ctx->ratp_console);
> + if (ret) {
> + pr_err("registering failed with %s\n", strerror(-ret));
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +void ratp_run_command(void)
> +{
> + int ret;
> +
> + if (!ratp_command)
> + return;
> +
> + pr_debug("running command: %s\n", ratp_command);
> +
> + ret = run_command(ratp_command);
> +
> + free(ratp_command);
> + ratp_command = NULL;
> +
> + ratp_bb_send_command_return(ratp_command_ctx, ret);
> +}
> +
> +static const char *ratpfs_mount_path;
> +
> +int barebox_ratp_fs_mount(const char *path)
> +{
> + if (path && ratpfs_mount_path)
> + return -EBUSY;
> +
> + ratpfs_mount_path = path;
> +
> + return 0;
> +}
> +
> +static void ratp_console_unregister(struct ratp_ctx *ctx)
> +{
> + int ret;
> +
> + console_set_active(&ctx->ratp_console, 0);
> + poller_unregister(&ctx->poller);
> + ratp_close(&ctx->ratp);
> + console_set_active(ctx->cdev, ctx->old_active);
> + ctx->cdev = NULL;
> +
> + if (ratpfs_mount_path) {
> + ret = umount(ratpfs_mount_path);
> + if (!ret)
> + ratpfs_mount_path = NULL;
> + }
> +}
> +
> +static void ratp_poller(struct poller_struct *poller)
> +{
> + struct ratp_ctx *ctx = container_of(poller, struct ratp_ctx, poller);
> + int ret;
> + size_t len;
> + void *buf;
> +
> + ratp_queue_console_tx(ctx);
> +
> + ret = ratp_poll(&ctx->ratp);
> + if (ret == -EINTR)
> + goto out;
> + if (ratp_closed(&ctx->ratp))
> + goto out;
> +
> + ret = ratp_recv(&ctx->ratp, &buf, &len);
> + if (ret < 0)
> + return;
> +
> + ratp_bb_dispatch(ctx, buf, len);
> +
> + free(buf);
> +
> + return;
> +
> +out:
> + ratp_console_unregister(ctx);
> +}
> +
> +static int do_ratp_close(int argc, char *argv[])
> +{
> + if (ratp_command_ctx && ratp_command_ctx->cdev)
> + ratp_console_unregister(ratp_command_ctx);
> + else
> + printf("ratp is not active\n");
> +
> + return 0;
> +}
> +
> +BAREBOX_CMD_START(ratp_close)
> + .cmd = do_ratp_close,
> +};
> +
> +int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx)
> +{
> + struct ratp_ctx *ctx = ratp_command_ctx;
> + struct ratp_bb *rbb;
> + int len;
> + u64 start;
> +
> + if (!ctx)
> + return -EINVAL;
> +
> + ctx->fs_rx = NULL;
> +
> + len = sizeof(*rbb) + tx->len;
> + rbb = xzalloc(len);
> + rbb->type = cpu_to_be16(BB_RATP_TYPE_FS);
> + memcpy(rbb->data, tx->data, tx->len);
> +
> + if (ratp_send(&ctx->ratp, rbb, len) != 0)
> + pr_debug("failed to send port pkt\n");
> +
> + free(rbb);
> +
> + start = get_time_ns();
> +
> + while (!ctx->fs_rx) {
> + poller_call();
> + if (ratp_closed(&ctx->ratp))
> + return -EIO;
> + if (is_timeout(start, 10 * SECOND))
> + return -ETIMEDOUT;
> + }
> +
> + *rx = ctx->fs_rx;
> +
> + pr_debug("%s: len %i\n", __func__, ctx->fs_rx->len);
> +
> + return 0;
> +}
> +
> +int barebox_ratp(struct console_device *cdev)
> +{
> + int ret;
> + struct ratp_ctx *ctx;
> + struct ratp *ratp;
> +
> + if (ratp_command_ctx) {
> + ctx = ratp_command_ctx;
> + } else {
> + ctx = xzalloc(sizeof(*ctx));
> + ratp_command_ctx = ctx;
> + ctx->ratp.send = console_send;
> + ctx->ratp.recv = console_recv;
> + ctx->console_recv_fifo = kfifo_alloc(512);
> + ctx->console_transmit_fifo = kfifo_alloc(SZ_128K);
> + ctx->poller.func = ratp_poller;
> + ratp_console_register(ctx);
> + }
> +
> + if (ctx->cdev)
> + return -EBUSY;
> +
> + ratp = &ctx->ratp;
> +
> + ctx->old_active = console_get_active(cdev);
> + console_set_active(cdev, 0);
> +
> + ctx->cdev = cdev;
> + ctx->have_synch = 1;
> +
> + ret = ratp_establish(ratp, false, 100);
> + if (ret < 0)
> + goto out;
> +
> + ret = poller_register(&ctx->poller);
> + if (ret)
> + goto out1;
> +
> + console_set_active(&ctx->ratp_console, CONSOLE_STDOUT | CONSOLE_STDERR |
> + CONSOLE_STDIN);
> +
> + return 0;
> +
> +out1:
> + ratp_close(ratp);
> +out:
> + console_set_active(ctx->cdev, ctx->old_active);
> + ctx->cdev = NULL;
> +
> + return ret;
> +}
> +
> +static void barebox_ratp_close(void)
> +{
> + if (ratp_command_ctx && ratp_command_ctx->cdev)
> + ratp_console_unregister(ratp_command_ctx);
> +}
> +predevshutdown_exitcall(barebox_ratp_close);
> \ No newline at end of file
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index 41145a3..fcf92c9 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -4,6 +4,7 @@ config CRC32
> bool
>
> config CRC16
> + default y
> bool
>
> config CRC7
> diff --git a/fs/Makefile b/fs/Makefile
> index 4693205..befbdf2 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -14,3 +14,4 @@ obj-$(CONFIG_FS_UIMAGEFS) += uimagefs.o
> obj-$(CONFIG_FS_EFI) += efi.o
> obj-$(CONFIG_FS_EFIVARFS) += efivarfs.o
> obj-$(CONFIG_FS_SMHFS) += smhfs.o
> +obj-$(CONFIG_RATP) += ratpfs.o
> diff --git a/include/ratp.h b/include/ratp.h
> index b91d305..94fd004 100644
> --- a/include/ratp.h
> +++ b/include/ratp.h
> @@ -19,4 +19,4 @@ bool ratp_busy(struct ratp *ratp);
>
> void ratp_run_command(void);
>
> -#endif /* __RATP_H */
> +#endif /* __RATP_H */
> \ No newline at end of file
> diff --git a/lib/readline.c b/lib/readline.c
> index c007e10..681f125 100644
> --- a/lib/readline.c
> +++ b/lib/readline.c
> @@ -1,6 +1,8 @@
> #include <common.h>
> #include <readkey.h>
> #include <init.h>
> +#include <poller.h>
> +#include <ratp.h>
> #include <xfuncs.h>
> #include <complete.h>
> #include <linux/ctype.h>
> @@ -197,6 +199,11 @@ int readline(const char *prompt, char *buf, int len)
> puts (prompt);
>
> while (1) {
> + while (!tstc()) {
> + poller_call();
> + ratp_run_command();
ratp_run_command() is not stubed out in <ratp.h> so this would break
linkage when RATP is not selected in Kconfig
> + }
> +
> ichar = read_key();
>
> if ((ichar == '\n') || (ichar == '\r')) {
> --
> 2.6.4
>
>
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
More information about the barebox
mailing list