summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/lib/Makefile.inc5
-rw-r--r--tests/lib/stack-test.c133
2 files changed, 138 insertions, 0 deletions
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 <tests/test.h>
+#include <lib.h>
+#include <symbols.h>
+
+
+#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);
+}