From 744a123033a043f7b10b7937ed7814fa1505d3fd Mon Sep 17 00:00:00 2001 From: Namyoon Woo Date: Sat, 7 Mar 2020 21:34:18 -0800 Subject: introducing an unittest of EC-EFS This patch adds a test case for EC-EFS functions. BUG=b:150650877 BRANCH=cr50 TEST=make run-ec_comm make runhosttests make buildall -j Signed-off-by: Namyoon Woo Change-Id: I90cdc3aa73cf8946da4cf094de5ca0adfaaa0a7c Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2096338 Reviewed-by: Vadim Bendebury --- board/host/board.c | 25 +++ board/host/board.h | 16 ++ board/host/gpio.inc | 5 + board/host/tpm_nvmem_ops.h | 31 ++++ chip/host/build.mk | 4 +- chip/host/registers.c | 36 +++++ chip/host/registers.h | 5 + chip/host/uart.c | 84 +++++++--- chip/host/uartn.h | 26 ++++ common/ec_efs.c | 7 + include/ec_comm.h | 5 + include/test_util.h | 5 + test/build.mk | 2 + test/ec_comm.c | 374 +++++++++++++++++++++++++++++++++++++++++++++ test/ec_comm.tasklist | 9 ++ test/test_config.h | 5 + 16 files changed, 620 insertions(+), 19 deletions(-) create mode 100644 board/host/tpm_nvmem_ops.h create mode 100644 chip/host/registers.c create mode 100644 chip/host/uartn.h create mode 100644 test/ec_comm.c create mode 100644 test/ec_comm.tasklist diff --git a/board/host/board.c b/board/host/board.c index 80ac631d19..cccb6f15ec 100644 --- a/board/host/board.c +++ b/board/host/board.c @@ -5,6 +5,7 @@ /* Emulator board-specific configuration */ #include "button.h" +#include "ec_comm.h" #include "extpower.h" #include "gpio.h" #include "host_command.h" @@ -89,3 +90,27 @@ int board_get_entropy(void *buffer, int len) return 1; } #endif + +test_mockable void ccd_update_state(void) +{ + +} + +test_mockable void ec_comm_packet_mode_en(enum gpio_signal unsed) +{ + +} + +test_mockable void ec_comm_packet_mode_dis(enum gpio_signal unsed) +{ + +} + +int board_has_ec_cr50_comm_support(void) +{ +#ifdef CONFIG_EC_EFS_SUPPORT + return 1; +#else + return 0; +#endif +} diff --git a/board/host/board.h b/board/host/board.h index ad65749c3d..8ccdd40b80 100644 --- a/board/host/board.h +++ b/board/host/board.h @@ -77,10 +77,26 @@ enum { #define CONFIG_SPI_MASTER #define CONFIG_SPI_FP_PORT 1 /* SPI1: third master config */ +/* UART indexes (use define rather than enum to expand them) */ +enum { + UART_DEFAULT = 0, + UART_CR50 = 0, + UART_AP = 1, + UART_EC = 2, + UART_COUNT, + + UART_NULL = 0xff, +}; + #define CONFIG_RNG void fps_event(enum gpio_signal signal); /* Let the tests always check the other NVMEM slot. */ static inline int board_nvmem_legacy_check_needed(void){ return 1; } +/* Mock functions for EC-CR50 communication test */ +int board_has_ec_cr50_comm_support(void); +void board_reboot_ec_deferred(int usec_delay); +void ccd_update_state(void); + #endif /* __CROS_EC_BOARD_H */ diff --git a/board/host/gpio.inc b/board/host/gpio.inc index 5a08172a07..bf2f974bd3 100644 --- a/board/host/gpio.inc +++ b/board/host/gpio.inc @@ -16,6 +16,11 @@ GPIO_INT(VOLUME_UP_L, PIN(0, 4), GPIO_INT_BOTH, button_interrupt) GPIO_INT(CHARGE_DONE, PIN(0, 5), GPIO_INT_BOTH, inductive_charging_interrupt) /* Fingerprint */ GPIO_INT(FPS_INT, PIN(0, 14), GPIO_INT_RISING, fps_event) +/* GPIOs for EC-CR50 communication */ +GPIO_INT(EC_PACKET_MODE_EN, PIN(0, 16), GPIO_INT_RISING, + ec_comm_packet_mode_en) +GPIO_INT(EC_PACKET_MODE_DIS, PIN(0, 17), GPIO_INT_FALLING, + ec_comm_packet_mode_dis) GPIO(EC_INT_L, PIN(0, 6), 0) GPIO(WP, PIN(0, 7), 0) diff --git a/board/host/tpm_nvmem_ops.h b/board/host/tpm_nvmem_ops.h new file mode 100644 index 0000000000..f2090f7733 --- /dev/null +++ b/board/host/tpm_nvmem_ops.h @@ -0,0 +1,31 @@ +/* + * Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __EC_BOARD_CR50_TPM_NVMEM_OPS_H +#define __EC_BOARD_CR50_TPM_NVMEM_OPS_H + +enum tpm_read_rv { + TPM_READ_SUCCESS, + TPM_READ_NOT_FOUND, + TPM_READ_TOO_SMALL, +}; + +enum tpm_write_rv { + TPM_WRITE_CREATED, + TPM_WRITE_UPDATED, + TPM_WRITE_FAIL, +}; + +enum tpm_nv_hidden_object { + TPM_HIDDEN_U2F_KEK, + TPM_HIDDEN_U2F_KH_SALT, +}; + +enum tpm_read_rv read_tpm_nvmem(uint16_t object_index, + uint16_t object_size, + void *obj_value); + +#endif /* ! __EC_BOARD_CR50_TPM_NVMEM_OPS_H */ diff --git a/chip/host/build.mk b/chip/host/build.mk index f57fe85502..f018c2a281 100644 --- a/chip/host/build.mk +++ b/chip/host/build.mk @@ -8,8 +8,8 @@ CORE:=host -chip-y=system.o gpio.o uart.o persistence.o flash.o lpc.o reboot.o i2c.o \ - clock.o spi_master.o trng.o +chip-y=clock.o flash.o gpio.o i2c.o lpc.o persistence.o reboot.o registers.o \ + spi_master.o system.o trng.o uart.o ifndef CONFIG_KEYBOARD_NOT_RAW chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o endif diff --git a/chip/host/registers.c b/chip/host/registers.c new file mode 100644 index 0000000000..fad062ea15 --- /dev/null +++ b/chip/host/registers.c @@ -0,0 +1,36 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Registers for test + */ +#include +#include +#include + +#include "common.h" +#include "registers.h" +#include "util.h" + +static struct faux_register_array { + const char * const name; + unsigned int var; +} mock_registers_[] = { + { + .name = GNAME(PMU, PWRDN_SCRATCH20), + }, + + /* Define registers as needed. */ +}; + +void *get_reg_addr(const char * const reg_name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mock_registers_); i++) + if (!strcmp(mock_registers_[i].name, reg_name)) + return &mock_registers_[i].var; + + fprintf(stderr, "Unknown register is accessed: %s\n", reg_name); + exit(1); +} diff --git a/chip/host/registers.h b/chip/host/registers.h index 7347ce04d3..87cd17d5fd 100644 --- a/chip/host/registers.h +++ b/chip/host/registers.h @@ -9,3 +9,8 @@ * There is no register for emulator, but this file exists to prevent * compilation failure if any file includes registers.h */ + +#define GNAME(mname, rname) "GC_ ## mname ## _ ## rname ## _NAME" +#define GREG32(mname, rname) REG32(get_reg_addr(GNAME(mname, rname))) + +void *get_reg_addr(const char * const reg_name); diff --git a/chip/host/uart.c b/chip/host/uart.c index 578924612f..4d505acf80 100644 --- a/chip/host/uart.c +++ b/chip/host/uart.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #include "task.h" #include "test_util.h" #include "uart.h" +#include "uartn.h" #include "util.h" static int stopped = 1; @@ -31,34 +33,69 @@ static int char_available; static struct queue const cached_char = QUEUE_NULL(INPUT_BUFFER_SIZE, char); #define CONSOLE_CAPTURE_SIZE 2048 -static char capture_buf[CONSOLE_CAPTURE_SIZE]; -static int capture_size; -static int capture_enabled; +static struct { + char buf[CONSOLE_CAPTURE_SIZE]; + int size; + int enabled; +} uart_capture[UART_COUNT]; -void test_capture_console(int enabled) + +static void putch_into_captured_buf(int uart, char c, int is_last) { - if (enabled == capture_enabled) + uart_capture[uart].buf[uart_capture[uart].size] = c; + if (!is_last) + uart_capture[uart].size++; +} + +void test_capture_uartn(int uart, int enabled) +{ + if (uart >= UART_COUNT) { + fprintf(stderr, "Unknown UART port accessed: %d\n", uart); + exit(1); + } + + if (enabled == uart_capture[uart].enabled) return; if (enabled) - capture_size = 0; + uart_capture[uart].size = 0; else - capture_buf[capture_size] = '\0'; + putch_into_captured_buf(uart, '\0', 1); - capture_enabled = enabled; + uart_capture[uart].enabled = enabled; } -static void test_capture_char(char c) +void test_capture_console(int enabled) +{ + test_capture_uartn(UART_DEFAULT, enabled); +} + +static void test_capture_char(int uart, char c) { - if (capture_size == CONSOLE_CAPTURE_SIZE) + if (uart >= UART_COUNT) { + fprintf(stderr, "Unknown UART port accessed: %d\n", uart); + exit(1); + } + + if (uart_capture[uart].size == CONSOLE_CAPTURE_SIZE) return; - capture_buf[capture_size++] = c; + + putch_into_captured_buf(uart, c, 0); } +const char *test_get_captured_uartn(int uart) +{ + if (uart >= UART_COUNT) { + fprintf(stderr, "Unknown UART port accessed: %d\n", uart); + exit(1); + } + + return uart_capture[uart].buf; +} const char *test_get_captured_console(void) { - return (const char *)capture_buf; + return test_get_captured_uartn(UART_DEFAULT); } static void uart_interrupt(void) @@ -90,7 +127,7 @@ int uart_tx_stopped(void) void uart_tx_flush(void) { - /* Nothing */ + uartn_tx_flush(UART_DEFAULT); } int uart_tx_ready(void) @@ -105,10 +142,7 @@ int uart_rx_available(void) void uart_write_char(char c) { - if (capture_enabled) - test_capture_char(c); - printf("%c", c); - fflush(stdout); + uartn_write_char(UART_DEFAULT, c); } int uart_read_char(void) @@ -193,3 +227,19 @@ void uart_init(void) stopped = 1; /* Not transmitting yet */ init_done = 1; } + +test_mockable void uartn_tx_flush(int uart_unused) +{ + /* Nothing */ +} + +test_mockable void uartn_write_char(int uart, char c) +{ + if (uart_capture[uart].enabled) + test_capture_char(uart, c); + + if (uart == UART_DEFAULT) { + printf("%c", c); + fflush(stdout); + } +} diff --git a/chip/host/uartn.h b/chip/host/uartn.h new file mode 100644 index 0000000000..5056e61bb7 --- /dev/null +++ b/chip/host/uartn.h @@ -0,0 +1,26 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __CROS_EC_UARTN_H +#define __CROS_EC_UARTN_H + +#include "uart.h" + +/** + * Flush the transmit FIFO. + */ +void uartn_tx_flush(int uart); + +/** + * Send a character to the UART data register. + * + * If the transmit FIFO is full, blocks until there is space. + * + * @param c Character to send. + */ +void uartn_write_char(int uart, char c); + + +#endif /* __CROS_EC_UARTN_H */ diff --git a/common/ec_efs.c b/common/ec_efs.c index b61ed87888..9cc4061882 100644 --- a/common/ec_efs.c +++ b/common/ec_efs.c @@ -280,3 +280,10 @@ void ec_efs_print_status(void) HEX_BUF(ec_efs_ctx.hash, SHA256_DIGEST_SIZE)); #endif } + +#ifdef BOARD_HOST +uint8_t ec_efs_get_boot_mode(void) +{ + return ec_efs_ctx.boot_mode; +} +#endif diff --git a/include/ec_comm.h b/include/ec_comm.h index 263d311e63..dee31df4be 100644 --- a/include/ec_comm.h +++ b/include/ec_comm.h @@ -42,4 +42,9 @@ void ec_efs_refresh(void); /* print EC-EFS status */ void ec_efs_print_status(void); +#ifdef BOARD_HOST +/* return the current boot mode. For test purpose only. */ +uint8_t ec_efs_get_boot_mode(void); +#endif + #endif /* __CROS_EC_COMM_H */ diff --git a/include/test_util.h b/include/test_util.h index 23034f918e..bfcd940cea 100644 --- a/include/test_util.h +++ b/include/test_util.h @@ -197,6 +197,11 @@ void test_chipset_on(void); /* Simulates chipset power off */ void test_chipset_off(void); +/* Start/stop capturing a specific UART output */ +void test_capture_uartn(int uart, int enabled); +/* Get captured a specific UART output */ +const char *test_get_captured_uartn(int uart); + /* Start/stop capturing console output */ void test_capture_console(int enabled); diff --git a/test/build.mk b/test/build.mk index 4284374df0..143041ee7f 100644 --- a/test/build.mk +++ b/test/build.mk @@ -23,6 +23,7 @@ test-list-host += charge_manager_drp_charging test-list-host += charge_ramp test-list-host += console_edit test-list-host += crc32 +test-list-host += ec_comm test-list-host += entropy test-list-host += extpwr_gpio test-list-host += fan @@ -101,6 +102,7 @@ charge_manager_drp_charging-y=charge_manager.o charge_ramp-y+=charge_ramp.o console_edit-y=console_edit.o crc32-y=crc32.o +ec_comm-y=ec_comm.o entropy-y=entropy.o extpwr_gpio-y=extpwr_gpio.o fan-y=fan.o diff --git a/test/ec_comm.c b/test/ec_comm.c new file mode 100644 index 0000000000..ba92e3132d --- /dev/null +++ b/test/ec_comm.c @@ -0,0 +1,374 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Test ec_comm + */ + +#include "common.h" +#include "crc8.h" +#include "ec_comm.h" +#include "test_util.h" +#include "timer.h" +#include "tpm_nvmem.h" +#include "tpm_nvmem_ops.h" +#include "uart.h" +#include "util.h" +#include "vboot.h" + +const uint8_t sample_ec_hash[SHA256_DIGEST_SIZE] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, +}; + +struct vb2_secdata_kernel test_secdata = { + .struct_version = VB2_SECDATA_KERNEL_STRUCT_VERSION_MIN, + .struct_size = sizeof(struct vb2_secdata_kernel), + .reserved0 = 0, + .kernel_versions = VB2_SECDATA_KERNEL_UID, +}; + +union cr50_test_packet { + struct cr50_comm_packet ph; + uint8_t packet[CR50_COMM_MAX_PACKET_SIZE * 2]; +}; + +union cr50_test_packet sample_packet_cmd_set_mode = { + .ph.magic = CR50_COMM_MAGIC_WORD, + .ph.version = CR50_COMM_VERSION, + .ph.crc = 0, + .ph.cmd = CR50_COMM_CMD_SET_BOOT_MODE, + .ph.size = 1, +}; + +union cr50_test_packet sample_packet_cmd_verify_hash = { + .ph.magic = CR50_COMM_MAGIC_WORD, + .ph.version = CR50_COMM_VERSION, + .ph.crc = 0, + .ph.cmd = CR50_COMM_CMD_VERIFY_HASH, + .ph.size = SHA256_DIGEST_SIZE, +}; + +/* EC Reset Count. It is used to see if ec has been reset. */ +static int ec_reset_count_; + +/* + * Return 1 if EC has been reset since the last call of this function, or + * 0 otherwise. + */ +static int ec_has_reset(void) +{ + static int prev_ec_reset_count; + + if (prev_ec_reset_count == ec_reset_count_) + return 0; + + prev_ec_reset_count = ec_reset_count_; + return 1; +} + +void board_reboot_ec_deferred(int usec_delay_used) +{ + /* ec_reset */ + ec_reset_count_++; + ec_efs_reset(); +} + +enum tpm_read_rv read_tpm_nvmem(uint16_t object_index, uint16_t object_size, + void *obj_value) +{ + /* Check the input parameter */ + if (object_index != KERNEL_NV_INDEX) + return TPM_READ_NOT_FOUND; + if (object_size != test_secdata.struct_size) + return TPM_READ_TOO_SMALL; + + /* + * Copy the test_secdata to obj_value as if it was loaded + * from NVMEM. + */ + memcpy(obj_value, (void *)&test_secdata, object_size); + + return TPM_READ_SUCCESS; +} + +/* + * Return 1 if the byte is found in buf string. + * 0 otherwise + */ +static int find_byte(const char *buf, uint8_t byte) +{ + int i = strlen(buf); + + while (i--) { + if (*buf == byte) + return 1; + buf++; + } + return 0; +} + +/* + * Calculate CRC8 of the the given CR50 packet and fill it in + * the packet. + */ +static void calculate_crc8(union cr50_test_packet *pk) +{ + const int offset_cmd = offsetof(struct cr50_comm_packet, cmd); + + /* Calculate the sample EC-CR50 packet. */ + pk->ph.crc = crc8((uint8_t *)&pk->ph.cmd, + (sizeof(struct cr50_comm_packet) + + pk->ph.size - offset_cmd)); +} + +/* + * Test EC CR50 communication with the given EC-CR50 packet. + * + * @param pk an ec_cr50 comm packet to test + * @param preambles the number of preambles + * @param resp_exp the expected response in two bytes as in + * CR50_COMM_RESPONSE. + * if it is zero, then no response is expected. + */ +static int test_ec_comm(const union cr50_test_packet *pk, int preambles, + uint16_t resp_exp) +{ + uint8_t *buf; + int leng; + int i; + const char *resp; + + leng = sizeof(struct cr50_comm_packet) + pk->ph.size; + + /* Prepare the input packet. */ + buf = (uint8_t *)pk; + + /* Start the test */ + ec_comm_packet_mode_en(1); + TEST_ASSERT(ec_comm_is_uart_in_packet_mode(UART_EC)); + + for (i = 0; i < preambles; i++) + ec_comm_process_packet(CR50_COMM_PREAMBLE); + + test_capture_uartn(UART_EC, 1); + + for (i = 0; i < leng; i++) + ec_comm_process_packet(buf[i]); + + resp = test_get_captured_uartn(UART_EC); + + if (resp_exp) + TEST_ASSERT(*(uint16_t *)resp == resp_exp); + else + /* Check if there was any EC-CR50-comm response. */ + TEST_ASSERT(find_byte(resp, '\xec') == 0); + + test_capture_uartn(UART_EC, 0); + + ec_comm_packet_mode_dis(1); + TEST_ASSERT(!ec_comm_is_uart_in_packet_mode(UART_EC)); + + return EC_SUCCESS; +} + +/* + * Test the failure case for packet errors. + */ +static int test_ec_comm_packet_failure(void) +{ + /* Copy the sample packet to buffer. */ + union cr50_test_packet pk = sample_packet_cmd_verify_hash; + int preambles = MIN_LENGTH_PREAMBLE; + + ec_has_reset(); + + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + /* Test 1: Test with less preambles than required. */ + calculate_crc8(&pk); + TEST_ASSERT(!test_ec_comm(&pk, 1, 0)); + + /* Test 2: Test a wrong magic */ + pk.ph.magic = 0x1234; + calculate_crc8(&pk); + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_ERROR_MAGIC)); + + /* Test 3: Test with a wrong CRC */ + pk = sample_packet_cmd_verify_hash; + calculate_crc8(&pk); + pk.ph.crc += 0x01; /* corrupt the CRC */ + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_ERROR_CRC)); + + /* Test 4: Test with too large payload */ + pk = sample_packet_cmd_verify_hash; + pk.ph.size = SHA256_DIGEST_SIZE + 1; + pk.ph.data[SHA256_DIGEST_SIZE] = 0xff; + calculate_crc8(&pk); + + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_ERROR_SIZE)); + + /* Test 5: Test with a undefined command */ + pk = sample_packet_cmd_verify_hash; + pk.ph.cmd = 0x1000; + calculate_crc8(&pk); + TEST_ASSERT(!test_ec_comm(&pk, preambles, + CR50_COMM_ERROR_UNDEFINED_CMD)); + + /* Test 6: Test with a wrong struct version */ + pk = sample_packet_cmd_verify_hash; + pk.ph.version = CR50_COMM_VERSION + 0x01; + calculate_crc8(&pk); + TEST_ASSERT(!test_ec_comm(&pk, preambles, + CR50_COMM_ERROR_STRUCT_VERSION)); + + /* Check if ec has ever been reset during these tests */ + TEST_ASSERT(!ec_has_reset()); + + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + return EC_SUCCESS; +} + +/* + * Test cases for set_boot_mode command. + */ +static int test_ec_comm_set_boot_mode(void) +{ + /* Copy the sample packet to buffer. */ + union cr50_test_packet pk = sample_packet_cmd_set_mode; + int preambles; + + ec_has_reset(); + + /* Test 1: Attempt to set boot mode to NORMAL. */ + pk.ph.data[0] = EC_EFS_BOOT_MODE_NORMAL; + calculate_crc8(&pk); + preambles = MIN_LENGTH_PREAMBLE * 2; + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_SUCCESS)); + TEST_ASSERT(!ec_has_reset()); /* EC must not be reset. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + /* Test 2: Attempt to set boot mode to NORMAL again. */ + preambles = MIN_LENGTH_PREAMBLE; + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_SUCCESS)); + TEST_ASSERT(!ec_has_reset()); /* EC must not be reset. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + /* + * Test 3: Attempt to set boot mode to NO BOOT. + * EC should not be reset with this boot mode change from NORMAL + * to NO_BOOT. + */ + pk.ph.data[0] = EC_EFS_BOOT_MODE_NO_BOOT; + calculate_crc8(&pk); + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_SUCCESS)); + TEST_ASSERT(!ec_has_reset()); /* EC must not be reset. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NO_BOOT); + + /* + * Test 4: Attempt to set boot mode to NO BOOT again. + * EC should not be reset since it is a repeating command. + */ + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_SUCCESS)); + TEST_ASSERT(!ec_has_reset()); /* EC must not be reset. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NO_BOOT); + + /* + * Test 5: Attempt to set boot mode to NORMAL. + * EC should be reset with this boot mode change from NO_BOOT + * to NORMAL. + */ + pk.ph.data[0] = EC_EFS_BOOT_MODE_NORMAL; + calculate_crc8(&pk); + TEST_ASSERT(!test_ec_comm(&pk, preambles, 0)); + TEST_ASSERT(ec_has_reset()); /* EC must be reset. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + return EC_SUCCESS; +} + +/* + * Test cases for verify_hash command. + */ +static int test_ec_comm_verify_hash(void) +{ + /* Copy the sample packet to buffer. */ + union cr50_test_packet pk = sample_packet_cmd_verify_hash; + int preambles = MIN_LENGTH_PREAMBLE; + + ec_has_reset(); + + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + /* Test 1: Attempt to verify EC Hash. */ + calculate_crc8(&pk); + preambles = MIN_LENGTH_PREAMBLE * 2; + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_SUCCESS)); + TEST_ASSERT(!ec_has_reset()); + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + /* Test 2: Attempt to verify EC Hash again. */ + preambles = MIN_LENGTH_PREAMBLE; + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_SUCCESS)); + TEST_ASSERT(!ec_has_reset()); + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + /* Test 3: Attempt to verify a wrong EC Hash. */ + pk.ph.data[0] ^= 0xff; /* corrupt the payload */ + calculate_crc8(&pk); + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_ERROR_BAD_PAYLOAD)); + TEST_ASSERT(!ec_has_reset()); /* EC should not be reset though. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NO_BOOT); + + /* Test 4: Attempt to verify a wrong EC Hash again. */ + TEST_ASSERT(!test_ec_comm(&pk, preambles, CR50_COMM_ERROR_BAD_PAYLOAD)); + TEST_ASSERT(!ec_has_reset()); /* EC should not be reset though. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NO_BOOT); + + /* + * Test 5: Attempt to verify the correct EC Hash. + * EC should be reset because EC Boot mode is NO BOOT. + */ + pk = sample_packet_cmd_verify_hash; + calculate_crc8(&pk); + preambles = MIN_LENGTH_PREAMBLE * 2; + TEST_ASSERT(!test_ec_comm(&pk, preambles, 0)); + TEST_ASSERT(ec_has_reset()); /* EC must be reset. */ + TEST_ASSERT(ec_efs_get_boot_mode() == EC_EFS_BOOT_MODE_NORMAL); + + /* Check if ec has ever been reset during these tests */ + return EC_SUCCESS; +} + +void run_test(void) +{ + uint8_t size_to_crc; + + /* Prepare the sample kernel secdata and a sample packet. */ + memcpy(test_secdata.ec_hash, sample_ec_hash, sizeof(sample_ec_hash)); + memcpy(sample_packet_cmd_verify_hash.ph.data, + sample_ec_hash, sizeof(sample_ec_hash)); + + /* Calculate the CRC8 for the sample kernel secdata. */ + size_to_crc = test_secdata.struct_size - + offsetof(struct vb2_secdata_kernel, crc8) - + sizeof(test_secdata.crc8); + test_secdata.crc8 = crc8((uint8_t *)&test_secdata.reserved0, + size_to_crc); + + /* Module init */ + board_reboot_ec_deferred(0); + ec_efs_refresh(); + + /* Start test */ + test_reset(); + + RUN_TEST(test_ec_comm_packet_failure); + RUN_TEST(test_ec_comm_set_boot_mode); + RUN_TEST(test_ec_comm_verify_hash); + + test_print_result(); +} diff --git a/test/ec_comm.tasklist b/test/ec_comm.tasklist new file mode 100644 index 0000000000..52c0d390ef --- /dev/null +++ b/test/ec_comm.tasklist @@ -0,0 +1,9 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** + * See CONFIG_TASK_LIST in config.h for details. + */ +#define CONFIG_TEST_TASK_LIST /* No test task */ diff --git a/test/test_config.h b/test/test_config.h index 5c9b1ed3f7..e5d19f0bf8 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -410,6 +410,11 @@ int ncp15wb_calculate_temp(uint16_t adc); #define CONFIG_USB_PD_PORT_MAX_COUNT 2 #endif +#ifdef TEST_EC_COMM +#define CONFIG_CRC8 +#define CONFIG_EC_EFS_SUPPORT +#endif + #if defined(TEST_NVMEM) || defined(TEST_NVMEM_VARS) #define CONFIG_CRC8 #define CONFIG_FLASH_ERASED_VALUE32 (-1U) -- cgit v1.2.1