diff --git a/bootloader.ld b/bootloader.ld index 1665e259..ce403031 100644 --- a/bootloader.ld +++ b/bootloader.ld @@ -3,10 +3,12 @@ OUTPUT_ARCH(arm) SEARCH_DIR(.) /* Memory Spaces Definitions */ +/*ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000*/ MEMORY { rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00007FE0 - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000 + ramf (rx) : ORIGIN = 0x20000000, LENGTH = 0x000000fc + ram (rw) : ORIGIN = 0x200000fc, LENGTH = 0x0000FF04 } __stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000; @@ -80,6 +82,12 @@ SECTIONS . = ALIGN(4); _srelocate = .; *(.ramfunc .ramfunc.*); + } > ramf + + .data : AT (_etext + SIZEOF(.relocate)) + { + . = ALIGN(4); + _sdata = .; *(.data .data.*); . = ALIGN(4); _erelocate = .; diff --git a/firmware.ld b/firmware.ld index 900181b9..e486e005 100644 --- a/firmware.ld +++ b/firmware.ld @@ -3,10 +3,14 @@ OUTPUT_ARCH(arm) SEARCH_DIR(.) /* Memory Spaces Definitions */ + +/*ramf (rx) : ORIGIN = 0x20000000, LENGTH = 0x0000027c + ram (rw) : ORIGIN = 0x2000027c, LENGTH = 0x0000FD84*/ MEMORY { rom (rx) : ORIGIN = 0x00409000, LENGTH = 0x00037000 - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000 + ramf (rx) : ORIGIN = 0x20000000, LENGTH = 0x000000fc + ram (rw) : ORIGIN = 0x200000fc, LENGTH = 0x0000FF04 } __stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000; @@ -80,6 +84,12 @@ SECTIONS . = ALIGN(4); _srelocate = .; *(.ramfunc .ramfunc.*); + } > ramf + + .data : AT (_etext + SIZEOF(.relocate)) + { + . = ALIGN(0x1000); + _sdata = .; *(.data .data.*); . = ALIGN(4); _erelocate = .; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7866af1..70be651a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -59,6 +59,7 @@ set(DBB-HARDWARE-SOURCES board_com.c hw_version.c systick.c + mpu.c ) set(YAJL-SOURCES diff --git a/src/bootloader.c b/src/bootloader.c index 6d5eb6d5..745d0629 100644 --- a/src/bootloader.c +++ b/src/bootloader.c @@ -39,6 +39,7 @@ #include "touch.h" #include "version.h" #include "bootloader.h" +#include "mpu.h" static char report[UDI_HID_REPORT_IN_SIZE]; @@ -334,7 +335,6 @@ void bootloader_command(const char *command) usb_reply((uint8_t *)report); } - void bootloader_jump(void) { void *app_start_addr = (void *)FLASH_APP_START; diff --git a/src/firmware.c b/src/firmware.c index 90b0056f..f854b91e 100644 --- a/src/firmware.c +++ b/src/firmware.c @@ -41,6 +41,8 @@ #include "commander.h" #include "board_com.h" +#include "mpu.h" + uint32_t __stack_chk_guard = 0; @@ -86,28 +88,13 @@ void MemManage_Handler(void) } } - -static void enable_usersig_area(void) -{ - __DSB(); - __ISB(); - MPU->CTRL = 0; - MPU->RBAR = FLASH_USERSIG_START | MPU_REGION_VALID | 1; - MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( - FLASH_USERSIG_SIZE) | MPU_REGION_STATE_RW; - MPU->CTRL = 0x1 | MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk; - __DSB(); - __ISB(); -} - - char usb_serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; int main (void) { + mpu_firmware_init(); wdt_disable(WDT); - enable_usersig_area(); irq_initialize_vectors(); cpu_irq_enable(); sleepmgr_init(); diff --git a/src/mpu.c b/src/mpu.c new file mode 100644 index 00000000..bad3993c --- /dev/null +++ b/src/mpu.c @@ -0,0 +1,184 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015-2016 Douglas J. Bakkum + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include +#include "flash.h" +#include "sam4s4a.h" +#include "core_cm4.h" +#include "mpu.h" + +/** + * MPU REGIONS: + * 0: whole flash region (bootloader + firmware code) + * start: IFLASH0_ADDR, size: IFLASH0_SIZE + * 1: bootloader region + * start: IFLASH0_ADDR, size: FLASH_BOOT_LEN + * 2: sram region + * start: IRAM_ADDR, size: IRAM_SIZE + * 3: usersig region + * start: FLASH_USERSIG_START, size: FLASH_USERSIG_SIZE + */ +static const uint8_t rn_flash = 0; +static const uint8_t rn_boot = 1; +static const uint8_t rn_sram = 2; +static const uint8_t rn_data = 3; +static const uint8_t rn_bss = 4; +static const uint8_t rn_stack = 5; +static const uint8_t rn_usersig = 6; + +/** + * Sets the flash region to read-only. + */ +static void mpu_flash_ro(void) +{ + // Configure flash region + MPU->RBAR = IFLASH0_ADDR | MPU_REGION_VALID | rn_flash; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( + IFLASH0_SIZE) | MPU_REGION_STATE_RO; +} + +/** + * Enables write access to code region where the firmware resides. + */ +static void mpu_bootloader_ro_firmware_rw(void) +{ + // Configure flash region + MPU->RBAR = IFLASH0_ADDR | MPU_REGION_VALID | rn_flash; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( + IFLASH0_SIZE) | MPU_REGION_STATE_RW; + + // Configure boot region + MPU->RBAR = IFLASH0_ADDR | MPU_REGION_VALID | rn_boot; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( + FLASH_BOOT_LEN) | MPU_REGION_STATE_RO; +} + +extern uint32_t _srelocate; +extern uint32_t _erelocate; +extern uint32_t _ebss; +extern uint32_t _sbss; +extern uint32_t _sdata; +extern uint32_t _sstack; + +/** + * Enables execution protection for the SRAM region. + */ +static void mpu_sram_nx(void) +{ + // Configure SRAM region, protect from execution + MPU->RBAR = IRAM_ADDR | MPU_REGION_VALID | rn_sram; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( + IRAM_SIZE) | MPU_REGION_STATE_RO; + MPU->RBAR = (uint32_t) &_sdata | MPU_REGION_VALID | rn_data; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size(( + uint32_t) &_erelocate - + (uint32_t) &_sdata) | MPU_REGION_STATE_RW | MPU_REGION_STATE_XN; + + MPU->RBAR = (uint32_t) &_sbss | MPU_REGION_VALID | rn_bss; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | + mpu_region_size((uint32_t) &_ebss - (uint32_t) &_sbss) | + MPU_REGION_STATE_RW; + + MPU->RBAR = (uint32_t) &_sstack | MPU_REGION_VALID | rn_stack; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size(( + IRAM_ADDR + IRAM_SIZE) - + (uint32_t) &_sstack) | MPU_REGION_STATE_RW | MPU_REGION_STATE_XN; +} + +/** + * Enables read-write access to user signature memory. + */ +static void mpu_usersig_rw(void) +{ + MPU->RBAR = FLASH_USERSIG_START | MPU_REGION_VALID | rn_usersig; + MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( + FLASH_USERSIG_SIZE) | MPU_REGION_STATE_RW; +} + + + +/** + * Initializes the memory regions for firmware mode. + * The complete code region is protected and read-only. + * SRAM is protected from execution. + */ +void mpu_firmware_init(void) +{ + int i = 0; + + __disable_irq(); + for (i = 0; i < 8; i ++) { + NVIC->ICER[i] = 0xFFFFFFFF; + } + for (i = 0; i < 8; i ++) { + NVIC->ICPR[i] = 0xFFFFFFFF; + } + __DSB(); + __ISB(); + MPU->CTRL = 0; + + mpu_flash_ro(); + mpu_sram_nx(); + mpu_usersig_rw(); + + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; + MPU->CTRL = 0x1 | MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk; + __DSB(); + __ISB(); + __enable_irq(); +} + +/** + * Initializes the memory regions for bootloader mode. + * The bootloader code is protected, but the memory + * region for the firmware code is writable. + * SRAM is protected from execution. + */ +void mpu_bootloader_init(void) +{ + int i = 0; + + __disable_irq(); + for (i = 0; i < 8; i ++) { + NVIC->ICER[i] = 0xFFFFFFFF; + } + for (i = 0; i < 8; i ++) { + NVIC->ICPR[i] = 0xFFFFFFFF; + } + __DSB(); + __ISB(); + MPU->CTRL = 0; + + mpu_bootloader_ro_firmware_rw(); + mpu_sram_nx(); + + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; + MPU->CTRL = 0x1 | MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk; + __DSB(); + __ISB(); + __enable_irq(); +} + diff --git a/src/mpu.h b/src/mpu.h new file mode 100644 index 00000000..c70310e1 --- /dev/null +++ b/src/mpu.h @@ -0,0 +1,46 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015-2016 Douglas J. Bakkum + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifndef _MPU_H_ +#define _MPU_H_ + +/** + * Initializes the memory regions for bootloader mode. + * The bootloader code is protected, but the memory + * region for the firmware code is writable. + * SRAM is protected from execution. + */ +void mpu_bootloader_init(void); + +/** + * Initializes the memory regions for firmware mode. + * The complete code region is protected and read-only. + * SRAM is protected from execution. + */ +void mpu_firmware_init(void); + +#endif + diff --git a/src/startup.c b/src/startup.c index 438f13f3..ea6907c2 100644 --- a/src/startup.c +++ b/src/startup.c @@ -39,6 +39,7 @@ #include "board_com.h" #include "sam4s4a.h" #include "core_cm4.h" +#include "mpu.h" uint32_t __stack_chk_guard = 0; @@ -83,37 +84,6 @@ void MemManage_Handler(void) } -static void mpu_init(void) -{ - int i = 0; - - __disable_irq(); - for (i = 0; i < 8; i ++) { - NVIC->ICER[i] = 0xFFFFFFFF; - } - for (i = 0; i < 8; i ++) { - NVIC->ICPR[i] = 0xFFFFFFFF; - } - __DSB(); - __ISB(); - MPU->CTRL = 0; - - // Configure flash region - MPU->RBAR = IFLASH0_ADDR | MPU_REGION_VALID | 0; - MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( - IFLASH0_SIZE) | MPU_REGION_STATE_RW; - - // Configure boot region - MPU->RBAR = IFLASH0_ADDR | MPU_REGION_VALID | 1; - MPU->RASR = MPU_REGION_ENABLE | MPU_REGION_NORMAL | mpu_region_size( - FLASH_BOOT_LEN) | MPU_REGION_STATE_RO; - - SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; - MPU->CTRL = 0x1 | MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk; - __DSB(); - __ISB(); - __enable_irq(); -} int main(void) @@ -133,7 +103,7 @@ int main(void) delay_init(F_CPU); systick_init(); touch_init(); - mpu_init(); + mpu_bootloader_init(); bootloader_jump(); while (1) { }