ctxp corrupted in _port_irq_epilogue

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: ctxp corrupted in _port_irq_epilogue

Post by Giovanni »

About this:

Code: Select all

#define CORTEX_PRIORITY_SVCALL 8


This means that all IRQs with priorities from 0 to 8 are "fast" and must not use the prologue/epilogue macros, on the other hand priorities between 9 to 15 must use macros, is this confirmed?
Some HAL drivers use priorities in the range 2 to 8, are you using any of those? drivers are not designed to operate in "fast" priorities range.

Giovanni
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: ctxp corrupted in _port_irq_epilogue

Post by Giovanni »

Uhm, stop everything.

This:

Code: Select all

#define PORT_INT_REQUIRED_STACK 128
#define PORT_IDLE_THREAD_STACK_SIZE 512


Those values are way too high, we have an allocated area of 0x400 for the process stack, those sizes already take 640 bytes, add intctx and exctx structures and the effective stack used by main(), an overflow of the process stack is very likely.

Please use the default values fixed in 2.6.4:

Code: Select all

#define PORT_INT_REQUIRED_STACK 16
#define PORT_IDLE_THREAD_STACK_SIZE 64


Alternatively increase the process stack size. I think the process stack is overwriting the main stack.

Look at the SP register position in the main function after executing chSysInit() for confirmation.

Giovanni
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: ctxp corrupted in _port_irq_epilogue

Post by Giovanni »

Err, PORT_IDLE_THREAD_STACK_SIZE is not related to that stack...

PORT_INT_REQUIRED_STACK(128) + exctx(104) + intctx(100) = 332 bytes taken from the context, not enough....
AndreR
Posts: 24
Joined: Mon Apr 28, 2014 2:01 pm

Re: ctxp corrupted in _port_irq_epilogue

Post by AndreR »

IRQ levels are confirmed. DMA IRQ at lvl 12, timers at 3-5, no other IRQ enabled, checked in NVIC.
The ChibiOS HAL is not even part of my project, I use the old and new fwlib from ST for init stuff (simply more readable), but prefer register access for the fast stuff.

Code: Select all

#define PORT_IDLE_THREAD_STACK_SIZE 64

Idle thread stack overflows immediately, probably due to my idle tick hook which requires some more stack. 128 works fine.

Code: Select all

#define PORT_INT_REQUIRED_STACK 16

Doesn't change anything, but I will stick to this value.

Write to 0x10000400 also occurs in release build (-Os), at exactly the same instruction. Looks like such writes beyond the stack also occurs on other stacks, checked that in debugger memory view.

Providing an MWE is difficult because I have data incomming via SPI and the timers are controlling two motors with attached encoders.
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: ctxp corrupted in _port_irq_epilogue

Post by Giovanni »

Have to ask, are you using the chibiOS startup and scatter files? there are FPU related initializations there. Also, those 0x10000xxx addresses do not belong to the internal RAM.

BTW, I suggested the wrong value, PORT_INT_STACK_SIZE should be 32 but it is unrelated to your problem.

Giovanni
AndreR
Posts: 24
Joined: Mon Apr 28, 2014 2:01 pm

Re: ctxp corrupted in _port_irq_epilogue

Post by AndreR »

Yes, here is crt0.c

Code: Select all

/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
                 2011,2012,2013 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

                                      ---

    A special exception to the GPL can be applied should you wish to distribute
    a combined work that includes ChibiOS/RT, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/

/**
 * @file    ARMCMx/crt0.c
 * @brief   Generic ARMvx-M (Cortex-M0/M1/M3/M4) startup file for ChibiOS/RT.
 *
 * @addtogroup ARMCMx_STARTUP
 * @{
 */

#include <stdint.h>

#if !defined(FALSE)
#define FALSE       0
#endif

#if !defined(TRUE)
#define TRUE        (!FALSE)
#endif

#define SCB_CPACR               *((uint32_t *)0xE000ED88U)
#define SCB_FPCCR               *((uint32_t *)0xE000EF34U)
#define SCB_FPDSCR              *((uint32_t *)0xE000EF3CU)
#define FPCCR_ASPEN             (0x1U << 31)
#define FPCCR_LSPEN             (0x1U << 30)

typedef void (*funcp_t)(void);
typedef funcp_t * funcpp_t;

#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))

/*
 * Area fill code, it is a macro because here functions cannot be called
 * until stacks are initialized.
 */
#define fill32(start, end, filler) {                                        \
  uint32_t *p1 = start;                                                     \
  uint32_t *p2 = end;                                                       \
  while (p1 < p2)                                                           \
    *p1++ = filler;                                                         \
}

/*===========================================================================*/
/**
 * @name    Startup settings
 * @{
 */
