summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--baseboard/kukui/baseboard.h1
-rw-r--r--common/chipset.c27
-rw-r--r--common/main.c16
-rw-r--r--common/uart_buffering.c34
-rw-r--r--core/cortex-m0/ec.lds.S28
-rw-r--r--include/chipset.h5
-rw-r--r--include/config.h9
-rw-r--r--include/link_defs.h7
-rw-r--r--include/uart.h5
-rw-r--r--include/util.h3
10 files changed, 126 insertions, 9 deletions
diff --git a/baseboard/kukui/baseboard.h b/baseboard/kukui/baseboard.h
index ee8428f03f..b0313bf10c 100644
--- a/baseboard/kukui/baseboard.h
+++ b/baseboard/kukui/baseboard.h
@@ -98,6 +98,7 @@
#define CONFIG_FORCE_CONSOLE_RESUME
#define CONFIG_HOST_COMMAND_STATUS
#define CONFIG_CMD_AP_RESET_LOG
+#define CONFIG_PRESERVE_LOGS
/* Required for FAFT */
#define CONFIG_CMD_BUTTON
diff --git a/common/chipset.c b/common/chipset.c
index 427ea37940..9c11abe9c0 100644
--- a/common/chipset.c
+++ b/common/chipset.c
@@ -10,6 +10,7 @@
#include "console.h"
#include "ec_commands.h"
#include "host_command.h"
+#include "link_defs.h"
#include "system.h"
#include "task.h"
#include "timer.h"
@@ -60,10 +61,29 @@ DECLARE_HOST_COMMAND(EC_CMD_AP_RESET,
#ifdef CONFIG_CMD_AP_RESET_LOG
static struct mutex reset_log_mutex;
-static int next_reset_log;
+static int next_reset_log __preserved_logs(next_reset_log);
static uint32_t ap_resets_since_ec_boot;
/* keep reset_logs size a power of 2 */
-static struct ap_reset_log_entry reset_logs[4];
+static struct ap_reset_log_entry
+ reset_logs[4] __preserved_logs(reset_logs);
+static int reset_log_checksum __preserved_logs(reset_log_checksum);
+
+/* Calculate reset log checksum */
+static int calc_reset_log_checksum(void)
+{
+ return next_reset_log ^ reset_logs[next_reset_log].reset_cause;
+}
+
+/* Initialize reset logs and next reset log */
+void init_reset_log(void)
+{
+ if (next_reset_log < 0 || next_reset_log >= ARRAY_SIZE(reset_logs) ||
+ reset_log_checksum != calc_reset_log_checksum()) {
+ reset_log_checksum = 0;
+ next_reset_log = 0;
+ memset(&reset_logs, 0, sizeof(reset_logs));
+ }
+}
void report_ap_reset(enum chipset_shutdown_reason reason)
{
@@ -76,6 +96,9 @@ void report_ap_reset(enum chipset_shutdown_reason reason)
next_reset_log &= ARRAY_SIZE(reset_logs) - 1;
ap_resets_since_ec_boot++;
mutex_unlock(&reset_log_mutex);
+
+ /* Update checksum */
+ reset_log_checksum = calc_reset_log_checksum();
}
static int host_command_get_uptime_info(struct host_cmd_handler_args *args)
diff --git a/common/main.c b/common/main.c
index 069b20dd17..c5e63e7faa 100644
--- a/common/main.c
+++ b/common/main.c
@@ -39,6 +39,22 @@
test_mockable __keep int main(void)
{
+ if (IS_ENABLED(CONFIG_PRESERVE_LOGS)) {
+ /*
+ * Initialize tx buffer head and tail. This needs to be done
+ * before any updates of uart tx input because we need to
+ * verify if the values remain the same after every EC reset.
+ */
+ uart_init_buffer();
+
+ /*
+ * Initialize reset logs. Needs to be done before any updates of
+ * reset logs because we need to verify if the values remain
+ * the same after every EC reset.
+ */
+ init_reset_log();
+ }
+
/*
* Pre-initialization (pre-verified boot) stage. Initialization at
* this level should do as little as possible, because verified boot
diff --git a/common/uart_buffering.c b/common/uart_buffering.c
index 9eb6db5cdf..f1c68e7773 100644
--- a/common/uart_buffering.c
+++ b/common/uart_buffering.c
@@ -37,9 +37,10 @@
(CONFIG_UART_RX_DMA_RECHECKS + 1))
/* Transmit and receive buffers */
-static volatile char tx_buf[CONFIG_UART_TX_BUF_SIZE] __uncached;
-static volatile int tx_buf_head;
-static volatile int tx_buf_tail;
+static volatile char tx_buf[CONFIG_UART_TX_BUF_SIZE]
+ __uncached __preserved_logs(tx_buf);
+static volatile int tx_buf_head __preserved_logs(tx_buf_head);
+static volatile int tx_buf_tail __preserved_logs(tx_buf_tail);
static volatile char rx_buf[CONFIG_UART_RX_BUF_SIZE] __uncached;
static volatile int rx_buf_head;
static volatile int rx_buf_tail;
@@ -47,6 +48,24 @@ static int tx_snapshot_head;
static int tx_snapshot_tail;
static int tx_last_snapshot_head;
static int tx_next_snapshot_head;
+static int tx_checksum __preserved_logs(tx_checksum);
+
+static int uart_buffer_calc_checksum(void)
+{
+ return tx_buf_head ^ tx_buf_tail;
+}
+
+
+void uart_init_buffer(void)
+{
+ if (tx_checksum != uart_buffer_calc_checksum() ||
+ !IN_RANGE(tx_buf_head, 0, CONFIG_UART_TX_BUF_SIZE) ||
+ !IN_RANGE(tx_buf_tail, 0, CONFIG_UART_TX_BUF_SIZE)) {
+ tx_buf_head = 0;
+ tx_buf_tail = 0;
+ tx_checksum = 0;
+ }
+}
/**
* Put a single character into the transmit buffer.
@@ -92,6 +111,9 @@ static int __tx_char(void *context, int c)
tx_buf[tx_buf_head] = c;
tx_buf_head = tx_buf_next;
+
+ if (IS_ENABLED(CONFIG_PRESERVE_LOGS))
+ tx_checksum = uart_buffer_calc_checksum();
#endif
return 0;
}
@@ -121,6 +143,9 @@ void uart_process_output(void)
tx_buf_tail = (tx_buf_tail + tx_dma_in_progress) &
(CONFIG_UART_TX_BUF_SIZE - 1);
tx_dma_in_progress = 0;
+
+ if (IS_ENABLED(CONFIG_PRESERVE_LOGS))
+ tx_checksum = uart_buffer_calc_checksum();
}
/* Disable DMA-done interrupt if nothing to send */
@@ -147,6 +172,9 @@ void uart_process_output(void)
while (uart_tx_ready() && (tx_buf_head != tx_buf_tail)) {
uart_write_char(tx_buf[tx_buf_tail]);
tx_buf_tail = TX_BUF_NEXT(tx_buf_tail);
+
+ if (IS_ENABLED(CONFIG_PRESERVE_LOGS))
+ tx_checksum = uart_buffer_calc_checksum();
}
/* If output buffer is empty, disable transmit interrupt */
diff --git a/core/cortex-m0/ec.lds.S b/core/cortex-m0/ec.lds.S
index 42e0b2e034..953433459a 100644
--- a/core/cortex-m0/ec.lds.S
+++ b/core/cortex-m0/ec.lds.S
@@ -191,16 +191,36 @@ SECTIONS
. = ALIGN(4);
} > FLASH
__data_lma_start = . ;
-
- .bss : {
+ .vtable : {
/*
- * Vector table must be at the beginning of bss section. The vector
+ * Vector table must be at the base of SRAM. The vector
* table section contains a RAM copy of the vector table used on
* STM chips for relocating the vector table.
*/
. = ALIGN(8);
- __bss_start = .;
*(.bss.vector_table)
+ . = ALIGN(8);
+ } > IRAM
+
+#ifdef CONFIG_PRESERVE_LOGS
+ .preserve_logs(NOLOAD) : {
+ /*
+ * The size of the vector table is fixed. Thus, the address of
+ * the preserved logs is also fixed.
+ */
+ . = ALIGN(8);
+ *(SORT(.preserved_logs.*))
+ . = ALIGN(8);
+ __preserved_logs_end = .;
+ } > IRAM
+
+ ASSERT((SIZEOF(.vtable) + SIZEOF(.preserve_logs) + CONFIG_RAM_BASE) ==
+ __preserved_logs_end, "preserve_logs must be right after vtable")
+#endif
+
+ .bss : {
+ . = ALIGN(8);
+ __bss_start = .;
/* Stacks must be 64-bit aligned */
. = ALIGN(8);
*(.bss.system_stack)
diff --git a/include/chipset.h b/include/chipset.h
index bb0d7b4943..05eeb844a1 100644
--- a/include/chipset.h
+++ b/include/chipset.h
@@ -263,3 +263,8 @@ static inline void report_ap_reset(enum chipset_shutdown_reason reason) { }
#endif /* !CONFIG_CMD_AP_RESET_LOG */
#endif /* __CROS_EC_CHIPSET_H */
+
+/**
+ * Initialize reset logs and next reset log.
+ */
+void init_reset_log(void);
diff --git a/include/config.h b/include/config.h
index 377f89d603..5bb89a7a46 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3525,6 +3525,15 @@
*/
#undef CONFIG_UART_PAD_SWITCH
+/**
+ * This will only be used for Kukui and cortex-m0. Preserve EC reset logs and
+ * console logs on SRAM so that the logs will be preserved after EC shutting
+ * down or sysjumped. It will keep the contents across EC resets, so we have
+ * more information about system states. The contents on SRAM will be cleared
+ * when checksum or sanity check fails.
+ */
+#undef CONFIG_PRESERVE_LOGS
+
/*
* UART receive buffer size in bytes. Must be a power of 2 for macros in
* common/uart_buffering.c to work properly. Must be larger than
diff --git a/include/link_defs.h b/include/link_defs.h
index 28ea0113e1..5ea500516f 100644
--- a/include/link_defs.h
+++ b/include/link_defs.h
@@ -134,3 +134,10 @@ extern void *__dram_bss_end;
#endif
#endif /* __CROS_EC_LINK_DEFS_H */
+
+#ifdef CONFIG_PRESERVE_LOGS
+#define __preserved_logs(name) \
+ __attribute__((section(".preserved_logs." STRINGIFY(name))))
+#else
+#define __preserved_logs(name)
+#endif
diff --git a/include/uart.h b/include/uart.h
index d5493544c2..66561b09a7 100644
--- a/include/uart.h
+++ b/include/uart.h
@@ -352,3 +352,8 @@ int uart_console_read_buffer(uint8_t type,
uint16_t *write_count);
#endif /* __CROS_EC_UART_H */
+
+/**
+ * Initialize tx buffer head and tail
+ */
+void uart_init_buffer(void);
diff --git a/include/util.h b/include/util.h
index 04acffd988..60bb00510a 100644
--- a/include/util.h
+++ b/include/util.h
@@ -55,6 +55,9 @@ extern "C" {
/* True of x is a power of two */
#define POWER_OF_TWO(x) ((x) && !((x) & ((x) - 1)))
+/* Macro to check if the value is in range */
+#define IN_RANGE(x, min, max) ((x) >= (min) && (x) < (max))
+
/*
* macros for integer division with various rounding variants
* default integer division rounds down.