diff --git a/Documentation/user/remote-control.rst b/Documentation/user/remote-control.rst index 2172514..c8b7442 100644 --- a/Documentation/user/remote-control.rst +++ b/Documentation/user/remote-control.rst @@ -18,6 +18,13 @@ console offers interactive access to barebox on flawy serial connections. +In addition to the bbremote tool provided with barebox, other third +party tools exist that use the same RATP based protocol to communicate +with the barebox instance, e.g. the libratp-barebox C library and the +ratp-barebox-cli tool: + + https://github.com/aleksander0m/libratp-barebox + Enabling remote control support ------------------------------- diff --git a/arch/arm/lib32/barebox.lds.S b/arch/arm/lib32/barebox.lds.S index e7b87b7..6fadc2a 100644 --- a/arch/arm/lib32/barebox.lds.S +++ b/arch/arm/lib32/barebox.lds.S @@ -85,6 +85,10 @@ .barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + __barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + __barebox_magicvar_start = .; .barebox_magicvar : { BAREBOX_MAGICVARS } __barebox_magicvar_end = .; diff --git a/arch/arm/lib64/barebox.lds.S b/arch/arm/lib64/barebox.lds.S index 240699f..a53b933 100644 --- a/arch/arm/lib64/barebox.lds.S +++ b/arch/arm/lib64/barebox.lds.S @@ -82,6 +82,10 @@ .barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + __barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + __barebox_magicvar_start = .; .barebox_magicvar : { BAREBOX_MAGICVARS } __barebox_magicvar_end = .; diff --git a/arch/blackfin/boards/ipe337/barebox.lds.S b/arch/blackfin/boards/ipe337/barebox.lds.S index 51a586a..7e82a1b 100644 --- a/arch/blackfin/boards/ipe337/barebox.lds.S +++ b/arch/blackfin/boards/ipe337/barebox.lds.S @@ -68,6 +68,10 @@ .barebox_cmd : { BAREBOX_CMDS } ___barebox_cmd_end = .; + ___barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + ___barebox_ratp_cmd_end = .; + ___barebox_magicvar_start = .; .barebox_magicvar : { BAREBOX_MAGICVARS } ___barebox_magicvar_end = .; @@ -91,4 +95,3 @@ ___bss_stop = .; _end = .; } - diff --git a/arch/mips/lib/barebox.lds.S b/arch/mips/lib/barebox.lds.S index 899f62b..660d4be 100644 --- a/arch/mips/lib/barebox.lds.S +++ b/arch/mips/lib/barebox.lds.S @@ -55,6 +55,10 @@ .barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + __barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + __barebox_magicvar_start = .; .barebox_magicvar : { BAREBOX_MAGICVARS } __barebox_magicvar_end = .; diff --git a/arch/nios2/cpu/barebox.lds.S b/arch/nios2/cpu/barebox.lds.S index a2d7fa8..fbcd1cd 100644 --- a/arch/nios2/cpu/barebox.lds.S +++ b/arch/nios2/cpu/barebox.lds.S @@ -55,6 +55,10 @@ .barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + __barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + __barebox_magicvar_start = .; .barebox_magicvar : { BAREBOX_MAGICVARS } __barebox_magicvar_end = .; @@ -129,4 +133,3 @@ _end = .; PROVIDE (end = .); } - diff --git a/arch/openrisc/cpu/barebox.lds.S b/arch/openrisc/cpu/barebox.lds.S index b819ca0..c6807ae 100644 --- a/arch/openrisc/cpu/barebox.lds.S +++ b/arch/openrisc/cpu/barebox.lds.S @@ -57,6 +57,10 @@ .barebox_cmd : { BAREBOX_CMDS } > ram __barebox_cmd_end = .; + __barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } > ram + __barebox_ratp_cmd_end = .; + __barebox_magicvar_start = .; .barebox_magicvar : { BAREBOX_MAGICVARS } > ram __barebox_magicvar_end = .; diff --git a/arch/ppc/boards/pcm030/barebox.lds.S b/arch/ppc/boards/pcm030/barebox.lds.S index 0e34f0a..3b8bf3c 100644 --- a/arch/ppc/boards/pcm030/barebox.lds.S +++ b/arch/ppc/boards/pcm030/barebox.lds.S @@ -104,6 +104,10 @@ .barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + __barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + __barebox_magicvar_start = .; .barebox_magicvar : { BAREBOX_MAGICVARS } __barebox_magicvar_end = .; diff --git a/arch/ppc/mach-mpc85xx/barebox.lds.S b/arch/ppc/mach-mpc85xx/barebox.lds.S index beebab3..0001972 100644 --- a/arch/ppc/mach-mpc85xx/barebox.lds.S +++ b/arch/ppc/mach-mpc85xx/barebox.lds.S @@ -105,6 +105,10 @@ .barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + __barebox_ratp_cmd_start = .; + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + __barebox_initcalls_start = .; .barebox_initcalls : { INITCALLS } __barebox_initcalls_end = .; diff --git a/arch/sandbox/board/barebox.lds.S b/arch/sandbox/board/barebox.lds.S index 0d67ab6..80e27fe 100644 --- a/arch/sandbox/board/barebox.lds.S +++ b/arch/sandbox/board/barebox.lds.S @@ -21,6 +21,11 @@ __barebox_cmd_start = .; __barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + + . = ALIGN(64); + __barebox_ratp_cmd_start = .; + __barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; } INSERT BEFORE .rodata; diff --git a/arch/x86/lib/barebox.lds.S b/arch/x86/lib/barebox.lds.S index 23d7546..6ee9342 100644 --- a/arch/x86/lib/barebox.lds.S +++ b/arch/x86/lib/barebox.lds.S @@ -171,6 +171,13 @@ . = ALIGN(4); } > barebox + .barebox_ratp_cmd : AT ( LOADADDR(.got) + SIZEOF (.got) ) { + __barebox_ratp_cmd_start = .; + BAREBOX_RATP_CMDS + __barebox_ratp_cmd_end = .; + . = ALIGN(4); + } > barebox + .barebox_magicvars : AT ( LOADADDR(.barebox_cmd) + SIZEOF (.barebox_cmd) ) { __barebox_magicvar_start = .; BAREBOX_MAGICVARS diff --git a/arch/x86/mach-efi/elf_ia32_efi.lds.S b/arch/x86/mach-efi/elf_ia32_efi.lds.S index 69f43f5..9477aa7 100644 --- a/arch/x86/mach-efi/elf_ia32_efi.lds.S +++ b/arch/x86/mach-efi/elf_ia32_efi.lds.S @@ -70,6 +70,11 @@ __barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + . = ALIGN(64); + __barebox_ratp_cmd_start = .; + __barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + . = ALIGN(4096); .dynamic : { *(.dynamic) } . = ALIGN(4096); diff --git a/arch/x86/mach-efi/elf_x86_64_efi.lds.S b/arch/x86/mach-efi/elf_x86_64_efi.lds.S index 93d34d1..90b6b9f 100644 --- a/arch/x86/mach-efi/elf_x86_64_efi.lds.S +++ b/arch/x86/mach-efi/elf_x86_64_efi.lds.S @@ -72,6 +72,11 @@ __barebox_cmd : { BAREBOX_CMDS } __barebox_cmd_end = .; + . = ALIGN(64); + __barebox_ratp_cmd_start = .; + __barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + __barebox_ratp_cmd_end = .; + . = ALIGN(4096); .dynamic : { *(.dynamic) } . = ALIGN(4096); diff --git a/common/Kconfig b/common/Kconfig index 25de248..af71d68 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -770,18 +770,7 @@ 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 - select CRC16 - select POLLER - depends on CONSOLE_FULL - 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. +source common/ratp/Kconfig config PARTITION bool diff --git a/common/Makefile b/common/Makefile index 5351ef0..a9abcd1 100644 --- a/common/Makefile +++ b/common/Makefile @@ -46,7 +46,7 @@ obj-$(CONFIG_SHELL_HUSH) += hush.o obj-$(CONFIG_SHELL_SIMPLE) += parser.o obj-$(CONFIG_STATE) += state/ -obj-$(CONFIG_RATP) += ratp.o +obj-$(CONFIG_RATP) += ratp/ obj-$(CONFIG_BOOTCHOOSER) += bootchooser.o obj-$(CONFIG_UIMAGE) += image.o uimage.o obj-$(CONFIG_FITIMAGE) += image-fit.o @@ -60,7 +60,6 @@ obj-$(CONFIG_FIRMWARE) += firmware.o obj-$(CONFIG_UBIFORMAT) += ubiformat.o obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o -obj-$(CONFIG_CONSOLE_RATP) += ratp.o obj-$(CONFIG_BOOT) += boot.o ifdef CONFIG_PASSWORD diff --git a/common/module.lds.S b/common/module.lds.S index a03d04f..f3dbb12 100644 --- a/common/module.lds.S +++ b/common/module.lds.S @@ -35,6 +35,8 @@ .got : { *(.got) } .barebox_cmd : { BAREBOX_CMDS } + .barebox_ratp_cmd : { BAREBOX_RATP_CMDS } + . = ALIGN(4); .bss : { *(.bss) } } diff --git a/common/ratp.c b/common/ratp.c deleted file mode 100644 index 80863f8..0000000 --- a/common/ratp.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * 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; - struct console_device ratp_console; - int have_synch; - 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_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_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 barebox_ratp_command_run(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_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); -} - -int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx) -{ - struct ratp_ctx *ctx = ratp_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 (!cdev->getc || !cdev->putc) - return -EINVAL; - - if (ratp_ctx) { - ctx = ratp_ctx; - } else { - ctx = xzalloc(sizeof(*ctx)); - ratp_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_ctx && ratp_ctx->cdev) - ratp_console_unregister(ratp_ctx); -} -predevshutdown_exitcall(barebox_ratp_close); diff --git a/common/ratp/Kconfig b/common/ratp/Kconfig new file mode 100644 index 0000000..93ff75d --- /dev/null +++ b/common/ratp/Kconfig @@ -0,0 +1,14 @@ + +config CONSOLE_RATP + bool + select RATP + select CRC16 + select POLLER + depends on CONSOLE_FULL + 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. + diff --git a/common/ratp/Makefile b/common/ratp/Makefile new file mode 100644 index 0000000..2c6d674 --- /dev/null +++ b/common/ratp/Makefile @@ -0,0 +1,6 @@ +obj-y += ratp.o +obj-y += ping.o +obj-y += getenv.o +obj-y += md.o +obj-y += mw.o +obj-y += reset.o diff --git a/common/ratp/getenv.c b/common/ratp/getenv.c new file mode 100644 index 0000000..b409634 --- /dev/null +++ b/common/ratp/getenv.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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. + * + */ + +/* + * RATP getenv + */ + +#include +#include +#include +#include + +static int ratp_cmd_getenv(const struct ratp_bb *req, int req_len, + struct ratp_bb **rsp, int *rsp_len) +{ + int dlen = req_len - sizeof (struct ratp_bb); + char *varname; + const char *value; + + varname = xstrndup ((const char *)req->data, dlen); + value = getenv (varname); + free (varname); + + dlen = strlen (value); + + *rsp_len = sizeof(struct ratp_bb) + dlen; + *rsp = xzalloc(*rsp_len); + (*rsp)->type = cpu_to_be16(BB_RATP_TYPE_GETENV_RETURN); + memcpy ((*rsp)->data, value, dlen); + return 0; +} + +BAREBOX_RATP_CMD_START(GETENV) + .request_id = BB_RATP_TYPE_GETENV, + .response_id = BB_RATP_TYPE_GETENV_RETURN, + .cmd = ratp_cmd_getenv +BAREBOX_RATP_CMD_END 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/common/ratp/ping.c b/common/ratp/ping.c new file mode 100644 index 0000000..cc29ea3 --- /dev/null +++ b/common/ratp/ping.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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. + * + */ + +/* + * RATP ping + */ + +#include +#include +#include + +static int ratp_cmd_ping(const struct ratp_bb *req, int req_len, + struct ratp_bb **rsp, int *rsp_len) +{ + /* Just build response */ + *rsp_len = sizeof(struct ratp_bb); + *rsp = xzalloc(*rsp_len); + (*rsp)->type = cpu_to_be16(BB_RATP_TYPE_PONG); + return 0; +} + +BAREBOX_RATP_CMD_START(PING) + .request_id = BB_RATP_TYPE_PING, + .response_id = BB_RATP_TYPE_PONG, + .cmd = ratp_cmd_ping +BAREBOX_RATP_CMD_END diff --git a/common/ratp/ratp.c b/common/ratp/ratp.c new file mode 100644 index 0000000..fae9cec --- /dev/null +++ b/common/ratp/ratp.c @@ -0,0 +1,482 @@ +/* + * 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 + +LIST_HEAD(ratp_command_list); +EXPORT_SYMBOL(ratp_command_list); + +#define for_each_ratp_command(cmd) list_for_each_entry(cmd, &ratp_command_list, list) + +struct ratp_bb_command_return { + uint32_t errno; +}; + +struct ratp_ctx { + struct console_device *cdev; + struct ratp ratp; + struct console_device ratp_console; + int have_synch; + 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 compare_ratp_command(struct list_head *a, struct list_head *b) +{ + int id_a = list_entry(a, struct ratp_command, list)->request_id; + int id_b = list_entry(b, struct ratp_command, list)->request_id; + + return (id_a - id_b); +} + +int register_ratp_command(struct ratp_command *cmd) +{ + debug("register ratp command: request %hu, response %hu\n", + cmd->request_id, cmd->response_id); + list_add_sort(&cmd->list, &ratp_command_list, compare_ratp_command); + return 0; +} +EXPORT_SYMBOL(register_ratp_command); + +struct ratp_command *find_ratp_request(uint16_t request_id) +{ + struct ratp_command *cmdtp; + + for_each_ratp_command(cmdtp) + if (request_id == cmdtp->request_id) + return cmdtp; + + return NULL; /* not found */ +} + +extern struct ratp_command __barebox_ratp_cmd_start; +extern struct ratp_command __barebox_ratp_cmd_end; + +static int init_ratp_command_list(void) +{ + struct ratp_command *cmdtp; + + for (cmdtp = &__barebox_ratp_cmd_start; + cmdtp != &__barebox_ratp_cmd_end; + cmdtp++) + register_ratp_command(cmdtp); + + return 0; +} + +late_initcall(init_ratp_command_list); + +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 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 char *ratp_command; +static struct ratp_ctx *ratp_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); + int ret = 0; + uint16_t type = be16_to_cpu(rbb->type); + struct ratp_command *cmd; + + /* See if there's a command registered to this type */ + cmd = find_ratp_request(type); + if (cmd) { + struct ratp_bb *rsp = NULL; + int rsp_len = 0; + + ret = cmd->cmd(rbb, len, &rsp, &rsp_len); + if (!ret) + ret = ratp_send(&ctx->ratp, rsp, rsp_len); + + free(rsp); + return ret; + } + + switch (type) { + case BB_RATP_TYPE_COMMAND: + if (!IS_ENABLED(CONFIG_CONSOLE_RATP) || ratp_command) + return 0; + + ratp_command = xstrndup((const char *)rbb->data, dlen); + ratp_ctx = ctx; + pr_debug("got command: %s\n", ratp_command); + + break; + + case BB_RATP_TYPE_COMMAND_RETURN: + break; + + case BB_RATP_TYPE_CONSOLEMSG: + if (!IS_ENABLED(CONFIG_CONSOLE_RATP)) + return 0; + + kfifo_put(ctx->console_recv_fifo, rbb->data, dlen); + 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 barebox_ratp_command_run(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_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; + + if (IS_ENABLED(CONFIG_CONSOLE_RATP)) + 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); +} + +int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx) +{ + struct ratp_ctx *ctx = ratp_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 (!cdev->getc || !cdev->putc) + return -EINVAL; + + if (ratp_ctx) { + ctx = ratp_ctx; + } else { + ctx = xzalloc(sizeof(*ctx)); + ratp_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_ctx && ratp_ctx->cdev) + ratp_console_unregister(ratp_ctx); +} +predevshutdown_exitcall(barebox_ratp_close); diff --git a/common/ratp/reset.c b/common/ratp/reset.c new file mode 100644 index 0000000..ca8be4e --- /dev/null +++ b/common/ratp/reset.c @@ -0,0 +1,55 @@ +/* + * reset.c - reset the cpu + * + * Copyright (c) 2007 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 + +struct ratp_bb_reset { + struct ratp_bb header; + uint8_t force; +} __attribute__((packed)); + +static int ratp_cmd_reset(const struct ratp_bb *req, int req_len, + struct ratp_bb **rsp, int *rsp_len) +{ + struct ratp_bb_reset *reset_req = (struct ratp_bb_reset *)req; + + if (req_len < sizeof (*reset_req)) { + printf ("ratp reset ignored: size mismatch (%d < %zu)\n", req_len, sizeof (*reset_req)); + return 2; + } + + debug("running reset %s\n", reset_req->force ? "(forced)" : ""); + + if (!reset_req->force) + shutdown_barebox(); + + restart_machine(); + /* Not reached */ + return 1; +} + +BAREBOX_RATP_CMD_START(RESET) + .request_id = BB_RATP_TYPE_RESET, + .cmd = ratp_cmd_reset +BAREBOX_RATP_CMD_END diff --git a/fs/Kconfig b/fs/Kconfig index 57f2676..3512000 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -94,7 +94,7 @@ config FS_RATP bool - depends on CONSOLE_RATP + depends on RATP prompt "RATP filesystem support" help This enables support for transferring files over RATP. A host can diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h index c8a919b..74d3ca4 100644 --- a/include/asm-generic/barebox.lds.h +++ b/include/asm-generic/barebox.lds.h @@ -44,6 +44,8 @@ #define BAREBOX_CMDS KEEP(*(SORT_BY_NAME(.barebox_cmd*))) +#define BAREBOX_RATP_CMDS KEEP(*(SORT_BY_NAME(.barebox_ratp_cmd*))) + #define BAREBOX_SYMS KEEP(*(__usymtab)) #define BAREBOX_MAGICVARS KEEP(*(SORT_BY_NAME(.barebox_magicvar*))) diff --git a/include/ratp_bb.h b/include/ratp_bb.h index f485f7d..3a80cf6 100644 --- a/include/ratp_bb.h +++ b/include/ratp_bb.h @@ -1,6 +1,29 @@ #ifndef __RATP_BB_H #define __RATP_BB_H +#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 +#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 +#define BB_RATP_TYPE_RESET 14 + +struct ratp_bb { + uint16_t type; + uint16_t flags; + uint8_t data[]; +}; + struct ratp_bb_pkt { unsigned int len; uint8_t data[]; @@ -11,4 +34,33 @@ int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx); int barebox_ratp_fs_mount(const char *path); +/* + * RATP commands definition + */ + +struct ratp_command { + struct list_head list; + uint16_t request_id; + uint16_t response_id; + int (*cmd)(const struct ratp_bb *req, + int req_len, + struct ratp_bb **rsp, + int *rsp_len); +} +#ifdef __x86_64__ +/* This is required because the linker will put symbols on a 64 bit alignment */ +__attribute__((aligned(64))) +#endif +; + +#define BAREBOX_RATP_CMD_START(_name) \ +extern const struct ratp_command __barebox_ratp_cmd_##_name; \ +const struct ratp_command __barebox_ratp_cmd_##_name \ + __attribute__ ((unused,section (".barebox_ratp_cmd_" __stringify(_name)))) = { + +#define BAREBOX_RATP_CMD_END \ +}; + +int register_ratp_command(struct ratp_command *cmd); + #endif /* __RATP_BB_H */ diff --git a/lib/Kconfig b/lib/Kconfig index dca93b8..4e9213f 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -95,7 +95,7 @@ config RATP select CRC16 - bool + bool "RATP protocol support" help Reliable Asynchronous Transfer Protocol (RATP) is a protocol for reliably transferring packets over serial links described in RFC916. This implementation diff --git a/lib/readline.c b/lib/readline.c index 1e380ab..904a776 100644 --- a/lib/readline.c +++ b/lib/readline.c @@ -202,7 +202,7 @@ while (1) { while (!tstc()) { poller_call(); - if (IS_ENABLED(CONFIG_RATP)) + if (IS_ENABLED(CONFIG_CONSOLE_RATP)) barebox_ratp_command_run(); } diff --git a/scripts/remote/controller.py b/scripts/remote/controller.py index a7257ec..2ed8346 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_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) + elif p_type == BBType.reset: + logging.debug("received: reset") + return BBPacketReset(raw=data) else: logging.debug("received: UNKNOWN") return BBPacket(raw=data) @@ -112,6 +124,21 @@ 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 reset(self, force): + self._send(BBPacketReset(force=force)) + def close(self): self.conn.close() diff --git a/scripts/remote/main.py b/scripts/remote/main.py index 79203df..38d280b 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,34 @@ 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_reset(args): + ctrl = get_controller(args) + ctrl.reset(args.force) + ctrl.close() + return 0 + + def handle_listen(args): port = serial.serial_for_url(args.port, args.baudrate) conn = SerialRatpConnection(port) @@ -118,6 +147,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 +176,24 @@ 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_reset = subparsers.add_parser('reset', help="run reset command") +parser_reset_force = parser_reset.add_mutually_exclusive_group(required=False) +parser_reset_force.add_argument('--force', dest='force', action='store_true') +parser_reset_force.add_argument('--no-force', dest='force', action='store_false') +parser_reset.set_defaults(func=handle_reset,force=False) + 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..729f2e6 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,11 @@ getenv_return = 7 fs = 8 fs_return = 9 + md = 10 + md_return = 11 + mw = 12 + mw_return = 13 + reset = 14 class BBPacket(object): @@ -152,3 +158,102 @@ 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) + + +class BBPacketReset(BBPacket): + def __init__(self, raw=None, force=None): + self.force = force + super(BBPacketReset, self).__init__(BBType.reset, raw=raw) + + def __repr__(self): + return "BBPacketReset(force=%c)" % (self.force) + + def _unpack_payload(self, payload): + self.force = struct.unpack("?", payload[:1]) + + def _pack_payload(self): + return struct.pack("?", self.force)