summaryrefslogblamecommitdiffstats
path: root/testsuites/validation/tc-bsp-interrupt-spurious.c
blob: f1230cb7e061c0ccaba32eb4b95703c1a0ae892f (plain) (tree)
































































                                                                              
                                                  










                                          





                                               

















                                                             
                                









                                                                      





                                                                             









                                                                              


































                                                                           





                                                                            

          





                                                                        

                                                                               
                    
































                                                                            





                                                                          

                                                                       
                                             














                                                            
                       






















































                                                                        


                                                                               






                                                   


                                                                            









                                              






























                                                                               








































































                                                                             

                                              
                                                                  

                                                    
    
                                      




















                                                                             



                                        




















                                                              






                                                          
                                                             
 
                         
 





                                        



                                          




                                                            

                                                               






                                                               

                                                




                                                               



                                 
            








































                                                                             












                                                                  




                                                                      
                                                                           


























                                                                               


                                                               
     








                                                                      



         
/* 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 <setjmp.h>
#include <bsp/irq-generic.h>

#include "tx-support.h"

#include <rtems/test.h>

/**
 * @defgroup RTEMSTestCaseBspReqInterruptSpurious \
 *   spec:/bsp/req/interrupt-spurious
 *
 * @ingroup RTEMSTestSuiteTestsuitesValidationIntr
 *
 * @{
 */

typedef enum {
  BspReqInterruptSpurious_Pre_First_Null,
  BspReqInterruptSpurious_Pre_First_Entry,
  BspReqInterruptSpurious_Pre_First_NA
} BspReqInterruptSpurious_Pre_First;

typedef enum {
  BspReqInterruptSpurious_Pre_FirstAgain_Null,
  BspReqInterruptSpurious_Pre_FirstAgain_Entry,
  BspReqInterruptSpurious_Pre_FirstAgain_NA
} BspReqInterruptSpurious_Pre_FirstAgain;

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 Pre_FirstAgain_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 references the interrupt entry to restore during test
   *   case teardown.
   */
  rtems_interrupt_entry *entry_to_restore;

  /**
   * @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 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;

  /**
   * @brief This member references an interrupt entry for the first entry of
   *   the interrupt vector or is NULL.
   */
  rtems_interrupt_entry *first_again;

  struct {
    /**
     * @brief This member defines the pre-condition indices for the next
     *   action.
     */
    size_t pci[ 2 ];

    /**
     * @brief This member defines the pre-condition states for the next action.
     */
    size_t pcs[ 2 ];

    /**
     * @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 BspReqInterruptSpurious_PreDesc_FirstAgain[] = {
  "Null",
  "Entry",
  "NA"
};

static const char * const * const BspReqInterruptSpurious_PreDesc[] = {
  BspReqInterruptSpurious_PreDesc_First,
  BspReqInterruptSpurious_PreDesc_FirstAgain,
  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;
  CallWithinISRClear();
  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 first loaded value of 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 first loaded value of 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_Pre_FirstAgain_Prepare(
  BspReqInterruptSpurious_Context       *ctx,
  BspReqInterruptSpurious_Pre_FirstAgain state
)
{
  switch ( state ) {
    case BspReqInterruptSpurious_Pre_FirstAgain_Null: {
      /*
       * While the second loaded value of the pointer to the first interrupt
       * entry of the interrupt vector specified by the ``vector`` parameter is
       * equal to NULL.
       */
      ctx->first_again = NULL;
      break;
    }

    case BspReqInterruptSpurious_Pre_FirstAgain_Entry: {
      /*
       * While the second loaded value of 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_again = &ctx->entry;
      break;
    }

    case BspReqInterruptSpurious_Pre_FirstAgain_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
)
{
  ctx->first = NULL;
  ctx->test_vector = CallWithinISRGetVector();
  T_assert_lt_u32( ctx->test_vector, BSP_INTERRUPT_VECTOR_COUNT );
  ctx->first = &bsp_interrupt_dispatch_table[
    bsp_interrupt_dispatch_index( ctx->test_vector )
  ];
  ctx->entry_to_restore = *ctx->first;

  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;

  if ( ctx->first != NULL ) {
    *ctx->first = ctx->entry_to_restore;
  }
}

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 defined(RTEMS_SMP)
  if ( *ctx->first == NULL && ctx->first_again != NULL ) {
    *ctx->first = ctx->first_again;
    bsp_interrupt_spurious( ctx->test_vector );
  } else
  #endif
  {
    (void) rtems_interrupt_vector_enable( ctx->test_vector );

    CallWithinISRRaise();

    while ( !ctx->interrupt_occurred ) {
      /* Wait */
    }

    Disable( ctx );
  }
}

