summaryrefslogtreecommitdiff
path: root/zephyr/test/vboot_efs2/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/test/vboot_efs2/src/main.c')
-rw-r--r--zephyr/test/vboot_efs2/src/main.c423
1 files changed, 423 insertions, 0 deletions
diff --git a/zephyr/test/vboot_efs2/src/main.c b/zephyr/test/vboot_efs2/src/main.c
new file mode 100644
index 0000000000..1558fb75f0
--- /dev/null
+++ b/zephyr/test/vboot_efs2/src/main.c
@@ -0,0 +1,423 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#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 "system_fake.h"
+#include "task.h"
+#include "usb_mux.h"
+#include "usbc_ppc.h"
+#include "vboot.h"
+
+#include "zephyr/devicetree.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>
+
+#define SERIAL_BUFFER_SIZE DT_PROP(DT_NODELABEL(test_uart), buffer_size)
+
+static int show_power_shortage_called;
+void show_power_shortage(void)
+{
+ show_power_shortage_called++;
+}
+
+static int show_critical_error_called;
+void show_critical_error(void)
+{
+ show_critical_error_called++;
+}
+
+ZTEST(vboot_efs2, test_vboot_main_system_is_in_rw)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ /* Set system_is_in_rw */
+ system_set_shrspi_image_copy(EC_IMAGE_RW);
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+ vboot_main();
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+ zassert_equal(show_power_shortage_called, 1, NULL);
+
+ zassert_true(strstr(outbuffer, "VB Already in RW") != NULL,
+ "Expected msg not in %s", outbuffer);
+
+ /* Verify some things we don't expect also. */
+ zassert_true(strstr(outbuffer, "VB Ping Cr50") == NULL,
+ "Unexpected msg in %s", outbuffer);
+ zassert_true(strstr(outbuffer, "VB Exit") == NULL,
+ "Unexpected msg in %s", outbuffer);
+ zassert_false(vboot_allow_usb_pd(), NULL);
+ zassert_equal(show_critical_error_called, 0, NULL);
+}
+
+ZTEST(vboot_efs2, test_vboot_main_system_is_manual_recovery)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ system_enter_manual_recovery();
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+ vboot_main();
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+ zassert_equal(show_power_shortage_called, 0, NULL);
+ zassert_true(strstr(outbuffer, "VB In recovery mode") != NULL,
+ "Expected msg not in %s", outbuffer);
+
+ /* Verify some things we don't expect also. */
+ zassert_true(strstr(outbuffer, "VB Ping Cr50") == NULL,
+ "Unexpected msg in %s", outbuffer);
+ zassert_true(strstr(outbuffer, "VB Exit") == NULL,
+ "Unexpected msg in %s", outbuffer);
+ zassert_false(vboot_allow_usb_pd(), NULL);
+ zassert_equal(show_critical_error_called, 0, NULL);
+}
+
+ZTEST(vboot_efs2, test_vboot_main_stay_in_ro)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ system_set_reset_flags(EC_RESET_FLAG_STAY_IN_RO);
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+ vboot_main();
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+ zassert_equal(show_power_shortage_called, 0, NULL);
+
+ /* Verify some things we don't expect also. */
+ zassert_true(strstr(outbuffer, "VB In recovery mode") == NULL,
+ "Expected msg not in %s", outbuffer);
+ zassert_true(strstr(outbuffer, "VB Ping Cr50") == NULL,
+ "Unexpected msg in %s", outbuffer);
+ zassert_true(strstr(outbuffer, "VB Exit") == NULL,
+ "Unexpected msg in %s", outbuffer);
+ zassert_false(vboot_allow_usb_pd(), NULL);
+ zassert_equal(show_critical_error_called, 0, NULL);
+}
+
+ZTEST(vboot_efs2, test_vboot_main_jump_timeout)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+ vboot_main();
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+ zassert_equal(show_critical_error_called, 1, NULL);
+
+ zassert_true(strstr(outbuffer, "VB Ping Cr50") != NULL,
+ "Expected msg not in %s", outbuffer);
+ zassert_false(vboot_allow_usb_pd(), NULL);
+ zassert_equal(show_power_shortage_called, 0, NULL);
+}
+
+#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 + sizeof(req) <=
+ serial_vnd_out_data_size_get(uart_shell_dev)) {
+ serial_vnd_read_out_data(uart_shell_dev, NULL,
+ req.size +
+ sizeof(req));
+ serial_vnd_queue_in_data(
+ uart_shell_dev, user_data,
+ sizeof(struct cr50_comm_response));
+ }
+ }
+ } else {
+ /* Packet mode is off, so just consume enough bytes from the out
+ * buffer to clear it.
+ */
+ serial_vnd_read_out_data(uart_shell_dev, NULL,
+ SERIAL_BUFFER_SIZE);
+ }
+}
+
+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(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_vboot_get_rw_hash_fail)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+ struct ec_response_vboot_hash response;
+ struct ec_params_vboot_hash hash_start_params = {
+ .cmd = EC_VBOOT_HASH_START,
+ .hash_type = EC_VBOOT_HASH_TYPE_SHA256,
+ .offset = 0,
+ .size = 0x12345,
+ };
+ struct host_cmd_handler_args hash_start_args = BUILD_HOST_COMMAND(
+ EC_CMD_VBOOT_HASH, 0, response, hash_start_params);
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+
+ zassert_ok(host_command_process(&hash_start_args), NULL);
+ 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 (0x6)") != 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_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);
+}
+
+ZTEST(vboot_efs2, test_shutdown_hook_in_rw)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ /* Set system_is_in_rw */
+ system_set_shrspi_image_copy(EC_IMAGE_RW);
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+ hook_notify(HOOK_CHIPSET_SHUTDOWN_COMPLETE);
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_true(strstr(outbuffer, "VB hook_shutdown") != NULL,
+ "Expected msg not in %s", outbuffer);
+ zassert_equal(system_get_reset_flags(), 0, NULL);
+
+ /* Verify some things we don't expect also. */
+ zassert_true(strstr(outbuffer, "VB Ping Cr50") == NULL,
+ "Unexpected msg in %s", outbuffer);
+ zassert_false(vboot_allow_usb_pd(), NULL);
+ zassert_equal(show_critical_error_called, 0, NULL);
+ zassert_equal(show_power_shortage_called, 0, NULL);
+}
+
+ZTEST(vboot_efs2, test_shutdown_hook_in_ro)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ /* Set system_is_in_rw */
+ system_set_shrspi_image_copy(EC_IMAGE_RO);
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+ hook_notify(HOOK_CHIPSET_SHUTDOWN_COMPLETE);
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_true(strstr(outbuffer, "VB hook_shutdown") != NULL,
+ "Expected msg not in %s", outbuffer);
+ zassert_true(strstr(outbuffer, "VB Ping Cr50") != NULL,
+ "Expected msg not in %s", outbuffer);
+ zassert_equal(system_get_reset_flags(), EC_RESET_FLAG_AP_IDLE, NULL);
+ zassert_equal(show_critical_error_called, 1, NULL);
+
+ /* Verify some things we don't expect also. */
+ zassert_false(vboot_allow_usb_pd(), NULL);
+ zassert_equal(show_power_shortage_called, 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;
+}
+
+void vboot_efs2_cleanup(void *fixture)
+{
+ ARG_UNUSED(fixture);
+
+ system_set_shrspi_image_copy(EC_IMAGE_RO);
+ show_power_shortage_called = 0;
+ show_critical_error_called = 0;
+ system_exit_manual_recovery();
+ system_clear_reset_flags(EC_RESET_FLAG_STAY_IN_RO | EC_RESET_FLAG_EFS |
+ EC_RESET_FLAG_AP_IDLE);
+ vboot_disable_pd();
+ serial_vnd_set_callback(uart_shell_dev, NULL, NULL);
+ serial_vnd_read_out_data(uart_shell_dev, NULL, SERIAL_BUFFER_SIZE);
+}
+
+ZTEST_SUITE(vboot_efs2, NULL, vboot_efs2_setup, NULL, vboot_efs2_cleanup, NULL);
+
+int board_set_active_charge_port(int port)
+{
+ return EC_ERROR_INVAL;
+}
+
+void board_set_charge_limit(int port, int supplier, int charge_ma, int max_ma,
+ int charge_mv)
+{
+}
+
+void pd_power_supply_reset(int port)
+{
+}
+
+int pd_check_vconn_swap(int port)
+{
+ return 0;
+}
+
+int pd_set_power_supply_ready(int port)
+{
+ return EC_SUCCESS;
+}
+
+enum usbc_port { USBC_PORT_C0 = 0, USBC_PORT_COUNT };
+
+/* BC1.2 charger detect configuration */
+const struct pi3usb9201_config_t pi3usb9201_bc12_chips[] = {
+ [USBC_PORT_C0] = {
+ .i2c_port = I2C_PORT_USB_C0,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
+ },
+};
+
+struct usb_mux_chain usb_muxes[] = {
+ [USBC_PORT_C0] = {
+ .mux = &(struct usb_mux) {
+ .usb_port = USBC_PORT_C0,
+ .driver = &tcpci_tcpm_usb_mux_driver,
+ .i2c_port = I2C_PORT_USB_C0,
+ .i2c_addr_flags = DT_REG_ADDR(DT_NODELABEL(tcpci_emul)),
+ },
+ },
+};
+
+/* USBC PPC configuration */
+struct ppc_config_t ppc_chips[] = {
+ [USBC_PORT_C0] = {
+ .i2c_port = I2C_PORT_USB_C0,
+ .i2c_addr_flags = SN5S330_ADDR0_FLAGS,
+ .drv = &sn5s330_drv,
+ },
+};
+unsigned int ppc_cnt = ARRAY_SIZE(ppc_chips);