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
default 131072
# CONFIG_WR_SWITCH has no further options at all at this point
if WR_NODE
config STACKSIZE
int
depends on WR_NODE
int
default 2048
config PPSI
depends on WR_NODE
boolean
default y
config UART
depends on WR_NODE
boolean
default y
config W1
depends on WR_NODE
boolean
default y
# The other ones can be set by non-developers
config ETHERBONE
depends on WR_NODE
boolean "Compile Etherbone support in wrpc-sw"
help
This allows to run LM32 code that is aware of Etherbone.
......@@ -55,6 +59,7 @@ config ETHERBONE
If in doubt, say No.
config WRNIC
depends on WR_NODE
boolean "Compile White Rabbit NIC support in wrpc-sw"
help
This allows to run LM32 code that is aware of Etherbone and
......@@ -63,6 +68,7 @@ config WRNIC
If in doubt, say No.
config CMD_CONFIG
depends on WR_NODE
boolean "Include configuration in the output binary"
help
This options adds the "config" command to the shell, which
......@@ -70,6 +76,7 @@ config CMD_CONFIG
to the binary size (100b for the code plus the .config file).
config NIC_PFILTER
depends on WR_NODE
depends on ETHERBONE
bool "Add packet filter rules for wr-nic"
help
......@@ -93,7 +100,7 @@ config DEVELOPER
you are a developer of wrpc-sw.
config RAMSIZE
depends on DEVELOPER
depends on DEVELOPER && WR_NODE
int "Size of the RAM in the FPGA for this program"
default 90112
help
......@@ -103,7 +110,7 @@ config RAMSIZE
choose your preferred value here.
config STACKSIZE
depends on DEVELOPER
depends on DEVELOPER && WR_NODE
int "Size of the stack area needed by this program"
default 2048
help
......@@ -112,7 +119,7 @@ config STACKSIZE
at run time. (However, we have a detector for overflows).
config PRINT_BUFSIZE
depends on DEVELOPER
depends on DEVELOPER && WR_NODE
int "Size for the temporary output string of pp_printf"
default 128
help
......@@ -120,6 +127,7 @@ config PRINT_BUFSIZE
also constraints the maximum lenght of text that can be written
in a single call to printf.
# CHECK_RESET for switch and node
config CHECK_RESET
depends on DEVELOPER
bool "Print a stack trace if reset happens"
......@@ -131,7 +139,7 @@ config CHECK_RESET
choice
prompt "Implementation of pp_printf"
depends on DEVELOPER
depends on DEVELOPER && WR_NODE
config PRINTF_XINT
bool "hex-and-int"
......@@ -166,12 +174,13 @@ config PRINTF_NONE
endchoice
config PPSI
depends on WR_NODE
boolean
help
Select this option for the ppsi engine (now only option)
config DETERMINISTIC_BINARY
depends on DEVELOPER
depends on DEVELOPER && WR_NODE
boolean "Build a binary that is the same every time"
help
This option is used to #ifdef __DATE__ and __TIME__ strings
......@@ -185,7 +194,7 @@ config DETERMINISTIC_BINARY
config UART
boolean "Use hardware uart (and/or vuart if available)"
depends on DEVELOPER
depends on DEVELOPER && WR_NODE
default y
help
This option selects the serial driver, connected to either
......@@ -193,7 +202,7 @@ config UART
to how the gateware is built.
config UART_SW
depends on DEVELOPER
depends on DEVELOPER && WR_NODE
default !UART
boolean "Use software uart"
help
......@@ -204,6 +213,7 @@ config UART_SW
and diagnostics run on the hardware UART if available.
config SDB_STORAGE
depends on WR_NODE
default y
boolean "Use SDB to manage storage (instead of legacy eeprom code)"
help
......@@ -211,8 +221,8 @@ config SDB_STORAGE
(eeprom only) will be selected.
config LEGACY_EEPROM
depends on WR_NODE
boolean
default !SDB_STORAGE
endif
# CONFIG_WR_NODE
......@@ -68,6 +68,9 @@ endif
# And always complain if we pick the libgcc division: 64/32 = 32 is enough here.
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
cflags-$(CONFIG_WR_NODE) += -Isdb-lib
......
......@@ -79,6 +79,9 @@ SECTIONS
*(.mbox)
} > mbox
/* End of RAM for checking stack overflows */
PROVIDE(_endram = ORIGIN(stack));
/* First location in stack is highest address in RAM (stack area) */
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 @@
#include "flash.h"
#include "wrc_ptp.h"
#include "system_checks.h"
int wrc_ui_mode = UI_SHELL_MODE;
int wrc_ui_refperiod = TICS_PER_SECOND; /* 1 sec */
......@@ -161,73 +162,16 @@ static void ui_update()
}
extern uint32_t _endram;
extern uint32_t _fstack;
#define ENDRAM_MAGIC 0xbadc0ffe
static void check_stack(void)
/* initialize functions to be called after reset in check_reset function */
void init_hw_after_reset(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 */
sdb_find_devices();
uart_init_sw();
uart_init_hw();
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)
{
check_reset();
......
......@@ -3,39 +3,58 @@
#include "softpll_ng.h"
#include "minipc.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)
{
uint32_t start_tics = timer_get_tics();
check_reset();
stats.start_cnt++;
_endram = ENDRAM_MAGIC;
uart_init_hw();
TRACE("");
TRACE("\n");
TRACE("WR Switch Real Time Subsystem (c) CERN 2011 - 2014\n");
TRACE("Revision: %s, built: %s %s.\n",
build_revision, build_date, build_time);
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();
rtipc_init();
for(;;)
{
uint32_t tics = timer_get_tics();
if(time_after(tics, start_tics + TICS_PER_SECOND/5))
{
spll_show_stats();
start_tics = tics;
}
rts_update();
rtipc_action();
uint32_t tics = timer_get_tics();
if (time_after(tics, start_tics + TICS_PER_SECOND/5)) {
spll_show_stats();
start_tics = tics;
}
rts_update();
rtipc_action();
spll_update();
check_stack();
}
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