diff options
-rw-r--r-- | chip/lm4/config.h | 2 | ||||
-rw-r--r-- | common/uart_buffering.c | 86 | ||||
-rw-r--r-- | include/ec_commands.h | 14 | ||||
-rw-r--r-- | util/ectool.c | 31 |
4 files changed, 131 insertions, 2 deletions
diff --git a/chip/lm4/config.h b/chip/lm4/config.h index b02a229218..8433ee1637 100644 --- a/chip/lm4/config.h +++ b/chip/lm4/config.h @@ -13,7 +13,7 @@ #define CONFIG_IRQ_COUNT 132 /* Use a bigger console output buffer */ -#define CONFIG_UART_TX_BUF_SIZE 1024 +#define CONFIG_UART_TX_BUF_SIZE 8192 /****************************************************************************/ /* Memory mapping */ diff --git a/common/uart_buffering.c b/common/uart_buffering.c index 4e7accec66..1dd56aed60 100644 --- a/common/uart_buffering.c +++ b/common/uart_buffering.c @@ -9,7 +9,9 @@ #include "common.h" #include "console.h" +#include "host_command.h" #include "printf.h" +#include "system.h" #include "task.h" #include "uart.h" #include "util.h" @@ -39,7 +41,8 @@ #define CMD_HIST_NEXT(i) (((i) + 1) & (HISTORY_SIZE - 1)) #define CMD_HIST_PREV(i) (((i) - 1) & (HISTORY_SIZE - 1)) -/* Macro to calculate difference of pointers in the circular receive buffer. */ +/* Macros to calculate difference of pointers in the circular buffers. */ +#define TX_BUF_DIFF(i, j) (((i) - (j)) & (CONFIG_UART_TX_BUF_SIZE - 1)) #define RX_BUF_DIFF(i, j) (((i) - (j)) & (CONFIG_UART_RX_BUF_SIZE - 1)) /* ASCII control character; for example, CTRL('C') = ^C */ @@ -57,6 +60,8 @@ static volatile int rx_cur_buf_tail; static volatile int rx_cur_buf_head; static volatile int rx_cur_buf_ptr; static int last_rx_was_cr; +static int tx_snapshot_head; +static int tx_snapshot_tail; static enum { ESC_OUTSIDE, /* Not in escape code */ @@ -748,3 +753,82 @@ int uart_gets(char *dest, int size) /* Return the length we got */ return got; } + +/*****************************************************************************/ +/* Host commands */ + +static int host_command_console_snapshot(struct host_cmd_handler_args *args) +{ + /* + * Only allowed on unlocked system, since console output contains + * keystroke data. + */ + if (system_is_locked()) + return EC_ERROR_ACCESS_DENIED; + + /* Assume the whole circular buffer is full */ + tx_snapshot_head = tx_buf_head; + tx_snapshot_tail = TX_BUF_NEXT(tx_snapshot_head); + + /* + * Immediately skip any unused bytes. This doesn't always work, + * because a higher-priority task or interrupt handler can write to the + * buffer while we're scanning it. This is acceptable because this + * command is only for debugging, and the failure mode is a bit of + * garbage at the beginning of the saved output. The saved buffer + * could also be overwritten by the head coming completely back around + * before we finish. The alternative would be to make a full copy of + * the transmit buffer, but that requires a lot of RAM. + */ + while (tx_snapshot_tail != tx_snapshot_head) { + if (tx_buf[tx_snapshot_tail]) + break; + tx_snapshot_tail = TX_BUF_NEXT(tx_snapshot_tail); + } + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_CONSOLE_SNAPSHOT, + host_command_console_snapshot, + EC_VER_MASK(0)); + +static int host_command_console_read(struct host_cmd_handler_args *args) +{ + char *dest = (char *)args->response; + + /* + * Only allowed on unlocked system, since console output contains + * keystroke data. + */ + if (system_is_locked()) + return EC_ERROR_ACCESS_DENIED; + + /* If no snapshot data, return empty response */ + if (tx_snapshot_head == tx_snapshot_tail) + return EC_RES_SUCCESS; + + /* Copy data to response */ + while (tx_snapshot_tail != tx_snapshot_head && + args->response_size < args->response_max - 1) { + + /* + * Copy only non-zero bytes, so that we don't copy unused + * bytes if the buffer hasn't completely rolled at boot. + */ + if (tx_buf[tx_snapshot_tail]) { + *(dest++) = tx_buf[tx_snapshot_tail]; + args->response_size++; + } + + tx_snapshot_tail = TX_BUF_NEXT(tx_snapshot_tail); + } + + /* Null-terminate */ + *(dest++) = '\0'; + args->response_size++; + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_CONSOLE_READ, + host_command_console_read, + EC_VER_MASK(0)); diff --git a/include/ec_commands.h b/include/ec_commands.h index 3a602ea1ba..bda5995d55 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -918,6 +918,20 @@ struct ec_params_force_idle { } __packed; /*****************************************************************************/ +/* Console commands. Only available when flash write protect is unlocked. */ + +/* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */ +#define EC_CMD_CONSOLE_SNAPSHOT 0x97 + +/* + * Read next chunk of data from saved snapshot. + * + * Response is null-terminated string. Empty string, if there is no more + * remaining output. + */ +#define EC_CMD_CONSOLE_READ 0x98 + +/*****************************************************************************/ /* System commands */ /* diff --git a/util/ectool.c b/util/ectool.c index b0375c1e56..7478fa86c0 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -36,6 +36,8 @@ const char help_str[] = " Prints chip info\n" " cmdversions <cmd>\n" " Prints supported version mask for a command number\n" + " console\n" + " Prints the last output to the EC debug console\n" " echash [CMDS]\n" " Various EC hash commands\n" " eventclear <mask>\n" @@ -2072,6 +2074,34 @@ int cmd_rtc_set(int argc, char *argv[]) return 0; } +int cmd_console(int argc, char *argv[]) +{ + char out[EC_HOST_PARAM_SIZE]; + int rv; + + /* Snapshot the EC console */ + rv = ec_command(EC_CMD_CONSOLE_SNAPSHOT, 0, NULL, 0, NULL, 0); + if (rv < 0) + return rv; + + /* Loop and read from the snapshot until it's done */ + while (1) { + rv = ec_command(EC_CMD_CONSOLE_READ, 0, + NULL, 0, out, sizeof(out)); + if (rv < 0) + return rv; + + if (rv == 0) + break; /* Empty response means done */ + + /* Make sure output is null-terminated, then dump it */ + out[sizeof(out) - 1] = '\0'; + fputs(out, stdout); + } + printf("\n"); + return 0; +} + struct command { const char *name; @@ -2086,6 +2116,7 @@ const struct command commands[] = { {"chargeforceidle", cmd_charge_force_idle}, {"chipinfo", cmd_chipinfo}, {"cmdversions", cmd_cmdversions}, + {"console", cmd_console}, {"echash", cmd_ec_hash}, {"eventclear", cmd_host_event_clear}, {"eventclearb", cmd_host_event_clear_b}, |