diff --git a/tests/arch/arm/arm_interrupt/README.txt b/tests/arch/arm/arm_interrupt/README.txt index 577376f1fab..7cb8c736f88 100644 --- a/tests/arch/arm/arm_interrupt/README.txt +++ b/tests/arch/arm/arm_interrupt/README.txt @@ -1,11 +1,17 @@ -Title: Test to verify code fault handling in ISR execution context (ARM Only) +Title: Test to verify code fault handling in ISR execution context + and the behavior of irq_lock() and irq_unlock() when invoked + from User Mode. (ARM Only) Description: -This test verifies that we can handle system fault conditions +The first test verifies that we can handle system fault conditions while running in handler mode (i.e. in an ISR). Only for ARM Cortex-M targets. +The second test verifies that threads in user mode, despite being able to call +the irq_lock() and irq_unlock() functions without triggering a CPU fault, +they won't be able to read or modify the current IRQ locking status. + --------------------------------------------------------------------------- Building and Running Project: @@ -62,6 +68,13 @@ Sample Output: PASS - test_arm_interrupt =================================================================== + starting test - test_arm_user_interrupt + PASS - test_arm_user_interrupt + =================================================================== + Test suite arm_interrupt succeeded + =================================================================== + PROJECT EXECUTION SUCCESSFUL + Test suite arm_interrupt succeeded =================================================================== PROJECT EXECUTION SUCCESSFUL diff --git a/tests/arch/arm/arm_interrupt/prj.conf b/tests/arch/arm/arm_interrupt/prj.conf index a3f0a41c8d2..7298cd1ab9f 100644 --- a/tests/arch/arm/arm_interrupt/prj.conf +++ b/tests/arch/arm/arm_interrupt/prj.conf @@ -1,2 +1,4 @@ CONFIG_ZTEST=y CONFIG_DYNAMIC_INTERRUPTS=y +CONFIG_TEST_USERSPACE=y +CONFIG_APPLICATION_DEFINED_SYSCALL=y diff --git a/tests/arch/arm/arm_interrupt/src/arm_interrupt.c b/tests/arch/arm/arm_interrupt/src/arm_interrupt.c index 058d407205a..b96db8a4696 100644 --- a/tests/arch/arm/arm_interrupt/src/arm_interrupt.c +++ b/tests/arch/arm/arm_interrupt/src/arm_interrupt.c @@ -114,6 +114,86 @@ void test_arm_interrupt(void) zassert_true(post_flag == j, "Test flag not set by ISR\n"); } } + +#if defined(CONFIG_USERSPACE) +#include +#include "test_syscalls.h" + +void z_impl_test_arm_user_interrupt_syscall(void) +{ +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) + /* Confirm IRQs are not locked */ + zassert_false(__get_PRIMASK(), "PRIMASK is set\n"); +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + + static bool first_call = 1; + + if (first_call == 1) { + + /* First time the syscall is invoked */ + first_call = 0; + + /* Lock IRQs in supervisor mode */ + int key = irq_lock(); + + /* Verify that IRQs were not already locked */ + zassert_false(key, "IRQs locked in system call\n"); + } + + /* Confirm IRQs are still locked */ + zassert_true(__get_BASEPRI(), "BASEPRI not set\n"); +#endif +} + +static inline void z_vrfy_test_arm_user_interrupt_syscall(void) +{ + z_impl_test_arm_user_interrupt_syscall(); +} +#include + +void test_arm_user_interrupt(void) +{ + /* Test thread executing in user mode */ + zassert_true(arch_is_user_context(), + "Test thread not running in user mode\n"); + + /* Attempt to lock IRQs in user mode */ + irq_lock(); + /* Attempt to lock again should return non-zero value of previous + * locking attempt, if that were to be successful. + */ + int lock = irq_lock(); + + zassert_false(lock, "IRQs shown locked in user mode\n"); + + /* Generate a system call to manage the IRQ locking */ + test_arm_user_interrupt_syscall(); + + /* Attempt to unlock IRQs in user mode */ + irq_unlock(0); + +#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + /* The first system call has left the IRQs locked. + * Generate a second system call to inspect the IRQ locking. + * + * In Cortex-M Baseline system calls cannot be invoked + * with interrupts locked, so we skip this part of the + * test. + */ + test_arm_user_interrupt_syscall(); + + /* Verify that thread is not able to infer that IRQs are locked. */ + zassert_false(irq_lock(), "IRQs are shown to be locked\n"); +#endif +} +#else +void test_arm_user_interrupt(void) +{ + TC_PRINT("Skipped\n"); +} +#endif /* CONFIG_USERSPACE */ + + /** * @} */ diff --git a/tests/arch/arm/arm_interrupt/src/main.c b/tests/arch/arm/arm_interrupt/src/main.c index 132d7195f25..db79577917b 100644 --- a/tests/arch/arm/arm_interrupt/src/main.c +++ b/tests/arch/arm/arm_interrupt/src/main.c @@ -7,10 +7,12 @@ #include extern void test_arm_interrupt(void); +extern void test_arm_user_interrupt(void); void test_main(void) { ztest_test_suite(arm_interrupt, - ztest_unit_test(test_arm_interrupt)); + ztest_unit_test(test_arm_interrupt), + ztest_user_unit_test(test_arm_user_interrupt)); ztest_run_test_suite(arm_interrupt); } diff --git a/tests/arch/arm/arm_interrupt/src/test_syscalls.h b/tests/arch/arm/arm_interrupt/src/test_syscalls.h new file mode 100644 index 00000000000..9a2bdafdc8f --- /dev/null +++ b/tests/arch/arm/arm_interrupt/src/test_syscalls.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _TEST_SYSCALLS_H_ +#define _TEST_SYSCALLS_H_ +#include + +__syscall void test_arm_user_interrupt_syscall(void); + +#include + +#endif /* _TEST_SYSCALLS_H_ */