MPU assert for ARM_CM3_MPU (#952)

* Add runtime check to see if the target even has a MPU

* Add missing extern symbols for __ARMCC_VERSION support

* Add default for configTOTAL_MPU_REGIONS and change a runtime assert to compile time error

* Simplify check and link to reference documentation

Co-authored-by: Soren Ptak <ptaksoren@gmail.com>

---------

Co-authored-by: Soren Ptak <ptaksoren@gmail.com>
Co-authored-by: jasonpcarroll <23126711+jasonpcarroll@users.noreply.github.com>
diff --git a/portable/GCC/ARM_CM3_MPU/port.c b/portable/GCC/ARM_CM3_MPU/port.c
index d8c1832..fad62ff 100644
--- a/portable/GCC/ARM_CM3_MPU/port.c
+++ b/portable/GCC/ARM_CM3_MPU/port.c
@@ -1095,12 +1095,28 @@
 
 static void prvSetupMPU( void )
 {
-    extern uint32_t __privileged_functions_start__[];
-    extern uint32_t __privileged_functions_end__[];
-    extern uint32_t __FLASH_segment_start__[];
-    extern uint32_t __FLASH_segment_end__[];
-    extern uint32_t __privileged_data_start__[];
-    extern uint32_t __privileged_data_end__[];
+    #if defined( __ARMCC_VERSION )
+
+        /* Declaration when these variable are defined in code instead of being
+         * exported from linker scripts. */
+        extern uint32_t * __privileged_functions_start__;
+        extern uint32_t * __privileged_functions_end__;
+        extern uint32_t * __FLASH_segment_start__;
+        extern uint32_t * __FLASH_segment_end__;
+        extern uint32_t * __privileged_data_start__;
+        extern uint32_t * __privileged_data_end__;
+    #else
+        /* Declaration when these variable are exported from linker scripts. */
+        extern uint32_t __privileged_functions_start__[];
+        extern uint32_t __privileged_functions_end__[];
+        extern uint32_t __FLASH_segment_start__[];
+        extern uint32_t __FLASH_segment_end__[];
+        extern uint32_t __privileged_data_start__[];
+        extern uint32_t __privileged_data_end__[];
+    #endif /* if defined( __ARMCC_VERSION ) */
+
+    /* Ensure that the device has the expected MPU type */
+    configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );
 
     /* Check the expected MPU is present. */
     if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
@@ -1229,10 +1245,22 @@
                                 StackType_t * pxBottomOfStack,
                                 uint32_t ulStackDepth )
 {
-    extern uint32_t __SRAM_segment_start__[];
-    extern uint32_t __SRAM_segment_end__[];
-    extern uint32_t __privileged_data_start__[];
-    extern uint32_t __privileged_data_end__[];
+    #if defined( __ARMCC_VERSION )
+
+        /* Declaration when these variable are defined in code instead of being
+         * exported from linker scripts. */
+        extern uint32_t * __SRAM_segment_start__;
+        extern uint32_t * __SRAM_segment_end__;
+        extern uint32_t * __privileged_data_start__;
+        extern uint32_t * __privileged_data_end__;
+    #else
+        /* Declaration when these variable are exported from linker scripts. */
+        extern uint32_t __SRAM_segment_start__[];
+        extern uint32_t __SRAM_segment_end__[];
+        extern uint32_t __privileged_data_start__[];
+        extern uint32_t __privileged_data_end__[];
+    #endif /* if defined( __ARMCC_VERSION ) */
+
     int32_t lIndex;
     uint32_t ul;
 
diff --git a/portable/GCC/ARM_CM3_MPU/portmacro.h b/portable/GCC/ARM_CM3_MPU/portmacro.h
index 5983c79..a6e2ae2 100644
--- a/portable/GCC/ARM_CM3_MPU/portmacro.h
+++ b/portable/GCC/ARM_CM3_MPU/portmacro.h
@@ -86,6 +86,15 @@
 #define portMPU_REGION_CACHEABLE_BUFFERABLE                      ( 0x07UL << 16UL )
 #define portMPU_REGION_EXECUTE_NEVER                             ( 0x01UL << 28UL )
 
+/* MPU settings that can be overriden in FreeRTOSConfig.h. */
+#ifndef configTOTAL_MPU_REGIONS
+    /* Define to 8 for backward compatibility. */
+    #define configTOTAL_MPU_REGIONS    ( 8UL )
+#elif( configTOTAL_MPU_REGIONS != 8UL )
+    /* The Cortex M3 only supports 8 MPU regions. For more information refer to:
+     * https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit */
+    #error configTOTAL_MPU_REGIONS must be 8 for this port.
+#endif /* configTOTAL_MPU_REGIONS Check */
 #define portSTACK_REGION                                         ( 3UL )
 #define portGENERAL_PERIPHERALS_REGION                           ( 4UL )
 #define portUNPRIVILEGED_FLASH_REGION                            ( 5UL )