From 21e22ba8a7750f1cfe5cd3323e3137695ffef0a4 Mon Sep 17 00:00:00 2001 From: Anastasia Klimchuk Date: Mon, 10 May 2021 10:19:25 +1000 Subject: tests: Add unit test to run init/shutdown for mec1308.c, ene_lpc.c This patch includes mocks for io operations in hwaccess_x86_io.h because those are needed to test lifecycle of mec1308.c and ene_lpc.c BUG=b:181803212 TEST=builds and ninja test Change-Id: I3af612defe1af3850dfc1626a208d873e3a3eddc Signed-off-by: Anastasia Klimchuk Reviewed-on: https://review.coreboot.org/c/flashrom/+/51487 Reviewed-by: Edward O'Callaghan Reviewed-by: Nico Huber Tested-by: build bot (Jenkins) --- hwaccess_x86_io_unittest.h | 52 +++++++++++++++++++++++ meson.build | 1 + tests/init_shutdown.c | 100 +++++++++++++++++++++++++++++++++++++++++++++ tests/io_mock.h | 14 +++---- tests/meson.build | 7 ++++ tests/tests.c | 55 +++++++++++++++++++++++++ tests/tests.h | 2 + 7 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 hwaccess_x86_io_unittest.h diff --git a/hwaccess_x86_io_unittest.h b/hwaccess_x86_io_unittest.h new file mode 100644 index 000000000..7bffc963a --- /dev/null +++ b/hwaccess_x86_io_unittest.h @@ -0,0 +1,52 @@ +/* + * This file is part of the flashrom project. + * + * Copyright 2021 Google LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * This header is used instead of hwaccess_x86_io.h for unit tests + * (see flashrom_test_dep in meson.build). + * + * There is no hardware in unit test environment and all hardware operations + * need to be mocked. + */ + +/* + * The same guard is used intentionally for hwaccess_x86_io.h and + * hwaccess_x86_io_unittest.h. When build is made for the test environment, + * hwaccess_x86_io_unittest.h is included first, and it effectively + * replaces hwaccess_x86_io.h. + */ +#ifndef __HWACCESS_X86_IO_H__ +#define __HWACCESS_X86_IO_H__ 1 + +#define OUTB(v, p) test_outb(v, p) +#define OUTW(v, p) test_outw(v, p) +#define OUTL(v, p) test_outl(v, p) +#define INB(p) test_inb(p) +#define INW(p) test_inw(p) +#define INL(p) test_inl(p) + +#include +#include + +/* All functions below are mocked in unit tests. */ + +void test_outb(uint8_t value, uint16_t port); +uint8_t test_inb(uint16_t port); +void test_outw(uint16_t value, uint16_t port); +uint16_t test_inw(uint16_t port); +void test_outl(uint32_t value, uint16_t port); +uint32_t test_inl(uint16_t port); + +#endif /* !__HWACCESS_X86_IO_H__ */ diff --git a/meson.build b/meson.build index 81d63a9d1..8ff08b145 100644 --- a/meson.build +++ b/meson.build @@ -476,6 +476,7 @@ flashrom_test_dep = declare_dependency( compile_args : [ '-includestdlib.h', '-includeunittest_env.h', + '-includehwaccess_x86_io_unittest.h' ], dependencies : [ deps, diff --git a/tests/init_shutdown.c b/tests/init_shutdown.c index abaaf6821..4d9c54908 100644 --- a/tests/init_shutdown.c +++ b/tests/init_shutdown.c @@ -16,6 +16,7 @@ #include #include +#include "io_mock.h" #include "programmer.h" static void run_lifecycle(void **state, enum programmer prog, const char *param) @@ -36,6 +37,105 @@ void dummy_init_and_shutdown_test_success(void **state) run_lifecycle(state, PROGRAMMER_DUMMY, "bus=parallel+lpc+fwh+spi"); } +struct mec1308_io_state { + unsigned char outb_val; +}; + +void mec1308_outb(void *state, unsigned char value, unsigned short port) +{ + struct mec1308_io_state *io_state = state; + + io_state->outb_val = value; +} + +unsigned char mec1308_inb(void *state, unsigned short port) +{ + struct mec1308_io_state *io_state = state; + + return ((port == 0x2e /* MEC1308_SIO_PORT1 */ + || port == 0x4e /* MEC1308_SIO_PORT2 */) + ? 0x20 /* MEC1308_DEVICE_ID_REG */ + : ((io_state->outb_val == 0x84 /* MEC1308_MBX_DATA_START */) + ? 0xaa /* MEC1308_CMD_PASSTHRU_SUCCESS */ + : 0)); +} + +void mec1308_init_and_shutdown_test_success(void **state) +{ + struct mec1308_io_state mec1308_io_state = { 0 }; + const struct io_mock mec1308_io = { + .state = &mec1308_io_state, + .outb = mec1308_outb, + .inb = mec1308_inb, + }; + + io_mock_register(&mec1308_io); + + will_return_always(__wrap_sio_read, 0x4d); /* MEC1308_DEVICE_ID_VAL */ + run_lifecycle(state, PROGRAMMER_MEC1308, ""); + + io_mock_register(NULL); +} + +struct ene_lpc_io_state { + unsigned char outb_val; + int pause_cmd; +}; + +void ene_lpc_outb_kb932(void *state, unsigned char value, unsigned short port) +{ + struct ene_lpc_io_state *io_state = state; + + io_state->outb_val = value; + if (value == 0x59 /* ENE_KB932.ec_pause_cmd */) + io_state->pause_cmd = 1; +} + +unsigned char ene_lpc_inb_kb932(void *state, unsigned short port) +{ + struct ene_lpc_io_state *io_state = state; + unsigned char ene_hwver_offset = 0; /* REG_EC_HWVER & 0xff */ + unsigned char ene_ediid_offset = 0x24; /* REG_EC_EDIID & 0xff */ + unsigned char ec_status_buf_offset = 0x54; /* ENE_KB932.ec_status_buf & 0xff */ + + if (port == 0xfd63 /* ENE_KB932.port_io_base + port_ene_data */) { + if (io_state->outb_val == ene_hwver_offset) + return 0xa2; /* ENE_KB932.hwver */ + if (io_state->outb_val == ene_ediid_offset) + return 0x02; /* ENE_KB932.ediid */ + if (io_state->outb_val == ec_status_buf_offset) { + if (io_state->pause_cmd == 1) { + io_state->pause_cmd = 0; + return 0x33; /* ENE_KB932.ec_is_pausing mask */ + } else { + return 0x00; /* ENE_KB932.ec_is_running mask */ + } + } + } + + return 0; +} + +void ene_lpc_init_and_shutdown_test_success(void **state) +{ + /* + * Current implementation tests for chip ENE_KB932. + * Another chip which is not tested here is ENE_KB94X. + */ + struct ene_lpc_io_state ene_lpc_io_state = { 0, 0 }; + const struct io_mock ene_lpc_io = { + .state = &ene_lpc_io_state, + .outb = ene_lpc_outb_kb932, + .inb = ene_lpc_inb_kb932, + }; + + io_mock_register(&ene_lpc_io); + + run_lifecycle(state, PROGRAMMER_ENE_LPC, ""); + + io_mock_register(NULL); +} + void linux_spi_init_and_shutdown_test_success(void **state) { /* diff --git a/tests/io_mock.h b/tests/io_mock.h index 056e6bff1..69045a213 100644 --- a/tests/io_mock.h +++ b/tests/io_mock.h @@ -32,16 +32,16 @@ #define _IO_MOCK_H_ struct io_mock { - void *priv; + void *state; - void (*outb)(void *priv, unsigned char value, unsigned short port); - unsigned char (*inb)(void *priv, unsigned short port); + void (*outb)(void *state, unsigned char value, unsigned short port); + unsigned char (*inb)(void *state, unsigned short port); - void (*outw)(void *priv, unsigned short value, unsigned short port); - unsigned short (*inw)(void *priv, unsigned short port); + void (*outw)(void *state, unsigned short value, unsigned short port); + unsigned short (*inw)(void *state, unsigned short port); - void (*outl)(void *priv, unsigned int value, unsigned short port); - unsigned int (*inl)(void *priv, unsigned short port); + void (*outl)(void *state, unsigned int value, unsigned short port); + unsigned int (*inl)(void *state, unsigned short port); }; void io_mock_register(const struct io_mock *io); diff --git a/tests/meson.build b/tests/meson.build index b087f2ce2..d17567ec9 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -32,6 +32,13 @@ mocks = [ '-Wl,--wrap=ioctl', '-Wl,--wrap=fopen', '-Wl,--wrap=fopen64', + '-Wl,--wrap=rget_io_perms', + '-Wl,--wrap=test_outb', + '-Wl,--wrap=test_inb', + '-Wl,--wrap=test_outw', + '-Wl,--wrap=test_inw', + '-Wl,--wrap=test_outl', + '-Wl,--wrap=test_inl', '-Wl,--gc-sections', ] diff --git a/tests/tests.c b/tests/tests.c index 701770f49..44bbbdb8a 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -14,6 +14,7 @@ */ #include +#include "io_mock.h" #include "tests.h" #include @@ -22,6 +23,13 @@ /* redefinitions/wrapping */ #define LOG_ME printf("%s is called\n", __func__) +static const struct io_mock *current_io = NULL; + +void io_mock_register(const struct io_mock *io) +{ + current_io = io; +} + void __wrap_physunmap(void *virt_addr, size_t len) { LOG_ME; @@ -74,6 +82,51 @@ FILE *__wrap_fopen64(const char *pathname, const char *mode) return NULL; } +int __wrap_rget_io_perms(void) +{ + LOG_ME; + return 0; +} + +void __wrap_test_outb(unsigned char value, unsigned short port) { + /* LOG_ME; */ + if (current_io && current_io->outb) + current_io->outb(current_io->state, value, port); +} + +unsigned char __wrap_test_inb(unsigned short port) { + /* LOG_ME; */ + if (current_io && current_io->inb) + return current_io->inb(current_io->state, port); + return 0; +} + +void __wrap_test_outw(unsigned short value, unsigned short port) { + /* LOG_ME; */ + if (current_io && current_io->outw) + current_io->outw(current_io->state, value, port); +} + +unsigned short __wrap_test_inw(unsigned short port) { + /* LOG_ME; */ + if (current_io && current_io->inw) + return current_io->inw(current_io->state, port); + return 0; +} + +void __wrap_test_outl(unsigned int value, unsigned short port) { + /* LOG_ME; */ + if (current_io && current_io->outl) + current_io->outl(current_io->state, value, port); +} + +unsigned int __wrap_test_inl(unsigned short port) { + /* LOG_ME; */ + if (current_io && current_io->inl) + return current_io->inl(current_io->state, port); + return 0; +} + int main(void) { int ret = 0; @@ -112,6 +165,8 @@ int main(void) const struct CMUnitTest init_shutdown_tests[] = { cmocka_unit_test(dummy_init_and_shutdown_test_success), + cmocka_unit_test(mec1308_init_and_shutdown_test_success), + cmocka_unit_test(ene_lpc_init_and_shutdown_test_success), cmocka_unit_test(linux_spi_init_and_shutdown_test_success), }; ret |= cmocka_run_group_tests_name("init_shutdown.c tests", init_shutdown_tests, NULL, NULL); diff --git a/tests/tests.h b/tests/tests.h index 16476c27a..da4f4a97a 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -42,6 +42,8 @@ void probe_spi_st95_test_success(void **state); /* spi95.c */ /* init_shutdown.c */ void dummy_init_and_shutdown_test_success(void **state); +void mec1308_init_and_shutdown_test_success(void **state); +void ene_lpc_init_and_shutdown_test_success(void **state); void linux_spi_init_and_shutdown_test_success(void **state); #endif /* TESTS_H */ -- cgit v1.2.3