altos: Add stack-guard code. Uses STM MPU to trap stack overflow.
authorKeith Packard <keithp@keithp.com>
Thu, 25 Oct 2012 05:46:55 +0000 (22:46 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 25 Oct 2012 07:07:14 +0000 (00:07 -0700)
This marks the lowest portion of the stack as inaccessible to the CPU,
causing the processor to fault when it reaches it. The fault then
generates a panic message so that the user can know what happened.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/core/ao.h
src/core/ao_task.c
src/megametrum-v0.1/Makefile
src/megametrum-v0.1/ao_megametrum.c
src/stm-bringup/Makefile
src/stm-bringup/ao.h [new file with mode: 0644]
src/stm/ao_interrupt.c
src/stm/ao_mpu.h [new file with mode: 0644]
src/stm/ao_mpu_stm.c [new file with mode: 0644]
src/stm/registers.ld
src/stm/stm32l.h

index 2b375cfd68f7115d38ad7b6220adbb9e9f87c44d..87e69e192e7e99a551136184ef1af9549223c101 100644 (file)
@@ -64,6 +64,7 @@
 #define AO_PANIC_BT            11      /* Communications with bluetooth device failed */
 #define AO_PANIC_STACK         12      /* Stack overflow */
 #define AO_PANIC_SPI           13      /* SPI communication failure */
+#define AO_PANIC_CRASH         14      /* Processor crashed */
 #define AO_PANIC_SELF_TEST_CC1120      0x40 | 1        /* Self test failure */
 #define AO_PANIC_SELF_TEST_HMC5883     0x40 | 2        /* Self test failure */
 #define AO_PANIC_SELF_TEST_MPU6000     0x40 | 3        /* Self test failure */
index c2b1b2700453921e04f142c3db3849a02f800dfb..df70b906ccfa6bec6c793c417a25bc4d4e652ff6 100644 (file)
@@ -20,6 +20,9 @@
 #if HAS_SAMPLE_PROFILE
 #include <ao_sample_profile.h>
 #endif
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
 
 #define AO_NO_TASK_INDEX       0xff
 
@@ -127,6 +130,9 @@ ao_yield(void) ao_arch_naked_define
        ao_cur_task->start = ao_sample_profile_timer_value();
 #endif
        }
+#if HAS_STACK_GUARD
+       ao_mpu_stack_guard(ao_cur_task->stack);
+#endif
 #if AO_CHECK_STACK
        cli();
        in_yield = 0;
index b100fafcbb85fbb5e0f1e860f8779dbdd6654c8b..487a643f232ecfee6b7f0078d751aa1d74efe875 100644 (file)
@@ -25,11 +25,13 @@ INC = \
        ao_task.h \
        ao_whiten.h \
        ao_sample_profile.h \
+       ao_mpu.h \
        stm32l.h
 
 #
 # Common AltOS sources
 #
+#      ao_hmc5883.c
 
 #PROFILE=ao_profile.c
 #PROFILE_DEF=-DAO_PROFILE=1
@@ -38,7 +40,8 @@ SAMPLE_PROFILE=ao_sample_profile.c \
        ao_sample_profile_timer.c
 SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
 
-#      ao_hmc5883.c
+STACK_GUARD=ao_mpu_stm.c
+STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
 
 ALTOS_SRC = \
        ao_interrupt.c \
@@ -87,13 +90,14 @@ ALTOS_SRC = \
        ao_companion.c \
        ao_pyro.c \
        $(PROFILE) \
-       $(SAMPLE_PROFILE)
+       $(SAMPLE_PROFILE) \
+       $(STACK_GUARD)
 
 PRODUCT=MegaMetrum-v0.1
 PRODUCT_DEF=-DMEGAMETRUM
 IDPRODUCT=0x0023
 
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
 
 PROGNAME=megametrum-v0.1
 PROG=$(PROGNAME)-$(VERSION).elf
