diff --git a/tests/lib/Makefile.inc b/tests/lib/Makefile.inc index ccc6596e18..2c80b93439 100644 --- a/tests/lib/Makefile.inc +++ b/tests/lib/Makefile.inc @@ -13,6 +13,7 @@ tests-y += fmap-test tests-y += imd_cbmem-romstage-test tests-y += imd_cbmem-ramstage-test tests-y += region_file-test +tests-y += stack-test string-test-srcs += tests/lib/string-test.c string-test-srcs += src/lib/string.c @@ -71,3 +72,7 @@ imd_cbmem-romstage-test-mocks += cbmem_top_chipset region_file-test-srcs += tests/lib/region_file-test.c region_file-test-srcs += src/commonlib/region.c region_file-test-srcs += tests/stubs/console.c + +stack-test-srcs += tests/lib/stack-test.c +stack-test-srcs += src/lib/stack.c +stack-test-srcs += tests/stubs/console.c diff --git a/tests/lib/stack-test.c b/tests/lib/stack-test.c new file mode 100644 index 0000000000..f494c086ad --- /dev/null +++ b/tests/lib/stack-test.c @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + + +#if CONFIG_STACK_SIZE == 0 +# define STACK_SIZE 0x1000 +#else +# define STACK_SIZE CONFIG_STACK_SIZE +#endif + +/* Value used for stack initialization. Change if implementation changes. */ +#define STACK_GUARD_VALUE 0xDEADBEEF + +__weak extern u8 _stack[]; +__weak extern u8 _estack[]; +TEST_REGION(stack, STACK_SIZE); + + +static void fill_stack(u32 value) +{ + u32 *stack = (u32 *)_stack; + for (size_t i = 0; i < STACK_SIZE / sizeof(u32); ++i) + stack[i] = value; +} + +/* Fill stack region with guard value. */ +static void clean_stack(void) +{ + fill_stack(STACK_GUARD_VALUE); +} + +static int setup_stack_test(void **state) +{ + void *top_of_stack = _stack + sizeof(_stack); + + clean_stack(); + *state = top_of_stack; + + return 0; +} + +static void test_empty_stack(void **state) +{ + void *top_of_stack = *state; + + /* Expect success when checking empty stack. */ + assert_int_equal(0, checkstack(top_of_stack, 0)); +} + +static void test_almost_full_stack(void **state) +{ + void *top_of_stack = *state; + u32 *stack = (u32 *)_stack; + + /* Fill stack with random value except last word */ + for (size_t i = 1; i < STACK_SIZE / sizeof(u32); ++i) + stack[i] = 0xAA11FF44; + + /* Expect success when checking almost-full stack, + because last guard value is present */ + assert_int_equal(0, checkstack(top_of_stack, 0)); +} + +static void test_full_stack(void **state) +{ + void *top_of_stack = *state; + + /* Fill stack with value different than stack guard */ + fill_stack(0x600DB015); + + /* Expect failure when checking full stack as absence of guard value at the end of + the stack indicates stack overrun. */ + assert_int_equal(-1, checkstack(top_of_stack, 0)); +} + +static void test_partialy_filled_stack(void **state) +{ + void *top_of_stack = *state; + u32 *stack = (u32 *)_stack; + size_t i = STACK_SIZE / sizeof(u32) / 2; + + for (; i < STACK_SIZE / sizeof(u32); ++i) + stack[i] = 0x4321ABDC + i; + + /* Expect success when checking partially-filled stack, + because only part of stack is filled with non-guard value. */ + assert_int_equal(0, checkstack(top_of_stack, 0)); +} + +static void test_alternately_filled_stack(void **state) +{ + void *top_of_stack = *state; + u32 *stack = (u32 *)_stack; + size_t i; + + for (i = 0; i < STACK_SIZE / sizeof(u32); i += 2) + stack[i] = STACK_GUARD_VALUE; + + for (i = 1; i < STACK_SIZE / sizeof(u32); i += 2) + stack[i] = 0x42420707; + + assert_int_equal(0, checkstack(top_of_stack, 0)); +} + +static void test_incorrectly_initialized_stack(void **state) +{ + void *top_of_stack = *state; + u32 *stack = (u32 *)_stack; + + /* Remove last stack guard value */ + stack[0] = 0xFF00FF11; + + /* Expect failure when there is no last stack guard value even if no other value was + changed. */ + assert_int_equal(-1, checkstack(top_of_stack, 0)); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup(test_empty_stack, setup_stack_test), + cmocka_unit_test_setup(test_almost_full_stack, setup_stack_test), + cmocka_unit_test_setup(test_full_stack, setup_stack_test), + cmocka_unit_test_setup(test_partialy_filled_stack, setup_stack_test), + cmocka_unit_test_setup(test_alternately_filled_stack, setup_stack_test), + cmocka_unit_test_setup(test_incorrectly_initialized_stack, setup_stack_test), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +}