summaryrefslogtreecommitdiff
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
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>
-rw-r--r--chip/lm4/config.h2
-rw-r--r--common/uart_buffering.c86
-rw-r--r--include/ec_commands.h14
-rw-r--r--util/ectool.c31
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},