/*===========================================================================*/

/**
 * @brief   Control special register initialization value.
 * @details The system is setup to run in privileged mode using the PSP
 *          stack (dual stack mode).
 */
#if !defined(CRT0_CONTROL_INIT) || defined(__DOXYGEN__)
#define CRT0_CONTROL_INIT           0x00000002
#endif

/**
 * @brief   Stack segments initialization switch.
 */
#if !defined(CRT0_STACKS_FILL_PATTERN) || defined(__DOXYGEN__)
#define CRT0_STACKS_FILL_PATTERN    0x55555555
#endif

/**
 * @brief   Stack segments initialization switch.
 */
#if !defined(CRT0_INIT_STACKS) || defined(__DOXYGEN__)
#define CRT0_INIT_STACKS            TRUE
#endif

/**
 * @brief   DATA segment initialization switch.
 */
#if !defined(CRT0_INIT_DATA) || defined(__DOXYGEN__)
#define CRT0_INIT_DATA              TRUE
#endif

#if !defined(CRT0_INIT_CCM) || defined(__DOXYGEN__)
#define CRT0_INIT_CCM              TRUE
#endif

/**
 * @brief   BSS segment initialization switch.
 */
#if !defined(CRT0_INIT_BSS) || defined(__DOXYGEN__)
#define CRT0_INIT_BSS               TRUE
#endif

/**
 * @brief   Constructors invocation switch.
 */
#if !defined(CRT0_CALL_CONSTRUCTORS) || defined(__DOXYGEN__)
#define CRT0_CALL_CONSTRUCTORS      TRUE
#endif

/**
 * @brief   Destructors invocation switch.
 */
#if !defined(CRT0_CALL_DESTRUCTORS) || defined(__DOXYGEN__)
#define CRT0_CALL_DESTRUCTORS       TRUE
#endif

/** @} */

/*===========================================================================*/
/**
 * @name    Symbols from the scatter file
 */
/*===========================================================================*/

/**
 * @brief   Main stack lower boundary.
 * @details This symbol must be exported by the linker script and represents
 *          the main stack lower boundary.
 */
extern uint32_t __main_stack_base__;

/**
 *
 * @brief   Main stack initial position.
 * @details This symbol must be exported by the linker script and represents
 *          the main stack initial position.
 */
extern uint32_t __main_stack_end__;

/**
 * @brief   Process stack lower boundary.
 * @details This symbol must be exported by the linker script and represents
 *          the process stack lower boundary.
 */
extern uint32_t __process_stack_base__;

/**
 * @brief   Process stack initial position.
 * @details This symbol must be exported by the linker script and represents
 *          the process stack initial position.
 */
extern uint32_t __process_stack_end__;

/**
 * @brief   ROM image of the data segment start.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern uint32_t _textdata;

/**
 * @brief   Data segment start.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern uint32_t _data;

/**
 * @brief   Data segment end.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern uint32_t _edata;

extern uint32_t _ccmtext_data;   // ROM image of CCM code segment
extern uint32_t _ccmtext_start;   // load address in CCM (start)
extern uint32_t _ccmtext_end;   // last address for loading

/**
 * @brief   BSS segment start.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern uint32_t _bss_start;

/**
 * @brief   BSS segment end.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern uint32_t _bss_end;

/**
 * @brief   Constructors table start.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern funcp_t __init_array_start;

/**
 * @brief   Constructors table end.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern funcp_t __init_array_end;

/**
 * @brief   Destructors table start.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern funcp_t __fini_array_start;

/**
 * @brief   Destructors table end.
 * @pre     The symbol must be aligned to a 32 bits boundary.
 */
extern funcp_t __fini_array_end;

/** @} */

/**
 * @brief   Application @p main() function.
 */
extern void main(void);

/**
 * @brief   Early initialization.
 * @details This hook is invoked immediately after the stack initialization
 *          and before the DATA and BSS segments initialization. The
 *          default behavior is to do nothing.
 * @note    This function is a weak symbol.
 */
#if !defined(__DOXYGEN__)
__attribute__((weak))
#endif
void __early_init(void) {}

/**
 * @brief   Late initialization.
 * @details This hook is invoked after the DATA and BSS segments
 *          initialization and before any static constructor. The
 *          default behavior is to do nothing.
 * @note    This function is a weak symbol.
 */
#if !defined(__DOXYGEN__)
__attribute__((weak))
#endif
void __late_init(void) {}

/**
 * @brief   Default @p main() function exit handler.
 * @details This handler is invoked or the @p main() function exit. The
 *          default behavior is to enter an infinite loop.
 * @note    This function is a weak symbol.
 */
