uVisor NUCLEO-F411RE开发板移植问题说明
主要参考来源:
uVisor Documentation:https://docs.mbed.com/docs/uvisor-and-uvisor-lib-documentation/en/latest/
uVisor Porting Guide:https://docs.mbed.com/docs/uvisor-and-uvisor-lib-documentation/en/latest/core/PORTING/
uVisor Quick Start Guide:https://docs.mbed.com/docs/uvisor-and-uvisor-lib-documentation/en/latest/lib/QUICKSTART/
Bacis uVisor Example:https://github.com/ARMmbed/mbed-os-example-uvisor
开发环境:
OS:Ubuntu16.04
软件:mbed-cli 1.5.0
工具链:gcc-arm-none-eabi-6-2017-q2-update
问题描述:按照porting guide移植到NUCLEO-F411RE后,参照getting started guide进行检验,使能uVisor时led2不能闪烁。原本官方支持的DISCO-F429ZI(手头没有这块板,使用了NUCLEO-F429ZI替代)对同样的工程编译烧录,led2可以闪烁。
下面是我移植的步骤以及改动:
移植步骤:
1、新建mbed工程($ mbed new uvisor_porting),创建source目录,在source中添加main.cpp,连接NUCLEO-F411RE后编译烧录(~/uvisor_porting$ mbed compile -m auto -t GCC_ARM -f),开发板LED2闪烁。
$ mbed new uvisor_
porting
),创建
source
目录,在
中添加
main.cpp
,连接
NUCLEO-F411RE
后编译烧录(
~/uvisor_porting$ mbed compile -m auto -t GCC_ARM -f
),开发板
LED2
闪烁。
/* ~/code/uvisor-example/source/main.cpp */ #include "mbed.h" DigitalOut led(LED2); int main(void) { while (true) { led = !led; wait(0.5); } }
2、将uVisor的Git下来($ git clone git@github.com:ARMMbed/uvisor.git)
2
、将
uVisor
的
Git
下来(
$ git clone
git@github.com
:ARMMbed/uvisor.git
)
将uVisor文件夹放在/home/ackj/uvisor_porting/mbed-os/features
将
文件夹放在
/home/ackj/uvisor_porting/mbed-os/features
/FEATURE_UVISOR/importer/TARGET_IGNORE目录下。
/FEATURE_UVISOR/importer/TARGET_IGNORE
目录下。
3、在/home/ackj/uvisor_porting/mbed-os/features/
3
、在
/home/ackj/uvisor_porting/mbed-os/features/
FEATURE_UVISOR/importer/TARGET_IGNORE/uvisor/platform目录下添加stm32f411re文件夹,将stm32文件夹中的内容拷贝至stm32f411re文件夹内。
FEATURE_UVISOR/importer/TARGET_IGNORE/uvisor/platform
目录下添加
stm32f411re
文件夹,将
stm32
文件夹中的内容拷贝至
文件夹内。
4、修改inc文件夹中的configurations.h文件如下
#ifndef __CONFIGURATIONS_H__ #define __CONFIGURATIONS_H__ #define NVIC_VECTORS 102 //102个中断向量 #define FLASH_LENGTH_MIN 0x80000 //512K #define SRAM_LENGTH_MIN 0x20000 //128K #define FLASH_ORIGIN 0x08000000 #define FLASH_OFFSET 0x400 #if defined(CONFIGURATION_STM32_CORTEX_M4_0x20000000_0x400) /* ARM core selection */ #define CORE_CORTEX_M4 /* Memory boundaries */ #define SRAM_ORIGIN 0x20000000 #define SRAM_OFFSET 0x400 #else /* Hardware-specific configurations */ #error "Unrecognized uVisor configuration. Check your Makefile." #endif /* Hardware-specific configurations */ #endif /* __CONFIGURATIONS_H__ */
修改makefile.configurations文件如下:
ARCH_CORE:=CORE_ARMv7M ARCH_MPU:=MPU_ARMv7M CONFIGURATIONS:=\ CONFIGURATION_STM32_CORTEX_M4_0x20000000_0x400
在uvisor文件夹下运行make(~/uvisor_porting/mbed-os/features/FEATURE_UVISOR/
importer/TARGET_IGNORE/uvisor$ make),没有报错,并生成如下文件:
修改importer文件夹下的makefile文件,将STM32F4.stm32改为STM32F4.stm32f411re,如下:
# Translate between uVisor namespace and mbed namespace
TARGET_TRANSLATION:=MCU_K64F.kinetis EFM32.efm32 STM32F4.stm32f411re ARM_BEETLE_SOC.beetle M480.m480
在importer文件夹下运行make(~/uvisor_porting/mbed-os/features/
FEATURE_UVISOR/importer$ make)没有报错,并生成如下文件:
5、进入/uvisor_porting/mbed-os/targets/TARGET_STM/TARGET_STM32F4/
TARGET_STM32F411xE/device/TOOLCHAIN_GCC_ARM文件夹
修改启动文件startup_stm32f411xe.S,在bl SystemInit之前添加如下语句:
#if defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)
ldr r0, =uvisor_init
blx r0
#endif /* defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) */
修改STM32F411XE.ld文件如下(参照了STM32F429XI.ld):
M_VECTOR_RAM_SIZE = 0x400; /* With the RTOS in use, this does not affect the main stack size. The size of * the stack where main runs is determined via the RTOS. */ STACK_SIZE = 0x400; /* This is the guaranteed minimum available heap size for an application. When * uVisor is enabled, this is also the maximum available heap size. The * HEAP_SIZE value is set by uVisor porters to balance the size of the legacy * heap and the page heap in uVisor applications. */ HEAP_SIZE = 0x6000; #define FEATURE_UVISOR 1 #define TARGET_UVISOR_SUPPORTED 1 /* Linker script to configure memory regions. */ MEMORY { VECTORS (rx) : ORIGIN = 0x08000000, LENGTH = 0x400 FLASH (rx) : ORIGIN = 0x08000400, LENGTH = 512K-0x400 VECRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x400 RAM (rwx) : ORIGIN = 0x20000400, LENGTH = 128k - 0x400 } /* Linker script to place sections and symbol values. Should be used together * with other linker script that defines memory regions FLASH and RAM. * It references following symbols, which must be defined in code: * Reset_Handler : Entry of reset handler * * It defines following symbols, which code can use without definition: * __exidx_start * __exidx_end * __etext * __data_start__ * __preinit_array_start * __preinit_array_end * __init_array_start * __init_array_end * __fini_array_start * __fini_array_end * __data_end__ * __bss_start__ * __bss_end__ * __end__ * end * __HeapLimit * __StackLimit * __StackTop * __stack * _estack */ ENTRY(Reset_Handler) SECTIONS { .isr_vector : { __vector_table = .; KEEP(*(.isr_vector)) . = ALIGN(4); } > VECTORS /* Note: The uVisor expects this section at a fixed location, as specified * by the porting process configuration parameter: * FLASH_OFFSET. */ __UVISOR_FLASH_OFFSET = 0x400; __UVISOR_FLASH_START = ORIGIN(VECTORS) + __UVISOR_FLASH_OFFSET; .text __UVISOR_FLASH_START : { /* uVisor code and data */ . = ALIGN(4); __uvisor_main_start = .; *(.uvisor.main) __uvisor_main_end = .; *(.text*) KEEP(*(.init)) KEEP(*(.fini)) /* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors) /* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors) *(.rodata*) KEEP(*(.eh_frame*)) } > FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > FLASH __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > FLASH __exidx_end = .; __etext = .; _sidata = .; .interrupts_ram : { . = ALIGN(4); __VECTOR_RAM__ = .; __interrupts_ram_start__ = .; /* Create a global symbol at data start */ *(.m_interrupts_ram) /* This is a user defined section */ . += M_VECTOR_RAM_SIZE; . = ALIGN(4); __interrupts_ram_end__ = .; /* Define a global symbol at data end */ } > VECRAM /* uVisor own memory and private box memories /* Note: The uVisor expects this section at a fixed location, as specified by the porting process configuration parameter: SRAM_OFFSET. */ __UVISOR_SRAM_OFFSET = 0x400; __UVISOR_SRAM_START = ORIGIN(VECRAM) + __UVISOR_SRAM_OFFSET; .uvisor.bss __UVISOR_SRAM_START (NOLOAD): { . = ALIGN(32); __uvisor_bss_start = .; /* Protected uVisor own BSS section */ . = ALIGN(32); __uvisor_bss_main_start = .; KEEP(*(.keep.uvisor.bss.main)) . = ALIGN(32); __uvisor_bss_main_end = .; /* Protected uVisor boxes' static memories */ . = ALIGN(32); __uvisor_bss_boxes_start = .; KEEP(*(.keep.uvisor.bss.boxes)) . = ALIGN(32); __uvisor_bss_boxes_end = .; . = ALIGN(32); __uvisor_bss_end = .; } > RAM .page_heap (NOLOAD) : { . = ALIGN(32); __uvisor_page_start = .; KEEP(*(.keep.uvisor.page_heap)) . = ALIGN((1 << LOG2CEIL(LENGTH(RAM))) / 8); __uvisor_page_end = .; } > RAM .data : { PROVIDE( __etext = LOADADDR(.data) ); __data_start__ = .; _sdata = .; *(vtable) *(.data*) . = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN (__preinit_array_start = .); KEEP(*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(4); /* init data */ PROVIDE_HIDDEN (__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(4); /* finit data */ PROVIDE_HIDDEN (__fini_array_start = .); KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .); KEEP(*(.jcr*)) . = ALIGN(4); /* All data end */ __data_end__ = .; _edata = .; } > RAM AT > FLASH /* uVisor configuration section * This section must be located after all other flash regions. */ .uvisor.secure : { . = ALIGN(32); __uvisor_secure_start = .; /* uVisor secure boxes configuration tables */ . = ALIGN(32); __uvisor_cfgtbl_start = .; KEEP(*(.keep.uvisor.cfgtbl)) . = ALIGN(32); __uvisor_cfgtbl_end = .; /* Pointers to the uVisor secure boxes configuration tables */ /* Note: Do not add any further alignment here, as uVisor will need to * have access to the exact list of pointers. */ __uvisor_cfgtbl_ptr_start = .; KEEP(*(.keep.uvisor.cfgtbl_ptr_first)) KEEP(*(.keep.uvisor.cfgtbl_ptr)) __uvisor_cfgtbl_ptr_end = .; /* Pointers to all boxes register gateways. These are grouped here to allow discoverability and firmware verification. */ __uvisor_register_gateway_ptr_start = .; KEEP(*(.keep.uvisor.register_gateway_ptr)) __uvisor_register_gateway_ptr_end = .; . = ALIGN(32); __uvisor_secure_end = .; } > FLASH /* Uninitialized data section * This region is not initialized by the C/C++ library and can be used to * store state across soft reboots. */ .uninitialized (NOLOAD): { . = ALIGN(32); __uninitialized_start = .; *(.uninitialized) KEEP(*(.keep.uninitialized)) . = ALIGN(32); __uninitialized_end = .; } > RAM .bss (NOLOAD): { . = ALIGN(4); __bss_start__ = .; _sbss = .; *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; _ebss = .; } > RAM .heap (NOLOAD): { __uvisor_heap_start = .; __end__ = .; end = __end__; . += HEAP_SIZE; __HeapLimit = .; __uvisor_heap_end = .; } > RAM __StackTop = ORIGIN(RAM) + LENGTH(RAM); __stack = __StackTop; __StackLimit = __StackTop - STACK_SIZE; ASSERT(__StackLimit >= __HeapLimit, "Region RAM overflowed with stack and heap") __uvisor_flash_start = ORIGIN(VECTORS); __uvisor_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); __uvisor_sram_start = ORIGIN(RAM); __uvisor_sram_end = ORIGIN(RAM) + LENGTH(RAM); __uvisor_public_sram_start = ORIGIN(RAM); __uvisor_public_sram_end = ORIGIN(RAM) + LENGTH(RAM); }
6、按照uVisor Quick Start Guide的步骤,修改main.cpp如下:
#include "mbed.h" #include "uvisor-lib/uvisor-lib.h" static const UvisorBoxAclItem g_public_box_acls[] = { {GPIOA, sizeof(*GPIOA), UVISOR_TACLDEF_PERIPH}, {GPIOB, sizeof(*GPIOB), UVISOR_TACLDEF_PERIPH}, {TIM1, sizeof(*TIM1), UVISOR_TACLDEF_PERIPH}, {TIM5, sizeof(*TIM5), UVISOR_TACLDEF_PERIPH}, {RCC, sizeof(*RCC), UVISOR_TACLDEF_PERIPH}, {FLASH, sizeof(*FLASH), UVISOR_TACLDEF_PERIPH}, {PWR, sizeof(*PWR), UVISOR_TACLDEF_PERIPH}, {EXTI, sizeof(*EXTI), UVISOR_TACLDEF_PERIPH}, {(void *) 0x42000000, 0x02000000, UVISOR_TACLDEF_PERIPH}, }; UVISOR_SET_MODE_ACL(UVISOR_ENABLED, g_public_box_acls); DigitalOut led(LED2); int main(void) { while (true) { led = !led; wait(0.5); } }
在uvisor_porting目录下添加mbed_app.json文件,其内容如下:
{ "target_overrides": { "*": { "target.features_add": ["UVISOR"], "target.extra_labels_add": ["UVISOR_SUPPORTED"] } }, "macros": [ "FEATURE_UVISOR=1", "TARGET_UVISOR_SUPPORTED=1" ] }
7、在uvisor_porting目录下~/uvisor_porting$ mbed compile -c -m auto -t GCC_ARM -f,成功编译并烧录至开发板
问题:程序烧录成功后开发板上led2并未闪烁
试图寻找问题的步骤:
1、将开发板换成NUCLEO-F429ZI连接PC,同样的工程编译烧录,NUCLEO-F429ZI上的led2可以闪烁(411的led2连接的是GPIOA,429的led2连接的是GPIOB)。
2、打开F429ZI的启动文件startup_stm32f429xI.S,发现如下语句:
/* Call the clock system intitialization function.*/ bl SystemInitPre bl HAL_InitPre #if defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) ldr r0, =uvisor_init blx r0 #endif /* defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) */ bl SystemInit
比startup_stm32f411xe.S多了如下语句
/* Call the clock system intitialization function.*/
bl SystemInitPre
bl HAL_InitPre
于是将上述语句添加至startup_stm32f411xe.S中,并将/TARGET_STM32F4/
TARGET_STM32F429xI/device中的system_init_pre.c文件拷贝至/TARGET_STM32F4/
TARGET_STM32F411xE/device文件夹下。
system_init_pre.c内容如下:
#include "stm32f4xx.h" #include "nvic_addr.h" /*!< Uncomment the following line if you need to relocate your vector Table in Internal SRAM. */ /* note: if uVisor is present the definition must go in system_init_pre.c */ /* #define VECT_TAB_SRAM */ #define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */ /* this function is needed to peform hardware initialization that must happen * before the uVisor; the whole SystemInit function for the STM32F4 cannot be * put here as it depends on some APIs that need uVisor to be enabled */ void SystemInitPre(void) { /* FPU settings ------------------------------------------------------------*/ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ #endif /* Configure the Vector Table location add offset address ------------------*/ #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #else SCB->VTOR = NVIC_FLASH_VECTOR_ADDRESS; /* Vector Table Relocation in Internal FLASH */ #endif }
完成上述修改过后,连接NUCLEO-F411RE开发板至PC,编译烧录没问题,但是LED2仍然不闪烁。
这里有个问题:uVisor Porting Guide中对于启动文件有如下要求:
Make sure that no static initialization (zeroing the BSS section, loading data from flash to SRAM) happens before the uVisor initialization. Even setting a single global variable before uvisor_init() and then referring to it later can result in data corruption.
uvisor_init()
但是/uvisor_porting/mbed-os/targets/TARGET_STM/TARGET_STM32F4/
TARGET_STM32F429xI/device/TOOLCHAIN_GCC_ARM中的startup_stm32f429xI.S启动文件中代码片段如下:
.section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: ldr sp, =__stack /* set stack pointer */ /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 b LoopCopyDataInit CopyDataInit: ldr r3, =_sidata ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 LoopCopyDataInit: ldr r0, =_sdata ldr r3, =_edata adds r2, r0, r1 cmp r2, r3 bcc CopyDataInit ldr r2, =_sbss b LoopFillZerobss /* Zero fill the bss segment. */ FillZerobss: movs r3, #0 str r3, [r2], #4 LoopFillZerobss: ldr r3, = _ebss cmp r2, r3 bcc FillZerobss /* Call the clock system intitialization function.*/ bl SystemInitPre bl HAL_InitPre #if defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) ldr r0, =uvisor_init blx r0 #endif /* defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) */ bl SystemInit /* Call static constructors */ //bl __libc_init_array /* Call the application's entry point.*/ //bl main // Calling the crt0 'cold-start' entry point. There __libc_init_array is called // and when existing hardware_init_hook() and software_init_hook() before // starting main(). software_init_hook() is available and has to be called due // to initializsation when using rtos. bl _start bx lr .size Reset_Handler, .-Reset_Handler
显然在uVisor初始化之前有 static initialization (zeroing the BSS section, loading data from flash to SRAM)。
于是,将startup_stm32f411xe.S进行修改,使得uVisor初始化在static initialization之前:
.section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: /* Call the clock system intitialization function.*/ bl SystemInitPre bl HAL_InitPre #if defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) ldr r0, =uvisor_init blx r0 #endif /* defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) */ bl SystemInit ldr sp, =__stack /* set stack pointer */ /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 b LoopCopyDataInit CopyDataInit: ldr r3, =_sidata ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 LoopCopyDataInit: ldr r0, =_sdata ldr r3, =_edata adds r2, r0, r1 cmp r2, r3 bcc CopyDataInit ldr r2, =_sbss b LoopFillZerobss /* Zero fill the bss segment. */ FillZerobss: movs r3, #0 str r3, [r2], #4 LoopFillZerobss: ldr r3, = _ebss cmp r2, r3 bcc FillZerobss /* Call static constructors */ //bl __libc_init_array /* Call the application's entry point.*/ //bl main // Calling the crt0 'cold-start' entry point. There __libc_init_array is called // and when existing hardware_init_hook() and software_init_hook() before // starting main(). software_init_hook() is available and has to be called due // to initializsation when using rtos. bl _start bx lr .size Reset_Handler, .-Reset_Handler
重新对NUCLEO-F411RE进行编译烧录,编译烧录没有问题,LED2仍然不闪烁。
3、修改main.cpp如下
#include "mbed.h" DigitalOut led(LED2); int main(void) { while (true) { led = !led; wait(0.5); } }
并删除mbed_app.json文件,即不使能uVisor。编译烧录,LED2正常闪烁。