index 114f144fc3271c10c90b780e8fe6cf8e60bcda37..43c2292d40f2091e2084ba23a5005f4e9122d146 100644 (file)
 #include <ao_sample_profile.h>
 #endif
 #include <ao_pyro.h>
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
 
 int
 main(void)
 {
        ao_clock_init();
        
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+
        ao_serial_init();
        ao_led_init(LEDS_AVAILABLE);
        ao_led_on(AO_LED_GREEN);
index d45e836d6a822967c03771f249e622d525943631..5cc94bd969f64a3a147461bbe7489ef2416115a3 100644 (file)
@@ -12,7 +12,7 @@ PDCLIB=/home/keithp/sat
 C_LIB=$(PDCLIB)/lib/pdclib.a
 C_INC=-I$(PDCLIB)/include
 
-DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I../../src/stm $(C_INC)
+DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../../src/stm $(C_INC)
 
 # to run from SRAM
 LD_FLAGS_RAM=-L../stm -Wl,-Taltos-ram.ld
diff --git a/src/stm-bringup/ao.h b/src/stm-bringup/ao.h
new file mode 100644 (file)
index 0000000..27204fa
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define ao_panic(n)    for(;;);
index 6b4a9700c620fbcab4ca446cf4df5f4b00988af3..a423d8b13b1f76ad4ab2524602da956e8a74eadb 100644 (file)
@@ -15,6 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#include <ao.h>
 #include "stm32l.h"
 #include <string.h>
 
@@ -28,7 +29,7 @@ extern char __bss_start__, __bss_end__;
 
 void stm_halt_isr(void)
 {
-       for(;;);
+       ao_panic(AO_PANIC_CRASH);
 }
 
 void stm_ignore_isr(void)
diff --git a/src/stm/ao_mpu.h b/src/stm/ao_mpu.h
new file mode 100644 (file)
index 0000000..cc6132a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_MPU_H_
+#define _AO_MPU_H_
+
+extern uint32_t        ao_mpu_dregion;
+
+void
+ao_mpu_stack_guard(void *stack);
+
+void
+ao_mpu_init(void);
+
+#endif /* _AO_MPU_H_ */
diff --git a/src/stm/ao_mpu_stm.c b/src/stm/ao_mpu_stm.c
new file mode 100644 (file)
index 0000000..969d744
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_mpu.h>
+
+static uint32_t        stm_mpu_dregion;
+
+void
+ao_mpu_init(void)
+{
+       uint32_t        region;
+
+       /* Check to see how many regions we have */
+       stm_mpu_dregion = (stm_mpu.typer >> STM_MPU_TYPER_DREGION) & STM_MPU_TYPER_DREGION_MASK;
+
+       /* No MPU at all */
+       if (stm_mpu_dregion == 0)
+               return;
+
+       /* Disable MPU */
+       stm_mpu.cr = ((0 << STM_MPU_CR_PRIVDEFENA) |
+                     (0 << STM_MPU_CR_HFNMIENA) |
+                     (0 << STM_MPU_CR_ENABLE));
+
+       /* Disable all regions */
+       for (region = 0; region < stm_mpu_dregion; region++) {
+               /* Set the base address and RNR value */
+               stm_mpu.rbar = ((0 & (STM_MPU_RBAR_ADDR_MASK << STM_MPU_RBAR_ADDR)) |
+                               (1 << STM_MPU_RBAR_VALID) |
+                               (region << STM_MPU_RBAR_REGION));
+
+               /* Disable this region */
+               stm_mpu.rasr = 0;
+       }
+
+       region = 0;
+
+       /* Flash */
+       /* 0x00000000 - 0x1fffffff */
+       stm_mpu.rbar = (0x0000000 |
+                       (1 << STM_MPU_RBAR_VALID) |
+                       (region << STM_MPU_RBAR_REGION));
+
+       stm_mpu.rasr = ((0 << STM_MPU_RASR_XN) |
+                       (STM_MPU_RASR_AP_RO_RO << STM_MPU_RASR_AP) |
+                       (5 << STM_MPU_RASR_TEX) |
+                       (0 << STM_MPU_RASR_C) |
+                       (1 << STM_MPU_RASR_B) |
+                       (0 << STM_MPU_RASR_S) |
+                       (0 << STM_MPU_RASR_SRD) |
+                       (28 << STM_MPU_RASR_SIZE) |
+                       (1 << STM_MPU_RASR_ENABLE));
+       region++;
+
+       /* Ram */
+       /* 0x20000000 - 0x3fffffff */
+       stm_mpu.rbar = (0x20000000 |
+                       (1 << STM_MPU_RBAR_VALID) |
+                       (region << STM_MPU_RBAR_REGION));
+
+       stm_mpu.rasr = ((0 << STM_MPU_RASR_XN) |
+                       (STM_MPU_RASR_AP_RW_RW << STM_MPU_RASR_AP) |
+                       (5 << STM_MPU_RASR_TEX) |
+                       (0 << STM_MPU_RASR_C) |
+                       (1 << STM_MPU_RASR_B) |
+                       (0 << STM_MPU_RASR_S) |
+                       (0 << STM_MPU_RASR_SRD) |
+                       (28 << STM_MPU_RASR_SIZE) |
+                       (1 << STM_MPU_RASR_ENABLE));
+       region++;
+
+       /* Peripherals */
+
+       /* 0x4000000 - 0x7ffffff */
+       stm_mpu.rbar = (0x40000000 |
+                       (1 << STM_MPU_RBAR_VALID) |
+                       (region << STM_MPU_RBAR_REGION));
+
+       stm_mpu.rasr = ((1 << STM_MPU_RASR_XN) |
+                       (STM_MPU_RASR_AP_RW_RW << STM_MPU_RASR_AP) |
+                       (2 << STM_MPU_RASR_TEX) |
+                       (0 << STM_MPU_RASR_C) |
+                       (0 << STM_MPU_RASR_B) |
+                       (0 << STM_MPU_RASR_S) |
+                       (0 << STM_MPU_RASR_SRD) |
+                       (29 << STM_MPU_RASR_SIZE) |
+                       (1 << STM_MPU_RASR_ENABLE));
+       region++;
+
+       /* 0x8000000 - 0xffffffff */
+       stm_mpu.rbar = (0x80000000 |
+                       (1 << STM_MPU_RBAR_VALID) |
+                       (region << STM_MPU_RBAR_REGION));
+
+       stm_mpu.rasr = ((1 << STM_MPU_RASR_XN) |
+                       (STM_MPU_RASR_AP_RW_RW << STM_MPU_RASR_AP) |
+                       (2 << STM_MPU_RASR_TEX) |
+                       (0 << STM_MPU_RASR_C) |
+                       (0 << STM_MPU_RASR_B) |
+                       (0 << STM_MPU_RASR_S) |
+                       (0 << STM_MPU_RASR_SRD) |
+                       (30 << STM_MPU_RASR_SIZE) |
+                       (1 << STM_MPU_RASR_ENABLE));
+       region++;
+
+       /* Enable MPU */
+       stm_mpu.cr = ((0 << STM_MPU_CR_PRIVDEFENA) |
+                     (0 << STM_MPU_CR_HFNMIENA) |
+                     (1 << STM_MPU_CR_ENABLE));
+}
+
+/*
+ * Protect the base of the stack from CPU access
+ */
+
+void
+ao_mpu_stack_guard(void *base)
+{
+       uintptr_t       addr = (uintptr_t) base;
+
+       /* Round up to cover the lowest possible 32-byte region */
+       addr = (addr + ~(STM_MPU_RBAR_ADDR_MASK << STM_MPU_RBAR_ADDR)) & (STM_MPU_RBAR_ADDR_MASK << STM_MPU_RBAR_ADDR);
+
+       stm_mpu.rbar = addr | (1 << STM_MPU_RBAR_VALID) | (7 << STM_MPU_RBAR_REGION);
+       stm_mpu.rasr = ((1 << STM_MPU_RASR_XN) |
+                       (STM_MPU_RASR_AP_NONE_NONE << STM_MPU_RASR_AP) |
+                       (5 << STM_MPU_RASR_TEX) |
+                       (0 << STM_MPU_RASR_C) |
+                       (1 << STM_MPU_RASR_B) |
+                       (0 << STM_MPU_RASR_S) |
+                       (0 << STM_MPU_RASR_SRD) |
+                       (4 << STM_MPU_RASR_SIZE) |
+                       (1 << STM_MPU_RASR_ENABLE));
+}
index fd61e4864bd44a434d14f2c6fcad52e7f87ff994..f8b224a2d67d01f831ea003d52fcb42dc4f39428 100644 (file)
@@ -46,5 +46,7 @@ stm_tim2   = 0x40000000;
 
 stm_nvic   = 0xe000e100;
 
+stm_mpu    = 0xe000ed90;
+
 /* calibration data in system memory */
 stm_temp_cal = 0x1ff80078;
index e950d09bf5b8b905b6b32d7e37c290ce549ba696..d953aee433d5691b4061d82a49b882ac6fe82ad5 100644 (file)
@@ -901,6 +901,63 @@ stm_nvic_get_priority(int irq) {
        return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
 }
 
+struct stm_mpu {
+       vuint32_t       typer;
+       vuint32_t       cr;
+       vuint32_t       rnr;
+       vuint32_t       rbar;
+
+       vuint32_t       rasr;
+       vuint32_t       rbar_a1;
+       vuint32_t       rasr_a1;
+       vuint32_t       rbar_a2;
+       vuint32_t       rasr_a2;
+       vuint32_t       rbar_a3;
+       vuint32_t       rasr_a3;
+};
+
+extern struct stm_mpu stm_mpu;
+
+#define STM_MPU_TYPER_IREGION  16
+#define  STM_MPU_TYPER_IREGION_MASK    0xff
+#define STM_MPU_TYPER_DREGION  8
+#define  STM_MPU_TYPER_DREGION_MASK    0xff
+#define STM_MPU_TYPER_SEPARATE 0
+
+#define STM_MPU_CR_PRIVDEFENA  2
+#define STM_MPU_CR_HFNMIENA    1
+#define STM_MPU_CR_ENABLE      0
+
+#define STM_MPU_RNR_REGION     0
+#define STM_MPU_RNR_REGION_MASK                0xff
+
+#define STM_MPU_RBAR_ADDR      5
+#define STM_MPU_RBAR_ADDR_MASK         0x7ffffff
+
+#define STM_MPU_RBAR_VALID     4
+#define STM_MPU_RBAR_REGION    0
+#define STM_MPU_RBAR_REGION_MASK       0xf
+
+#define STM_MPU_RASR_XN                28
+#define STM_MPU_RASR_AP                24
+#define  STM_MPU_RASR_AP_NONE_NONE     0
+#define  STM_MPU_RASR_AP_RW_NONE       1
+#define  STM_MPU_RASR_AP_RW_RO         2
+#define  STM_MPU_RASR_AP_RW_RW         3
+#define  STM_MPU_RASR_AP_RO_NONE       5
+#define  STM_MPU_RASR_AP_RO_RO         6
+#define  STM_MPU_RASR_AP_MASK          7
+#define STM_MPU_RASR_TEX       19
+#define  STM_MPU_RASR_TEX_MASK         7
+#define STM_MPU_RASR_S         18
+#define STM_MPU_RASR_C         17
+#define STM_MPU_RASR_B         16
+#define STM_MPU_RASR_SRD       8
+#define  STM_MPU_RASR_SRD_MASK         0xff
+#define STM_MPU_RASR_SIZE      1
+#define  STM_MPU_RASR_SIZE_MASK                0x1f
+#define STM_MPU_RASR_ENABLE    0
+
 #define isr(name) void stm_ ## name ## _isr(void);
 
 isr(nmi)
@@ -1568,6 +1625,13 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;
 #define STM_TIM234_SR_CC1IF    1
 #define STM_TIM234_SR_UIF      0
 
+#define STM_TIM234_EGR_TG      6
+#define STM_TIM234_EGR_CC4G    4
+#define STM_TIM234_EGR_CC3G    3
+#define STM_TIM234_EGR_CC2G    2
+#define STM_TIM234_EGR_CC1G    1
+#define STM_TIM234_EGR_UG      0
+
 #define STM_TIM234_CCMR1_OC2CE 15
 #define STM_TIM234_CCMR1_OC2M  12
 #define  STM_TIM234_CCMR1_OC2M_FROZEN                  0