/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup RTEMSTestCaseBspReqInterruptSpurious */ /* * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * This file is part of the RTEMS quality process and was automatically * generated. If you find something that needs to be fixed or * worded better please post a report or patch to an RTEMS mailing list * or raise a bug report: * * https://www.rtems.org/bugs.html * * For information on updating and regenerating please refer to the How-To * section in the Software Requirements Engineering chapter of the * RTEMS Software Engineering manual. The manual is provided as a part of * a release. For development sources please refer to the online * documentation at: * * https://docs.rtems.org */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "tx-support.h" #include /** * @defgroup RTEMSTestCaseBspReqInterruptSpurious \ * spec:/bsp/req/interrupt-spurious * * @ingroup RTEMSTestSuiteTestsuitesValidationSmpOnly0 * * @{ */ typedef enum { BspReqInterruptSpurious_Pre_First_Null, BspReqInterruptSpurious_Pre_First_Entry, BspReqInterruptSpurious_Pre_First_NA } BspReqInterruptSpurious_Pre_First; typedef enum { BspReqInterruptSpurious_Post_Result_FatalError, BspReqInterruptSpurious_Post_Result_Dispatch, BspReqInterruptSpurious_Post_Result_NA } BspReqInterruptSpurious_Post_Result; typedef enum { BspReqInterruptSpurious_Post_FatalSource_SpuriousInterrupt, BspReqInterruptSpurious_Post_FatalSource_NA } BspReqInterruptSpurious_Post_FatalSource; typedef enum { BspReqInterruptSpurious_Post_FatalCode_Vector, BspReqInterruptSpurious_Post_FatalCode_NA } BspReqInterruptSpurious_Post_FatalCode; typedef struct { uint8_t Skip : 1; uint8_t Pre_First_NA : 1; uint8_t Post_Result : 2; uint8_t Post_FatalSource : 1; uint8_t Post_FatalCode : 1; } BspReqInterruptSpurious_Entry; /** * @brief Test context for spec:/bsp/req/interrupt-spurious test case. */ typedef struct { /** * @brief This member provides a jump buffer to return from the fatal error. */ jmp_buf before_call; /** * @brief This member provides an interrupt entry to be dispatched. */ rtems_interrupt_entry entry; /** * @brief If this member is true, then the interrupt shall be cleared. */ bool do_clear; /** * @brief This member is true, then an interrupt occurred. */ volatile bool interrupt_occurred; /** * @brief This member provides an entry dispatch counter. */ uint32_t entry_counter; /** * @brief This member provides a fatal error counter. */ uint32_t fatal_counter; /** * @brief This member contains the fatal source. */ rtems_fatal_source fatal_source; /** * @brief This member contains a fatal code. */ rtems_fatal_code fatal_code; /** * @brief This member contains the vector number of a testable interrupt. */ rtems_vector_number test_vector; /** * @brief This member references the pointer to the first entry of the * interrupt vector. */ rtems_interrupt_entry **first; struct { /** * @brief This member defines the pre-condition states for the next action. */ size_t pcs[ 1 ]; /** * @brief If this member is true, then the test action loop is executed. */ bool in_action_loop; /** * @brief This member contains the next transition map index. */ size_t index; /** * @brief This member contains the current transition map entry. */ BspReqInterruptSpurious_Entry entry; /** * @brief If this member is true, then the current transition variant * should be skipped. */ bool skip; } Map; } BspReqInterruptSpurious_Context; static BspReqInterruptSpurious_Context BspReqInterruptSpurious_Instance; static const char * const BspReqInterruptSpurious_PreDesc_First[] = { "Null", "Entry", "NA" }; static const char * const * const BspReqInterruptSpurious_PreDesc[] = { BspReqInterruptSpurious_PreDesc_First, NULL }; typedef BspReqInterruptSpurious_Context Context; static bool test_case_active; static void Disable( const Context *ctx ) { (void) rtems_interrupt_vector_disable( ctx->test_vector ); } static void ProcessInterrupt( Context *ctx ) { ctx->interrupt_occurred = true; if ( ctx->do_clear ) { rtems_status_code sc; sc = rtems_interrupt_clear( ctx->test_vector ); T_rsc_success( sc ); } Disable( ctx ); } static void EntryRoutine( void *arg ) { Context *ctx; ctx = arg; ++ctx->entry_counter; ProcessInterrupt( ctx ); } static void Fatal( rtems_fatal_source source, rtems_fatal_code code, void *arg ) { Context *ctx; ctx = arg; ctx->fatal_source = source; ctx->fatal_code = code; ++ctx->fatal_counter; longjmp( ctx->before_call, 1 ); } void __real_bsp_interrupt_handler_default( rtems_vector_number vector ); void __wrap_bsp_interrupt_handler_default( rtems_vector_number vector ); void __wrap_bsp_interrupt_handler_default( rtems_vector_number vector ) { if ( test_case_active ) { Context *ctx; ctx = T_fixture_context(); ProcessInterrupt( ctx ); if ( setjmp( ctx->before_call ) == 0 ) { __real_bsp_interrupt_handler_default( vector ); } } else { __real_bsp_interrupt_handler_default( vector ); } } static void BspReqInterruptSpurious_Pre_First_Prepare( BspReqInterruptSpurious_Context *ctx, BspReqInterruptSpurious_Pre_First state ) { switch ( state ) { case BspReqInterruptSpurious_Pre_First_Null: { /* * While the pointer to the first interrupt entry of the interrupt vector * specified by the ``vector`` parameter is equal to NULL. */ *ctx->first = NULL; break; } case BspReqInterruptSpurious_Pre_First_Entry: { /* * While the pointer to the first interrupt entry of the interrupt vector * specified by the ``vector`` parameter references an object of type * rtems_interrupt_entry. */ *ctx->first = &ctx->entry; break; } case BspReqInterruptSpurious_Pre_First_NA: break; } } static void BspReqInterruptSpurious_Post_Result_Check( BspReqInterruptSpurious_Context *ctx, BspReqInterruptSpurious_Post_Result state ) { switch ( state ) { case BspReqInterruptSpurious_Post_Result_FatalError: { /* * A fatal error shall occur. */ T_eq_u32( ctx->entry_counter, 0 ); T_eq_u32( ctx->fatal_counter, 1 ); break; } case BspReqInterruptSpurious_Post_Result_Dispatch: { /* * The interrupt entries installed at the interrupt vector specified by * the ``vector`` parameter shall be dispatched. */ T_eq_u32( ctx->entry_counter, 1 ); T_eq_u32( ctx->fatal_counter, 0 ); break; } case BspReqInterruptSpurious_Post_Result_NA: break; } } static void BspReqInterruptSpurious_Post_FatalSource_Check( BspReqInterruptSpurious_Context *ctx, BspReqInterruptSpurious_Post_FatalSource state ) { switch ( state ) { case BspReqInterruptSpurious_Post_FatalSource_SpuriousInterrupt: { /* * The fatal source shall be equal to * RTEMS_FATAL_SOURCE_SPURIOUS_INTERRUPT. */ T_eq_int( ctx->fatal_source, RTEMS_FATAL_SOURCE_SPURIOUS_INTERRUPT ); break; } case BspReqInterruptSpurious_Post_FatalSource_NA: break; } } static void BspReqInterruptSpurious_Post_FatalCode_Check( BspReqInterruptSpurious_Context *ctx, BspReqInterruptSpurious_Post_FatalCode state ) { switch ( state ) { case BspReqInterruptSpurious_Post_FatalCode_Vector: { /* * The fatal code shall be equal to the ``vector`` parameter. */ T_eq_ulong( ctx->fatal_code, ctx->test_vector ); break; } case BspReqInterruptSpurious_Post_FatalCode_NA: break; } } static void BspReqInterruptSpurious_Setup( BspReqInterruptSpurious_Context *ctx ) { rtems_interrupt_attributes attr = { .can_raise = true }; rtems_status_code sc; ctx->test_vector = GetTestableInterruptVector( &attr ); T_assert_lt_u32( ctx->test_vector, BSP_INTERRUPT_VECTOR_COUNT ); ctx->first = &bsp_interrupt_handler_table[ bsp_interrupt_handler_index( ctx->test_vector ) ]; sc = rtems_interrupt_get_attributes( ctx->test_vector, &attr ); T_rsc_success( sc ); ctx->do_clear = attr.can_clear && !attr.cleared_by_acknowledge; rtems_interrupt_entry_initialize( &ctx->entry, EntryRoutine, ctx, "Info" ); test_case_active = true; SetFatalHandler( Fatal, ctx ); } static void BspReqInterruptSpurious_Setup_Wrap( void *arg ) { BspReqInterruptSpurious_Context *ctx; ctx = arg; ctx->Map.in_action_loop = false; BspReqInterruptSpurious_Setup( ctx ); } static void BspReqInterruptSpurious_Teardown( BspReqInterruptSpurious_Context *ctx ) { SetFatalHandler( NULL, NULL ); test_case_active = false; } static void BspReqInterruptSpurious_Teardown_Wrap( void *arg ) { BspReqInterruptSpurious_Context *ctx; ctx = arg; ctx->Map.in_action_loop = false; BspReqInterruptSpurious_Teardown( ctx ); } static void BspReqInterruptSpurious_Action( BspReqInterruptSpurious_Context *ctx ) { ctx->interrupt_occurred = false; ctx->entry_counter = 0; ctx->fatal_counter = 0; ctx->fatal_source = RTEMS_FATAL_SOURCE_LAST; ctx->fatal_code = UINT32_MAX; if ( *ctx->first == NULL ) { rtems_status_code sc; (void) rtems_interrupt_vector_enable( ctx->test_vector ); sc = rtems_interrupt_raise( ctx->test_vector ); T_rsc_success( sc ); while ( !ctx->interrupt_occurred ) { /* Wait */ } Disable( ctx ); } else { bsp_interrupt_spurious( ctx->test_vector ); } } static const BspReqInterruptSpurious_Entry BspReqInterruptSpurious_Entries[] = { { 0, 0, BspReqInterruptSpurious_Post_Result_FatalError, BspReqInterruptSpurious_Post_FatalSource_SpuriousInterrupt, BspReqInterruptSpurious_Post_FatalCode_Vector }, { 0, 0, BspReqInterruptSpurious_Post_Result_Dispatch, BspReqInterruptSpurious_Post_FatalSource_NA, BspReqInterruptSpurious_Post_FatalCode_NA } }; static const uint8_t BspReqInterruptSpurious_Map[] = { 0, 1 }; static size_t BspReqInterruptSpurious_Scope( void *arg, char *buf, size_t n ) { BspReqInterruptSpurious_Context *ctx; ctx = arg; if ( ctx->Map.in_action_loop ) { return T_get_scope( BspReqInterruptSpurious_PreDesc, buf, n, ctx->Map.pcs ); } return 0; } static T_fixture BspReqInterruptSpurious_Fixture = { .setup = BspReqInterruptSpurious_Setup_Wrap, .stop = NULL, .teardown = BspReqInterruptSpurious_Teardown_Wrap, .scope = BspReqInterruptSpurious_Scope, .initial_context = &BspReqInterruptSpurious_Instance }; static inline BspReqInterruptSpurious_Entry BspReqInterruptSpurious_PopEntry( BspReqInterruptSpurious_Context *ctx ) { size_t index; index = ctx->Map.index; ctx->Map.index = index + 1; return BspReqInterruptSpurious_Entries[ BspReqInterruptSpurious_Map[ index ] ]; } static void BspReqInterruptSpurious_TestVariant( BspReqInterruptSpurious_Context *ctx ) { BspReqInterruptSpurious_Pre_First_Prepare( ctx, ctx->Map.pcs[ 0 ] ); BspReqInterruptSpurious_Action( ctx ); BspReqInterruptSpurious_Post_Result_Check( ctx, ctx->Map.entry.Post_Result ); BspReqInterruptSpurious_Post_FatalSource_Check( ctx, ctx->Map.entry.Post_FatalSource ); BspReqInterruptSpurious_Post_FatalCode_Check( ctx, ctx->Map.entry.Post_FatalCode ); } /** * @fn void T_case_body_BspReqInterruptSpurious( void ) */ T_TEST_CASE_FIXTURE( BspReqInterruptSpurious, &BspReqInterruptSpurious_Fixture ) { BspReqInterruptSpurious_Context *ctx; ctx = T_fixture_context(); ctx->Map.in_action_loop = true; ctx->Map.index = 0; for ( ctx->Map.pcs[ 0 ] = BspReqInterruptSpurious_Pre_First_Null; ctx->Map.pcs[ 0 ] < BspReqInterruptSpurious_Pre_First_NA; ++ctx->Map.pcs[ 0 ] ) { ctx->Map.entry = BspReqInterruptSpurious_PopEntry( ctx ); BspReqInterruptSpurious_TestVariant( ctx ); } } /** @} */