diff options
author | Jeremy Bettis <jbettis@google.com> | 2022-08-31 16:36:39 -0600 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-09-12 18:33:37 +0000 |
commit | 54a17155080c63f4654ec8729de593fcda721f87 (patch) | |
tree | b66348b7e4b8e5b1a0585407f91d978ed49aa732 | |
parent | 866baf5818e7bda257f8f21ffe02b1a5cead3331 (diff) | |
download | chrome-ec-54a17155080c63f4654ec8729de593fcda721f87.tar.gz |
zephyr: Add new vboot efs2 tests for cr50 errors
Emulate the cr50 to test all code in verify_and_jump.
Add LCOV_EXCL comments to prevent code coverage on stub functions that
are not intended to be used.
Depends on https://github.com/zephyrproject-rtos/zephyr/pull/49768
BRANCH=None
BUG=None
TEST=./twister
Cq-Depend: chromium:3886718
Change-Id: Ia52e8d96ead69843749230e76ec1a90c02a02d36
Signed-off-by: Jeremy Bettis <jbettis@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3867801
Reviewed-by: Aaron Massey <aaronmassey@google.com>
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Commit-Queue: Jeremy Bettis <jbettis@chromium.org>
Tested-by: Jeremy Bettis <jbettis@chromium.org>
-rw-r--r-- | common/vboot/efs2.c | 10 | ||||
-rw-r--r-- | zephyr/shim/src/console.c | 26 | ||||
-rw-r--r-- | zephyr/test/vboot_efs2/boards/native_posix.overlay | 9 | ||||
-rw-r--r-- | zephyr/test/vboot_efs2/prj.conf | 1 | ||||
-rw-r--r-- | zephyr/test/vboot_efs2/src/main.c | 157 |
5 files changed, 186 insertions, 17 deletions
diff --git a/common/vboot/efs2.c b/common/vboot/efs2.c index 6df6b5b56e..e6e4a18ea7 100644 --- a/common/vboot/efs2.c +++ b/common/vboot/efs2.c @@ -223,10 +223,12 @@ void vboot_disable_pd(void) } #endif +/* LCOV_EXCL_START - This is just a stub intended to be overridden */ __overridable void show_critical_error(void) { CPRINTS("%s", __func__); } +/* LCOV_EXCL_STOP */ static void verify_and_jump(void) { @@ -251,14 +253,16 @@ static void verify_and_jump(void) } } +/* LCOV_EXCL_START - This is just a stub intended to be overridden */ __overridable void show_power_shortage(void) { CPRINTS("%s", __func__); } +/* LCOV_EXCL_STOP */ static bool is_battery_ready(void) { - /* TODO: Add battery check (https://crbug.com/1045216) */ + /* TODO(b/172210316): Add battery check */ return true; } @@ -300,12 +304,16 @@ void vboot_main(void) * If battery is drained or bad, we will boot in NO_BOOT mode to * inform the user of the problem. */ + /* LCOV_EXCL_START - TODO(b/172210316) implement + * is_battery_ready(), and remove this lcov excl. + */ if (!is_battery_ready()) { CPRINTS("Battery not ready or bad"); if (set_boot_mode(BOOT_MODE_NO_BOOT) == CR50_COMM_SUCCESS) enable_pd(); } + /* LCOV_EXCL_STOP */ /* We'll enter recovery mode immediately, later, or never. */ return; diff --git a/zephyr/shim/src/console.c b/zephyr/shim/src/console.c index 5ae44e5a1b..b329133dc0 100644 --- a/zephyr/shim/src/console.c +++ b/zephyr/shim/src/console.c @@ -56,6 +56,8 @@ static struct k_poll_signal shell_init_signal; * (which requires locking the shell). */ static bool shell_stopped; + +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) RING_BUF_DECLARE(rx_buffer, CONFIG_UART_RX_BUF_SIZE); static void uart_rx_handle(const struct device *dev) @@ -90,10 +92,12 @@ static void uart_callback(const struct device *dev, void *user_data) if (uart_irq_rx_ready(dev)) uart_rx_handle(dev); } +#endif static void shell_uninit_callback(const struct shell *shell, int res) { if (!res) { +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) /* Set the new callback */ uart_irq_callback_user_data_set(uart_shell_dev, uart_callback, NULL); @@ -106,6 +110,7 @@ static void shell_uninit_callback(const struct shell *shell, int res) /* Enable RX interrupts */ uart_irq_rx_enable(uart_shell_dev); +#endif } /* Notify the uninit signal that we finished */ @@ -126,9 +131,11 @@ int uart_shell_stop(void) /* Clear all pending input */ uart_clear_input(); +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) /* Disable RX and TX interrupts */ uart_irq_rx_disable(uart_shell_dev); uart_irq_tx_disable(uart_shell_dev); +#endif /* Initialize the uninit signal */ k_poll_signal_init(&shell_uninit_signal); @@ -169,8 +176,10 @@ static void shell_init_from_work(struct k_work *work) k_thread_priority_set(shell_zephyr->ctx->tid, EC_TASK_PRIORITY(EC_SHELL_PRIO)); +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) uart_irq_rx_enable(uart_shell_dev); uart_irq_tx_enable(uart_shell_dev); +#endif /* Notify the init signal that initialization is complete */ k_poll_signal_raise(&shell_init_signal, 0); @@ -183,9 +192,11 @@ void uart_shell_start(void) K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &shell_init_signal); +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) /* Disable RX and TX interrupts */ uart_irq_rx_disable(uart_shell_dev); uart_irq_tx_disable(uart_shell_dev); +#endif /* Initialize k_work to call shell init (this makes it thread safe) */ k_work_init(&shell_init_work, shell_init_from_work); @@ -316,24 +327,39 @@ void uart_flush_output(void) void uart_tx_flush(void) { +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) while (!uart_irq_tx_complete(uart_shell_dev)) ; +#endif } int uart_getc(void) { +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) uint8_t c; if (ring_buf_get(&rx_buffer, &c, 1)) { return c; } return -1; +#else + uint8_t c; + int rv; + + rv = uart_poll_in(uart_shell_dev, &c); + if (rv) { + return rv; + } + return c; +#endif } void uart_clear_input(void) { +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) /* Reset the input ring buffer */ ring_buf_reset(&rx_buffer); +#endif } static void handle_sprintf_rv(int rv, size_t *len) diff --git a/zephyr/test/vboot_efs2/boards/native_posix.overlay b/zephyr/test/vboot_efs2/boards/native_posix.overlay index d0ab830358..c03a4757fe 100644 --- a/zephyr/test/vboot_efs2/boards/native_posix.overlay +++ b/zephyr/test/vboot_efs2/boards/native_posix.overlay @@ -10,6 +10,7 @@ chosen { cros-ec,flash = &flash1; cros-ec,flash-controller = &cros_flash; + zephyr,shell-uart = &test_uart; }; aliases { gpio-wp = &gpio_wp_l; @@ -74,7 +75,6 @@ compatible = "cros,tcpci-generic-emul"; status = "okay"; reg = <0x82>; - label = "TCPCI_EMUL"; alert_gpio = <&usb_c0_tcpc_int_odl>; }; }; @@ -98,6 +98,12 @@ compatible = "lgc,ac17a8m", "battery-smart"; }; }; + test_uart: uart@55556666 { + compatible = "vnd,serial"; + reg = <0x55556666 0x1000>; + status = "okay"; + buffer-size = <200>; + }; }; &gpio0 { @@ -121,7 +127,6 @@ compatible = "cros,isl923x-emul"; status = "okay"; reg = <0x9>; - label = "ISL923X_EMUL"; battery = <&battery>; }; }; diff --git a/zephyr/test/vboot_efs2/prj.conf b/zephyr/test/vboot_efs2/prj.conf index 1b73555f90..988ebc4a8c 100644 --- a/zephyr/test/vboot_efs2/prj.conf +++ b/zephyr/test/vboot_efs2/prj.conf @@ -36,6 +36,7 @@ CONFIG_PLATFORM_EC_VBOOT_HASH=y CONFIG_RING_BUFFER=y CONFIG_SERIAL=y CONFIG_SHELL_BACKEND_DUMMY=y +CONFIG_SHELL_BACKEND_DUMMY_BUF_SIZE=1000 CONFIG_SHELL_BACKEND_SERIAL=n CONFIG_SHIMMED_TASKS=y CONFIG_ZTEST=y diff --git a/zephyr/test/vboot_efs2/src/main.c b/zephyr/test/vboot_efs2/src/main.c index b0ef86c92a..162a7088b2 100644 --- a/zephyr/test/vboot_efs2/src/main.c +++ b/zephyr/test/vboot_efs2/src/main.c @@ -3,21 +3,25 @@ * found in the LICENSE file. */ -#include "zephyr/kernel.h" -#include <zephyr/ztest_assert.h> -#include <zephyr/ztest_test_new.h> -#include <zephyr/shell/shell_dummy.h> - +#include "driver/bc12/pi3usb9201_public.h" +#include "driver/tcpm/tcpci.h" #include "ec_app_main.h" +#include "emul/emul_flash.h" #include "hooks.h" +#include "ppc/sn5s330_public.h" #include "task.h" -#include "emul/emul_flash.h" -#include "vboot.h" -#include "driver/bc12/pi3usb9201_public.h" #include "usb_mux.h" -#include "driver/tcpm/tcpci.h" -#include "ppc/sn5s330_public.h" #include "usbc_ppc.h" +#include "vboot.h" + +#include <stdint.h> + +#include <zephyr/drivers/gpio/gpio_emul.h> +#include <zephyr/drivers/uart/serial_test.h> +#include <zephyr/kernel.h> +#include <zephyr/shell/shell_dummy.h> +#include <zephyr/ztest_assert.h> +#include <zephyr/ztest_test_new.h> static int show_power_shortage_called; void show_power_shortage(void) @@ -126,15 +130,139 @@ ZTEST(vboot_efs2, test_vboot_main_jump_timeout) zassert_equal(show_power_shortage_called, 0, NULL); } -/* TODO(jbettis): Add cases for verify_and_jump() CR50_COMM_ERR_BAD_PAYLOAD & - * CR50_COMM_SUCCESS - */ +#define PACKET_MODE_GPIO DT_PATH(named_gpios, ec_gsc_packet_mode) + +static const struct device *uart_shell_dev = + DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart)); +static const struct device *gpio_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(PACKET_MODE_GPIO, gpios)); + +static void reply_cr50_payload(const struct device *dev, void *user_data) +{ + if (gpio_emul_output_get(gpio_dev, + DT_GPIO_PIN(PACKET_MODE_GPIO, gpios))) { + struct cr50_comm_request req; + uint32_t bytes_read; + + bytes_read = serial_vnd_peek_out_data( + uart_shell_dev, (void *)&req, sizeof(req)); + /* If ! valid cr50_comm_request header, read 1 byte. */ + while (bytes_read == sizeof(req) && + req.magic != CR50_PACKET_MAGIC) { + /* Consume one byte and then peek again. */ + serial_vnd_read_out_data(uart_shell_dev, NULL, 1); + bytes_read = serial_vnd_peek_out_data( + uart_shell_dev, (void *)&req, sizeof(req)); + } + if (bytes_read == sizeof(req)) { + /* If we have a full packet, consume it, and reply + * with whatever is in user_data which holds a cr50 + * reply. + */ + if (req.size <= + serial_vnd_out_data_size_get(uart_shell_dev)) { + serial_vnd_read_out_data(uart_shell_dev, NULL, + req.size); + serial_vnd_queue_in_data( + uart_shell_dev, user_data, + sizeof(struct cr50_comm_response)); + } + } + } else { + /* Packet mode is off, so just consume some bytes from the out + * buffer. The buffer is only 200 in the dts, so 1000 will + * consume it all. + */ + serial_vnd_read_out_data(uart_shell_dev, NULL, 1000); + } +} + +ZTEST(vboot_efs2, test_vboot_main_jump_bad_payload) +{ + const struct shell *shell_zephyr = get_ec_shell(); + const char *outbuffer; + size_t buffer_size; + struct cr50_comm_response resp = { + .error = CR50_COMM_ERR_BAD_PAYLOAD, + }; + + serial_vnd_set_callback(uart_shell_dev, reply_cr50_payload, &resp); + + shell_backend_dummy_clear_output(shell_zephyr); + vboot_main(); + + outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size); + + zassert_true(strstr(outbuffer, "VB Ping Cr50") != NULL, + "Expected msg not in %s", outbuffer); + zassert_true(strstr(outbuffer, "VB Hash mismatch") != NULL, + "Expected msg not in %s", outbuffer); + zassert_true(vboot_allow_usb_pd(), NULL); + zassert_equal(show_power_shortage_called, 0, NULL); + zassert_equal(show_critical_error_called, 0, NULL); +} + +/* This hits the default case in verify_and_jump. */ +ZTEST(vboot_efs2, test_vboot_main_jump_bad_crc) +{ + const struct shell *shell_zephyr = get_ec_shell(); + const char *outbuffer; + size_t buffer_size; + struct cr50_comm_response resp = { + .error = CR50_COMM_ERR_CRC, + }; + + serial_vnd_set_callback(uart_shell_dev, reply_cr50_payload, &resp); + + shell_backend_dummy_clear_output(shell_zephyr); + vboot_main(); + + outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size); + + zassert_true(strstr(outbuffer, "VB Ping Cr50") != NULL, + "Expected msg not in %s", outbuffer); + zassert_true(strstr(outbuffer, "VB Failed to verify RW (0xec03)") != + NULL, + "Expected msg not in %s", outbuffer); + zassert_false(vboot_allow_usb_pd(), NULL); + zassert_equal(show_power_shortage_called, 0, NULL); + zassert_equal(show_critical_error_called, 1, NULL); +} + +ZTEST(vboot_efs2, test_vboot_main_jump_success) +{ + const struct shell *shell_zephyr = get_ec_shell(); + const char *outbuffer; + size_t buffer_size; + struct cr50_comm_response resp = { + .error = CR50_COMM_SUCCESS, + }; + + serial_vnd_set_callback(uart_shell_dev, reply_cr50_payload, &resp); + + shell_backend_dummy_clear_output(shell_zephyr); + vboot_main(); + + outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size); + + zassert_true(strstr(outbuffer, "VB Ping Cr50") != NULL, + "Expected msg not in %s", outbuffer); + zassert_true(strstr(outbuffer, "VB Failed to jump") != NULL, + "Expected msg not in %s", outbuffer); + zassert_false(vboot_allow_usb_pd(), NULL); + zassert_equal(show_power_shortage_called, 0, NULL); + zassert_equal(show_critical_error_called, 1, NULL); + zassert_equal(system_get_reset_flags(), 0, NULL); +} void *vboot_efs2_setup(void) { /* Wait for the shell to start. */ k_sleep(K_MSEC(1)); zassert_equal(get_ec_shell()->ctx->state, SHELL_STATE_ACTIVE, NULL); + + system_common_pre_init(); + return NULL; } @@ -146,8 +274,9 @@ void vboot_efs2_cleanup(void *fixture) show_power_shortage_called = 0; show_critical_error_called = 0; system_exit_manual_recovery(); - system_clear_reset_flags(EC_RESET_FLAG_STAY_IN_RO); + system_clear_reset_flags(EC_RESET_FLAG_STAY_IN_RO | EC_RESET_FLAG_EFS); vboot_disable_pd(); + serial_vnd_set_callback(uart_shell_dev, NULL, NULL); } ZTEST_SUITE(vboot_efs2, NULL, vboot_efs2_setup, NULL, vboot_efs2_cleanup, NULL); |