#if !defined(__DOXYGEN__)
__attribute__((weak, naked))
#endif
void _default_exit(void) {
  while (1)
    ;
}

/**
 * @brief   Reset vector.
 */
#if !defined(__DOXYGEN__)
__attribute__((used, naked))
#endif
void ResetHandler(void) {
  uint32_t psp, reg;

  /* Process Stack initialization, it is allocated starting from the
     symbol __process_stack_end__ and its lower limit is the symbol
     __process_stack_base__.*/
  asm volatile ("cpsid   i");
  psp = SYMVAL(__process_stack_end__);
  asm volatile ("msr     PSP, %0" : : "r" (psp));

#if CORTEX_USE_FPU
  /* Initializing the FPU context save in lazy mode.*/
  SCB_FPCCR = FPCCR_ASPEN | FPCCR_LSPEN;

  /* CP10 and CP11 set to full access.*/
  SCB_CPACR |= 0x00F00000;

  /* FPSCR and FPDSCR initially zero.*/
  reg = 0;
  asm volatile ("vmsr    FPSCR, %0" : : "r" (reg) : "memory");
  SCB_FPDSCR = reg;

  /* CPU mode initialization, enforced FPCA bit.*/
  reg = CRT0_CONTROL_INIT | 4;
#else
  /* CPU mode initialization.*/
  reg = CRT0_CONTROL_INIT;
#endif
  asm volatile ("msr     CONTROL, %0" : : "r" (reg));
  asm volatile ("isb");

#if CRT0_INIT_STACKS
  /* Main and Process stacks initialization.*/
  fill32(&__main_stack_base__,
         &__main_stack_end__,
         CRT0_STACKS_FILL_PATTERN);
  fill32(&__process_stack_base__,
         &__process_stack_end__,
         CRT0_STACKS_FILL_PATTERN);
#endif

  /* Early initialization hook invocation.*/
  __early_init();

#if CRT0_INIT_DATA
  /* DATA segment initialization.*/
  {
    uint32_t *tp, *dp;

    tp = &_textdata;
    dp = &_data;
    while (dp < &_edata)
      *dp++ = *tp++;
  }
#endif

#if CRT0_INIT_CCM
  /* CCM segment initialization.*/
  {
    uint32_t *tp, *dp;

    tp = &_ccmtext_data;
    dp = &_ccmtext_start;
    while (dp < &_ccmtext_end)
      *dp++ = *tp++;
  }
#endif

#if CRT0_INIT_BSS
  /* BSS segment initialization.*/
  fill32(&_bss_start, &_bss_end, 0);
#endif

  /* Late initialization hook invocation.*/
  __late_init();

#if CRT0_CALL_CONSTRUCTORS
  /* Constructors invocation.*/
  {
    funcpp_t fpp = &__init_array_start;
    while (fpp < &__init_array_end) {
      (*fpp)();
      fpp++;
    }
  }
#endif

  /* Invoking application main() function.*/
  main();

#if CRT0_CALL_DESTRUCTORS
  /* Destructors invocation.*/
  {
    funcpp_t fpp = &__fini_array_start;
    while (fpp < &__fini_array_end) {
      (*fpp)();
      fpp++;
    }
  }
#endif

  /* Invoking the exit handler.*/
  _default_exit();
}

/** @} */
AndreR
Posts: 24
Joined: Mon Apr 28, 2014 2:01 pm

Re: ctxp corrupted in _port_irq_epilogue

Post by AndreR »

And here the scatter file, modified it to put code in the CCM.

Code: Select all

/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
                 2011,2012,2013 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

                                      ---

    A special exception to the GPL can be applied should you wish to distribute
    a combined work that includes ChibiOS/RT, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/

__main_stack_size__     = 0x0400;
__process_stack_size__  = 0x0400;

MEMORY
{
   EEPROM : org = 0x08008000, len = 2k
    flash : org = 0x08008800, len = 94k
    ram : org = 0x20000000, len = 32k
    ccmram : org = 0x10000000, len = 8000
   BOOT : org = 0x10001F40, len = 192
}

__ram_start__           = ORIGIN(ram);
__ram_size__            = LENGTH(ram);
__ram_end__             = __ram_start__ + __ram_size__;

ENTRY(ResetHandler)