static const BspReqInterruptSpurious_Entry
BspReqInterruptSpurious_Entries[] = {
  { 0, 0, 1, BspReqInterruptSpurious_Post_Result_Dispatch,
    BspReqInterruptSpurious_Post_FatalSource_NA,
    BspReqInterruptSpurious_Post_FatalCode_NA },
#if defined(RTEMS_SMP)
  { 0, 0, 0, BspReqInterruptSpurious_Post_Result_FatalError,
    BspReqInterruptSpurious_Post_FatalSource_SpuriousInterrupt,
    BspReqInterruptSpurious_Post_FatalCode_Vector },
#else
  { 0, 0, 1, BspReqInterruptSpurious_Post_Result_FatalError,
    BspReqInterruptSpurious_Post_FatalSource_SpuriousInterrupt,
    BspReqInterruptSpurious_Post_FatalCode_Vector },
#endif
#if defined(RTEMS_SMP)
  { 0, 0, 0, BspReqInterruptSpurious_Post_Result_Dispatch,
    BspReqInterruptSpurious_Post_FatalSource_NA,
    BspReqInterruptSpurious_Post_FatalCode_NA }
#else
  { 0, 0, 1, BspReqInterruptSpurious_Post_Result_FatalError,
    BspReqInterruptSpurious_Post_FatalSource_SpuriousInterrupt,
    BspReqInterruptSpurious_Post_FatalCode_Vector }
#endif
};

static const uint8_t
BspReqInterruptSpurious_Map[] = {
  1, 2, 0, 0
};

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_SetPreConditionStates(
  BspReqInterruptSpurious_Context *ctx
)
{
  ctx->Map.pcs[ 0 ] = ctx->Map.pci[ 0 ];

  if ( ctx->Map.entry.Pre_FirstAgain_NA ) {
    ctx->Map.pcs[ 1 ] = BspReqInterruptSpurious_Pre_FirstAgain_NA;
  } else {
    ctx->Map.pcs[ 1 ] = ctx->Map.pci[ 1 ];
  }
}

static void BspReqInterruptSpurious_TestVariant(
  BspReqInterruptSpurious_Context *ctx
)
{
  BspReqInterruptSpurious_Pre_First_Prepare( ctx, ctx->Map.pcs[ 0 ] );
  BspReqInterruptSpurious_Pre_FirstAgain_Prepare( ctx, ctx->Map.pcs[ 1 ] );
  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.pci[ 0 ] = BspReqInterruptSpurious_Pre_First_Null;
    ctx->Map.pci[ 0 ] < BspReqInterruptSpurious_Pre_First_NA;
    ++ctx->Map.pci[ 0 ]
  ) {
    for (
      ctx->Map.pci[ 1 ] = BspReqInterruptSpurious_Pre_FirstAgain_Null;
      ctx->Map.pci[ 1 ] < BspReqInterruptSpurious_Pre_FirstAgain_NA;
      ++ctx->Map.pci[ 1 ]
    ) {
      ctx->Map.entry = BspReqInterruptSpurious_PopEntry( ctx );
      BspReqInterruptSpurious_SetPreConditionStates( ctx );
      BspReqInterruptSpurious_TestVariant( ctx );
    }
  }
}

/** @} */