diff --git a/common/Kconfig b/common/Kconfig index 8e7950968..2b5943be8 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 56e6becec..5eb3c96f4 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 4a1d2576d..a54189258 100644 --- a/common/console.c +++ b/common/console.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -313,8 +314,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 (IS_ENABLED(CONFIG_RATP) && ch == 0x01) { + barebox_ratp(cdev); + return -1; + } + + return ch; + } } if (!active) /* no active console found. bail out */ @@ -349,16 +358,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 000000000..2fef3cc0f --- /dev/null +++ b/common/ratp.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2015 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. + */ + +#define pr_fmt(fmt) "barebox-ratp: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 41145a312..fcf92c9f8 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 46932057c..befbdf27f 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 b91d305a2..94fd004f4 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/include/ratp_bb.h b/include/ratp_bb.h new file mode 100644 index 000000000..52ecaff37 --- /dev/null +++ b/include/ratp_bb.h @@ -0,0 +1,15 @@ +#ifndef __RATP_BB_H +#define __RATP_BB_H + +struct ratp_bb_pkt { + struct list_head list; + + unsigned int len; + uint8_t data[]; +}; + +int barebox_ratp(struct console_device *cdev); +int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx); +int barebox_ratp_fs_mount(const char *path); + +#endif /* __RATP_BB_H */ diff --git a/lib/readline.c b/lib/readline.c index c007e10f5..a5dac08af 100644 --- a/lib/readline.c +++ b/lib/readline.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -197,6 +199,12 @@ int readline(const char *prompt, char *buf, int len) puts (prompt); while (1) { + while (!tstc()) { + poller_call(); + if (IS_ENABLED(CONFIG_RATP)) + ratp_run_command(); + } + ichar = read_key(); if ((ichar == '\n') || (ichar == '\r')) {