SECTIONS
{
    . = 0;
    _text = .;

    .eeprom (NOLOAD) :
   {
       . = ALIGN(4);
       *(.eeprom)
       . = ALIGN(4);
   } >EEPROM

   startup : ALIGN(16) SUBALIGN(16)
    {
        KEEP(*(vectors))
    } > flash

    constructors : ALIGN(4) SUBALIGN(4)
    {
        PROVIDE(__init_array_start = .);
        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array))
        PROVIDE(__init_array_end = .);
    } > flash

    destructors : ALIGN(4) SUBALIGN(4)
    {
        PROVIDE(__fini_array_start = .);
        KEEP(*(.fini_array))
        KEEP(*(SORT(.fini_array.*)))
        PROVIDE(__fini_array_end = .);
    } > flash
   
    .text : ALIGN(16) SUBALIGN(16)
    {
        *(.text.startup.*)
        *(.text)
        *(.text.*)
        *(.rodata)
        *(.rodata.*)
        *(.glue_7t)
        *(.glue_7)
        *(.gcc*)
    } > flash

    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > flash

    .ARM.exidx : {
        PROVIDE(__exidx_start = .);
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        PROVIDE(__exidx_end = .);
     } > flash

    .eh_frame_hdr :
    {
        *(.eh_frame_hdr)
    } > flash

    .eh_frame : ONLY_IF_RO
    {
        *(.eh_frame)
    } > flash
   
    .textalign : ONLY_IF_RO
    {
        . = ALIGN(8);
    } > flash

    . = ALIGN(4);
    _etext = .;
   
     _ccmtext_data = LOADADDR(.ccmtext);
   _textdata = LOADADDR(.data);
 
    .stacks :
    {
        . = ALIGN(8);
        __main_stack_base__ = .;
        . += __main_stack_size__;
        . = ALIGN(8);
        __main_stack_end__ = .;
        __process_stack_base__ = .;
        __main_thread_stack_base__ = .;
        . += __process_stack_size__;
        . = ALIGN(8);
        __process_stack_end__ = .;
        __main_thread_stack_end__ = .;
    } > ccmram

    .ccm :
    {
        PROVIDE(_cmm_start = .);
        . = ALIGN(4);
        *(.bss.mainthread.*)
        . = ALIGN(4);
        *(.bss._idle_thread_wa)
        . = ALIGN(4);
        *(.bss.rlist)
        . = ALIGN(4);
        *(.bss.vtlist)
        . = ALIGN(4);
        *(.bss.endmem)
        . = ALIGN(4);
        *(.bss.nextmem)
        . = ALIGN(4);
        *(.bss.default_heap)
        . = ALIGN(4);
        *(.bss._ccm_wa*)
        . = ALIGN(4);
        PROVIDE(_cmm_end = .);
   } > ccmram
   
    .ccmtext :
    {
       PROVIDE(_ccmtext_start = .);
       . = ALIGN(4);
       *(.ccmtext*)
       *(.ccmtext.*)
       . = ALIGN(4);
       PROVIDE(_ccmtext_end = .);
    } > ccmram AT > flash
   
    .data :
    {
        . = ALIGN(4);
        PROVIDE(_data = .);
        *(.data)
        . = ALIGN(4);
        *(.data.*)
        . = ALIGN(4);
        *(.ramtext)
        . = ALIGN(4);
        PROVIDE(_edata = .);
    } > ram AT > flash

    .bss :
    {
        . = ALIGN(4);
        PROVIDE(_bss_start = .);
        *(.bss)
        . = ALIGN(4);
        *(.bss.*)
        . = ALIGN(4);
        *(COMMON)
        . = ALIGN(4);
        PROVIDE(_bss_end = .);
        PROVIDE(end = .);
      _end            = .;
    } > ram   
   
   .boot_bss (NOLOAD) :
   {
      *(.boot)         /* .boot sections (variables) */
      *(.boot*)        /* .boot* sections (variables)  */
   } >BOOT
}

__heap_base__   = _end;
__heap_end__    = __ram_end__;
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: ctxp corrupted in _port_irq_epilogue

Post by Giovanni »

It is a strange setup, hard to do debug without something to test...

In your screenshot the value of the FPxxx registers pointed by ctxp look corrupted, probably that is the cause of the exception.

Giovanni
AndreR
Posts: 24
Joined: Mon Apr 28, 2014 2:01 pm

Re: ctxp corrupted in _port_irq_epilogue

Post by AndreR »

Okay, here is one to think about: I just desperately tried a shot in the dark :)

I did this:

Code: Select all

//      asm volatile ("vmrs    APSR_nzcv, FPSCR" : : : "memory");


I have no idea, what this thing is doing/should do or which sideeffects appear with it, BUT everything is running fine in debug for more than 15mins now :o

Any explanation???
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: ctxp corrupted in _port_irq_epilogue

Post by Giovanni »

That line triggers an automatic store in the stack frame, by removing that some FP registers are not saved across a context switch triggered by a preemption. You are just removing the symptom I think.

I still think this can only be cause by a stack corruption, I would look for stack overflows or underflows.

What compiler version are you using? it is also possible we are hitting some compiler issue.

Giovanni
Post Reply