Commit da3da2d9 authored by Adam Wujek's avatar Adam Wujek 💬 Committed by Grzegorz Daniluk

wrs_main: check for stack overflow and detect reset

Add checking stack overflow and detecting reset to wrs. Code common for wrpc
and wrs is placed in system_checks.c and .h. Work is based on following
commits in wrc_main.c:
1704a668 main: check for stack overflow
7836c39e Optionally detect reset and print a stack trace

Additionally:
--update Kconfig to have a possibility to select CHECK_RESET also for switch,
  not only for node as before
--and _endram to ram-wrs.ld

When "stack overflow" occurs then message is printed once every second.
When reset occours then LM32 will print stack trace and reset once more.
NOTE: I couldn't get spll to work after reset, for sure problem is in
      ad9516 init function, but not only there.
Signed-off-by: Adam Wujek's avatarAdam Wujek <adam.wujek@cern.ch>
parent ee1c7482
...@@ -27,27 +27,31 @@ config RAMSIZE ...@@ -27,27 +27,31 @@ config RAMSIZE
default 131072 default 131072
# CONFIG_WR_SWITCH has no further options at all at this point # CONFIG_WR_SWITCH has no further options at all at this point
if WR_NODE
config STACKSIZE config STACKSIZE
depends on WR_NODE
int int
default 2048 default 2048
config PPSI config PPSI
depends on WR_NODE
boolean boolean
default y default y
config UART config UART
depends on WR_NODE
boolean boolean
default y default y
config W1 config W1
depends on WR_NODE
boolean boolean
default y default y
# The other ones can be set by non-developers # The other ones can be set by non-developers
config ETHERBONE config ETHERBONE
depends on WR_NODE
boolean "Compile Etherbone support in wrpc-sw" boolean "Compile Etherbone support in wrpc-sw"
help help
This allows to run LM32 code that is aware of Etherbone. This allows to run LM32 code that is aware of Etherbone.
...@@ -55,6 +59,7 @@ config ETHERBONE ...@@ -55,6 +59,7 @@ config ETHERBONE
If in doubt, say No. If in doubt, say No.
config WRNIC config WRNIC
depends on WR_NODE
boolean "Compile White Rabbit NIC support in wrpc-sw" boolean "Compile White Rabbit NIC support in wrpc-sw"
help help
This allows to run LM32 code that is aware of Etherbone and This allows to run LM32 code that is aware of Etherbone and
...@@ -63,6 +68,7 @@ config WRNIC ...@@ -63,6 +68,7 @@ config WRNIC
If in doubt, say No. If in doubt, say No.
config CMD_CONFIG config CMD_CONFIG
depends on WR_NODE
boolean "Include configuration in the output binary" boolean "Include configuration in the output binary"
help help
This options adds the "config" command to the shell, which This options adds the "config" command to the shell, which
...@@ -70,6 +76,7 @@ config CMD_CONFIG ...@@ -70,6 +76,7 @@ config CMD_CONFIG
to the binary size (100b for the code plus the .config file). to the binary size (100b for the code plus the .config file).
config NIC_PFILTER config NIC_PFILTER
depends on WR_NODE
depends on ETHERBONE depends on ETHERBONE
bool "Add packet filter rules for wr-nic" bool "Add packet filter rules for wr-nic"
help help
...@@ -93,7 +100,7 @@ config DEVELOPER ...@@ -93,7 +100,7 @@ config DEVELOPER
you are a developer of wrpc-sw. you are a developer of wrpc-sw.
config RAMSIZE config RAMSIZE
depends on DEVELOPER depends on DEVELOPER && WR_NODE
int "Size of the RAM in the FPGA for this program" int "Size of the RAM in the FPGA for this program"
default 90112 default 90112
help help
...@@ -103,7 +110,7 @@ config RAMSIZE ...@@ -103,7 +110,7 @@ config RAMSIZE
choose your preferred value here. choose your preferred value here.
config STACKSIZE config STACKSIZE
depends on DEVELOPER depends on DEVELOPER && WR_NODE
int "Size of the stack area needed by this program" int "Size of the stack area needed by this program"
default 2048 default 2048
help help
...@@ -112,7 +119,7 @@ config STACKSIZE ...@@ -112,7 +119,7 @@ config STACKSIZE
at run time. (However, we have a detector for overflows). at run time. (However, we have a detector for overflows).
config PRINT_BUFSIZE config PRINT_BUFSIZE
depends on DEVELOPER depends on DEVELOPER && WR_NODE
int "Size for the temporary output string of pp_printf" int "Size for the temporary output string of pp_printf"
default 128 default 128
help help
...@@ -120,6 +127,7 @@ config PRINT_BUFSIZE ...@@ -120,6 +127,7 @@ config PRINT_BUFSIZE
also constraints the maximum lenght of text that can be written also constraints the maximum lenght of text that can be written
in a single call to printf. in a single call to printf.
# CHECK_RESET for switch and node
config CHECK_RESET config CHECK_RESET
depends on DEVELOPER depends on DEVELOPER
bool "Print a stack trace if reset happens" bool "Print a stack trace if reset happens"
...@@ -131,7 +139,7 @@ config CHECK_RESET ...@@ -131,7 +139,7 @@ config CHECK_RESET
choice choice
prompt "Implementation of pp_printf" prompt "Implementation of pp_printf"
depends on DEVELOPER depends on DEVELOPER && WR_NODE
config PRINTF_XINT config PRINTF_XINT
bool "hex-and-int" bool "hex-and-int"
...@@ -166,12 +174,13 @@ config PRINTF_NONE ...@@ -166,12 +174,13 @@ config PRINTF_NONE
endchoice endchoice
config PPSI config PPSI
depends on WR_NODE
boolean boolean
help help
Select this option for the ppsi engine (now only option) Select this option for the ppsi engine (now only option)
config DETERMINISTIC_BINARY config DETERMINISTIC_BINARY
depends on DEVELOPER depends on DEVELOPER && WR_NODE
boolean "Build a binary that is the same every time" boolean "Build a binary that is the same every time"
help help
This option is used to #ifdef __DATE__ and __TIME__ strings This option is used to #ifdef __DATE__ and __TIME__ strings
...@@ -185,7 +194,7 @@ config DETERMINISTIC_BINARY ...@@ -185,7 +194,7 @@ config DETERMINISTIC_BINARY
config UART config UART
boolean "Use hardware uart (and/or vuart if available)" boolean "Use hardware uart (and/or vuart if available)"
depends on DEVELOPER depends on DEVELOPER && WR_NODE
default y default y
help help
This option selects the serial driver, connected to either This option selects the serial driver, connected to either
...@@ -193,7 +202,7 @@ config UART ...@@ -193,7 +202,7 @@ config UART
to how the gateware is built. to how the gateware is built.
config UART_SW config UART_SW
depends on DEVELOPER depends on DEVELOPER && WR_NODE
default !UART default !UART
boolean "Use software uart" boolean "Use software uart"
help help
...@@ -204,6 +213,7 @@ config UART_SW ...@@ -204,6 +213,7 @@ config UART_SW
and diagnostics run on the hardware UART if available. and diagnostics run on the hardware UART if available.
config SDB_STORAGE config SDB_STORAGE
depends on WR_NODE
default y default y
boolean "Use SDB to manage storage (instead of legacy eeprom code)" boolean "Use SDB to manage storage (instead of legacy eeprom code)"
help help
...@@ -211,8 +221,8 @@ config SDB_STORAGE ...@@ -211,8 +221,8 @@ config SDB_STORAGE
(eeprom only) will be selected. (eeprom only) will be selected.
config LEGACY_EEPROM config LEGACY_EEPROM
depends on WR_NODE
boolean boolean
default !SDB_STORAGE default !SDB_STORAGE
endif
# CONFIG_WR_NODE # CONFIG_WR_NODE
...@@ -68,6 +68,9 @@ endif ...@@ -68,6 +68,9 @@ endif
# And always complain if we pick the libgcc division: 64/32 = 32 is enough here. # And always complain if we pick the libgcc division: 64/32 = 32 is enough here.
obj-y += check-error.o obj-y += check-error.o
# add system check functions like stack overflow and check reset
obj-y += system_checks.o
obj-$(CONFIG_WR_NODE) += sdb-lib/libsdbfs.a obj-$(CONFIG_WR_NODE) += sdb-lib/libsdbfs.a
cflags-$(CONFIG_WR_NODE) += -Isdb-lib cflags-$(CONFIG_WR_NODE) += -Isdb-lib
......
...@@ -79,6 +79,9 @@ SECTIONS ...@@ -79,6 +79,9 @@ SECTIONS
*(.mbox) *(.mbox)
} > mbox } > mbox
/* End of RAM for checking stack overflows */
PROVIDE(_endram = ORIGIN(stack));
/* First location in stack is highest address in RAM (stack area) */ /* First location in stack is highest address in RAM (stack area) */
PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4); PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4);
} }
......
#ifndef __SYSTEM_CHECKS_H__
#define __SYSTEM_CHECKS_H__
#define ENDRAM_MAGIC 0xbadc0ffe
extern uint32_t _endram;
extern uint32_t _fstack;
void check_stack(void);
void check_reset(void);
void init_hw_after_reset(void);
#endif /* __SYSTEM_CHECKS_H__ */
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2014 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <wrc.h>
#include "system_checks.h"
extern void _reset_handler(void); /* user to reset again */
void check_stack(void)
{
/* print "Stack overflow!" forever if stack corrupted */
while (_endram != ENDRAM_MAGIC) {
mprintf("Stack overflow!\n");
timer_delay_ms(1000);
}
}
#ifdef CONFIG_CHECK_RESET
void check_reset(void)
{
/* static variables to preserve stack (for dumping it) */
static uint32_t *p, *save;
/* _endram is set to ENDRAM_MAGIC after calling this function */
if (_endram != ENDRAM_MAGIC)
return;
/* Before calling anything, find the beginning of the stack */
p = &_endram + 1;
while (!*p)
p++;
p = (void *)((unsigned long)p & ~0xf); /* align */
/* Copy it to the beginning of the stack, then reset pointers */
save = &_endram;
while (p <= &_fstack)
*save++ = *p++;
p -= (save - &_endram);
save = &_endram;
/* Ok, now init the devices so we can printf and delay */
init_hw_after_reset();
pp_printf("\nWarning: the CPU was reset\nStack trace:\n");
while (p < &_fstack) {
pp_printf("%08x: %08x %08x %08x %08x\n",
(int)p, save[0], save[1], save[2], save[3]);
p += 4;
save += 4;
}
pp_printf("Rebooting in 1 second\n\n\n");
timer_delay_ms(1000);
/* Zero the stack and start over (so we dump correctly next time) */
for (p = &_endram; p < &_fstack; p++)
*p = 0;
_endram = 0;
_reset_handler();
}
# else /* no CONFIG_CHECK_RESET */
void check_reset(void) {}
#endif
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "flash.h" #include "flash.h"
#include "wrc_ptp.h" #include "wrc_ptp.h"
#include "system_checks.h"
int wrc_ui_mode = UI_SHELL_MODE; int wrc_ui_mode = UI_SHELL_MODE;
int wrc_ui_refperiod = TICS_PER_SECOND; /* 1 sec */ int wrc_ui_refperiod = TICS_PER_SECOND; /* 1 sec */
...@@ -161,73 +162,16 @@ static void ui_update() ...@@ -161,73 +162,16 @@ static void ui_update()
} }
extern uint32_t _endram; /* initialize functions to be called after reset in check_reset function */
extern uint32_t _fstack; void init_hw_after_reset(void)
#define ENDRAM_MAGIC 0xbadc0ffe
static void check_stack(void)
{ {
while (_endram != ENDRAM_MAGIC) {
mprintf("Stack overflow!\n");
timer_delay_ms(1000);
}
}
#ifdef CONFIG_CHECK_RESET
static void check_reset(void)
{
extern void _reset_handler(void); /* user to reset again */
/* static variables to preserve stack (for dumping it) */
static uint32_t *p, *save;
/* _endram is set to ENDRAM_MAGIC after calling this function */
if (_endram != ENDRAM_MAGIC)
return;
/* Before calling anything, find the beginning of the stack */
p = &_endram + 1;
while (!*p)
p++;
p = (void *)((unsigned long)p & ~0xf); /* align */
/* Copy it to the beginning of the stack, then reset pointers */
save = &_endram;
while (p <= &_fstack)
*save++ = *p++;
p -= (save - &_endram);
save = &_endram;
/* Ok, now init the devices so we can printf and delay */ /* Ok, now init the devices so we can printf and delay */
sdb_find_devices(); sdb_find_devices();
uart_init_sw(); uart_init_sw();
uart_init_hw(); uart_init_hw();
timer_init(1); timer_init(1);
pp_printf("\nWarning: the CPU was reset\nStack trace:\n");
while (p < &_fstack) {
pp_printf("%08x: %08x %08x %08x %08x\n",
(int)p, save[0], save[1], save[2], save[3]);
p += 4;
save += 4;
}
pp_printf("Rebooting in 1 second\n\n\n");
timer_delay_ms(1000);
/* Zero the stack and start over (so we dump correctly next time) */
for (p = &_endram; p < &_fstack; p++)
*p = 0;
_endram = 0;
_reset_handler();
} }
# else /* no CONFIG_CHECK_RESET */
static void check_reset(void) {}
#endif
int main(void) int main(void)
{ {
check_reset(); check_reset();
......
...@@ -3,24 +3,42 @@ ...@@ -3,24 +3,42 @@
#include "softpll_ng.h" #include "softpll_ng.h"
#include "minipc.h" #include "minipc.h"
#include "revision.h" #include "revision.h"
#include "system_checks.h"
int scb_ver = 33; //SCB version. int scb_ver = 33; /* SCB version */
extern struct spll_stats stats;
/* initialize functions to be called after reset in check_reset function */
void init_hw_after_reset(void)
{
/* Ok, now init the devices so we can printf and delay */
uart_init_hw();
}
int main(void) int main(void)
{ {
uint32_t start_tics = timer_get_tics(); uint32_t start_tics = timer_get_tics();
check_reset();
stats.start_cnt++;
_endram = ENDRAM_MAGIC;
uart_init_hw(); uart_init_hw();
TRACE("\n");
TRACE("");
TRACE("WR Switch Real Time Subsystem (c) CERN 2011 - 2014\n"); TRACE("WR Switch Real Time Subsystem (c) CERN 2011 - 2014\n");
TRACE("Revision: %s, built: %s %s.\n", TRACE("Revision: %s, built: %s %s.\n",
build_revision, build_date, build_time); build_revision, build_date, build_time);
TRACE("SCB version: %d. %s\n", scb_ver,(scb_ver>=34)?"10 MHz SMC Output.":"" ); TRACE("SCB version: %d. %s\n", scb_ver,(scb_ver>=34)?"10 MHz SMC Output.":"" );
TRACE("--"); TRACE("Start counter %d\n", stats.start_cnt);
TRACE("--\n");
ad9516_init( scb_ver ); if (stats.start_cnt > 1) {
TRACE("!!spll does not work after restart!!\n");
/* for sure problem is in calling second time ad9516_init,
* but not only */
}
ad9516_init(scb_ver);
rts_init(); rts_init();
rtipc_init(); rtipc_init();
...@@ -28,14 +46,15 @@ int main(void) ...@@ -28,14 +46,15 @@ int main(void)
{ {
uint32_t tics = timer_get_tics(); uint32_t tics = timer_get_tics();
if(time_after(tics, start_tics + TICS_PER_SECOND/5)) if (time_after(tics, start_tics + TICS_PER_SECOND/5)) {
{
spll_show_stats(); spll_show_stats();
start_tics = tics; start_tics = tics;
} }
rts_update(); rts_update();
rtipc_action(); rtipc_action();
spll_update(); spll_update();
check_stack();
} }
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment