I am working with S12 ZVML MCU. I want to implement the stack counter undeflow/overflow check.
The S12Z safety manual recommends to implement a periodic stack over/underflow check.
My query is whether a simple check of comparing the stack counter against a user defined threshold counter value will suffice or any further additions are required.
There are two things to talk about.
1) Usually the stack should be correctly precalculated to be sure how the application is working and how much space it requires for the stack. Then you can use two approaches.
This is the part I am able to say from my position. The second part provides next possibility to get more info from special team.
2) You can post any safety related questions to the special community space. The community is monitored by experts in safety area.
You need to have an NDA to get there first. If you do not have it you have to ask for it by inserting a new case where you ask for it.
Please read this document.
an example of prm file. See modifications in bold.
/* This is a linker parameter file for the MC9S12ZVLA128 */
NAMES END /* CodeWarrior will pass all the needed files to the linker by command line. But here you may add your own files too. */
SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
/* Register space */
/* IO_SEG = PAGED 0x000000 TO 0x000FFF; intentionally not defined */
/* RAM */
//RAM = READ_WRITE 0x001000 TO 0x002FFF; intentionally removed
RAM = READ_WRITE 0x001000 TO 0x002DFF;
MY_STACK_RAM = NO_INIT 0x002F00 TO 0x002FFF; // expected stack size
MY_CHECK_STACK_RAM = READ_WRITE 0x002E00 TO 0x002EFF FILL 0xFF; // intentionally used for stack underflow check (select proper size)
/* EEPROM */
EEPROM = READ_ONLY 0x100000 TO 0x1007FF;
/* non-paged FLASHs */
ROM = READ_ONLY 0xFE0000 TO 0xFFFDFF;
/* VECTORS = READ_ONLY 0xFFFE00 TO 0xFFFFFF; intentionally not defined: used for VECTOR commands below */
//OSVECTORS = READ_ONLY 0xFFFE10 TO 0xFFFFFF; /* OSEK interrupt vectors (use your vector.o) */
PLACEMENT /* here all predefined and user segments are placed into the SEGMENTS defined above. */
_PRESTART, /* Used in HIWARE format: jump to _Startup at the code start */
STARTUP, /* startup data structures */
ROM_VAR, /* constant variables */
STRINGS, /* string literals */
VIRTUAL_TABLE_SEGMENT, /* C++ virtual table segment */
//.ostext, /* OSEK */
NON_BANKED, /* runtime routines which must not be banked */
COPY INTO ROM;
//.stackstart, /* eventually used for OSEK kernel awareness: Main-Stack Start */
// intentionally removed SSTACK, /* allocate stack first to avoid overwriting variables on overflow */ // !!!!!!!!!!!!
//.stackend, /* eventually used for OSEK kernel awareness: Main-Stack End */
DEFAULT_RAM INTO RAM;
SSTACK INTO MY_STACK_RAM;
MY_CHECK_STACK_RAM INTO MY_CHECK_STACK_RAM;
//.vectors INTO OSVECTORS; /* OSEK */
ENTRIES /* keep the following unreferenced variables */
/* OSEK: always allocate the vector table and all dependent objects */
//_vectab OsBuildNumber _OsOrtiStackStart _OsOrtiStart
STACKTOP 0x2fff // redefined for required stack size defined in the SEGMENTS section
VECTOR 0 _Startup /* reset vector: this is the default entry point for a C/C++ application. */
//VECTOR 0 Entry /* reset vector: this is the default entry point for an Assembly application. */
//INIT Entry /* for assembly applications: that this is as well the initialization entry point */
Result of the modifications is.....RAM 0x2e00~0x2eff is not used by application for variables and it is filled by patter 0xff at the start of the code automatically. RAM 0x2f00~0x2fff is used for STACK.
The filing the stack by known pattern and check how much from it was rewritten by application code is common approach for debug testing whether your stack size is adequal. Typically, we reset MCU by debugger into Startup() code (prior stack initialization), fill stack by debugger and let code run. After some time, we stop CPU and watch size of used stack.
However, if I remmember correctly, the stack is only part of RAM where linker will ignore the FILL command. So, Lama's advice may help only partialy.
Anyway, the stack is used from top and by default located at begining of RAM. So, you may simply write some pattern directly at address 0x1000 (RAM start) during MCU init and periodically check it.
volatile unsigned int stack_overflow @0x1000 =0x5AA5;
Note: Be aware! The default CW project has disabled memory overlapping warnings.
See https://community.nxp.com/docs/DOC-334387 for more details regarding variable allocation in CW.
I hope it helps you.