uVisor移植问题请教

uVisor NUCLEO-F411RE开发板移植问题说明

主要参考来源:

uVisor Documentationhttps://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

开发环境:

OSUbuntu16.04

软件:mbed-cli 1.5.0

工具链:gcc-arm-none-eabi-6-2017-q2-update

问题描述:按照porting guide移植到NUCLEO-F411RE后,参照getting started guide进行检验,使能uVisorled2不能闪烁。原本官方支持的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闪烁。

/* ~/code/uvisor-example/source/main.cpp */

#include "mbed.h"

DigitalOut led(LED2);

int main(void)
{
    while (true) {
        led = !led;
        wait(0.5);
    }
}

2、将uVisorGit下来($ git clone git@github.com:ARMMbed/uvisor.git

uVisor文件夹放在/home/ackj/uvisor_porting/mbed-os/features

/FEATURE_UVISOR/importer/TARGET_IGNORE目录下。

3、在/home/ackj/uvisor_porting/mbed-os/features/

FEATURE_UVISOR/importer/TARGET_IGNORE/uvisor/platform目录下添加stm32f411re文件夹,将stm32文件夹中的内容拷贝至stm32f411re文件夹内。


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可以闪烁(411led2连接的是GPIOA429led2连接的是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_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正常闪烁。