On Fri, Jan 8, 2016 at 3:13 AM, Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxx> > --- > 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); > + > 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@xxxxxxxxxxxxxx>, 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> It looks like this file is missing from the patchset > +#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(); > + } > + > ichar = read_key(); > > if ((ichar == '\n') || (ichar == '\r')) { > -- > 2.6.4 > > > _______________________________________________ > barebox mailing list > barebox@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/barebox _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox