summaryrefslogtreecommitdiff
path: root/common/uart_buffering.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-08-09 15:17:24 -0700
committerGerrit <chrome-bot@google.com>2012-08-09 17:40:38 -0700
commit6cd9e1124b2432f7b6d8693cc4bd170514cfd689 (patch)
treed418d284bd196d476426287c472dec8e5142ab43 /common/uart_buffering.c
parent371d06bbfdf56fad142539c9a72759e53d5bc26a (diff)
downloadchrome-ec-6cd9e1124b2432f7b6d8693cc4bd170514cfd689.tar.gz
Add ectool command to read snapshot of EC's console output
BUG=chrome-os-partner:12483 TEST=from root shell, 'ectool console', then on the ec console, type 'help list' a few times to generate lots of debug output, then repeat 'ectool console'. Then on EC console, 'syslock', and then 'ectool console' should fail. Change-Id: Ie1c74c7e35d6b8228615d20192fd90093977de64 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/29825 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Diffstat (limited to 'common/uart_buffering.c')
-rw-r--r--common/uart_buffering.c86
1 files changed, 85 insertions, 1 deletions
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));