ARM Cortex-M33, startup.s and main.c
-Aviral Mittal avimit att yahu dat cam.
https://www.linkedin.com/in/avimit/
SITE HOME

Secure to Non-Secure Switch on ARM V8.1 Architecture processor. ARM-Cortex M33.
This web page is created to provide a bare minimum startup.s and main.c files which can be compiled by
ARM Compiler 6.12 or ARM Compiler 6.13 to produce binary executable for Cortex-M33 processor
The ARM Cortex-M33 implements ARM V8.1 instruction set architecture.
This code can also be compiled by Kiel IDE while M33 or ARMv8.1 is used as a target processor.
ARM Cortex M23 is another processor which is based on  ARM v8.1 instruction-set architecture.
The 'main.c' is a very simple code written to put switch the ARM processor from Secure to Non-Secure State.
The bare minimum needed to get your code up-and-running is put into following 3 files
The objective here is to write a very simple program which will put the processor into Non-Secure state.
Steps:
  1. Define a function say 'a_ns_function'. This function does nothing but writes some bytes to some memory location.
  2. Put a compiler directive in your C-program to instruct the compiler/linker to keep the binary compiled code for this function as a specific memory location.
  3. Define Secure and non-secure memory locations. By default all of the memory space is treated as secure. Hence for this example only 1 non-secure region is defined. This is done by programing the SAU (Security Attribution Unit).
  4. Make sure that the compiler directive instructs the compiler/linker to put the compiled code corresponding to 'a_ns_function' in the region which is defined as non-secure region.
  5. Make a call to the function 'a_ns_function' by using in-line compiler instruction BLXNS. This instruction will make the processor switch from Secure to Non-Secure State.
Here is the C-code. Note that this is doing a bit more than the above.
//Avi : 11 Dec 2019: This code is running.
//This code is setting up SAU to set up non-secure region
//This code then makes the processor to switch from secure state to non-secure state
//The results can be seen in simulation.
//When this code runs, the CURRNS goes '1', following the BLXNS instruction,
//which calls the a_ns_function
#include <datatypes.h>
__asm(".global __use_no_semihosting"); //to direct the compiler not to use semi-hosting (BKPT)
__asm(".global __ARM_use_no_argv"); //direct the compiler not to use args to main
void _sys_exit ()
{
  while (1); //temporary place holders
}

void _ttywrch ()
{
  return; //temporary place holders
}
void en_sau ( CPU_SAU_REGS_TypeDef * saupointer)
{
  saupointer = SAU_REGS;
  saupointer->SAU_CTRL = 0x00000001;//Enable SAU
}

int get_no_of_sau_regions (CPU_SAU_REGS_TypeDef * saupointer)
{
  return saupointer->SAU_TYPE;
}

void set_mpu ( CPU_MPU_REGS_TypeDef * mypointer)
{
        mypointer = MPU_REGS;
        mypointer->MPU_CTRL = 0x00000007; //PRIVDEFENA (priv sw access to default memory map), HFNMIENA(enables mpu operation during hard fault), ENABLE = 1,1,1
        mypointer->MPU_RNR  = 0x00000001; //region 1, MPU RBAR, and ABAR now correspond to region 1
        mypointer->MPU_RBAR = 0x40000011; //Valid = 1, region 1

        //31302928  27262524  23222120  19181716  15141312  11100908  07060504  03020100
        //r r r xn  r apapap  r r t e   x s c b   s        r      d   r r s i     z e en
        //0 0 0 0   0 0 1 1   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 1   0 1 1 1
        mypointer->MPU_RASR = 0x03000017; //enable 4 KB region (size = 01011), TEX,S,C,B =0, Non-shareable, 011 -> RW,RW, instruction fetches enabled.
}

void go_to_dsleep ()
{
  SCR = 0x00000004; //bit 2 of SCR for deepsleep
  __asm("WFE");
}

void a_ns_function () __attribute__((section(".ARM.__at_0x20001a00")));
void a_ns_function ()
{
  GPIO_5 = 0x5a5a5a5a;
  GPIO_6 = 0x6a6a6a6a;
}

void a_secure_function ()
{
  GPIO_4 = 0xabcdef00;
}

//_sys_command_string
int main ()
{
        uint32_t cpu_id_var;
        const uint32_t cpu_id_val = 0x410FC240;
        int r0;//,r1,r2,r3,r4,r5,r6,r7,r8,r9;
        int no_of_sau_regions;
        CPU_MPU_REGS_TypeDef * mypointer; //pointer to the structure of mpu registers
        CPU_SAU_REGS_TypeDef * saupointer; //pointer to the structure of sau registers
        asm("nop");
        //set_mpu(mypointer);
        saupointer = SAU_REGS;
        saupointer->SAU_RNR = 0x00000000;
        saupointer->SAU_RBAR = 0x20001000U;
        saupointer->SAU_RLAR = 0x0000FFFDU; //d=1101 e= 1110, f = 1111 // NSC = 0, EN = 1 The region is Non-Secure
        __asm("DSB");
        GPIO_1 = saupointer->SAU_RBAR;
        GPIO_2 = saupointer->SAU_RLAR;

        saupointer->SAU_RNR = 0x00000001;
        saupointer->SAU_RBAR = 0x20020000;
        saupointer->SAU_RLAR = 0x0002FFFE; // NSC = 1, EN = 1 The region is secure and Non-Secure Callable
        en_sau(saupointer);
        __asm("DSB");
        no_of_sau_regions = get_no_of_sau_regions(saupointer);
        GPIO_1 = saupointer->SAU_RBAR;
        GPIO_2 = saupointer->SAU_RLAR;
        GPIO_3 = saupointer->SAU_CTRL;
        saupointer->SAU_RNR = 0x00000000;
        __asm("DSB");
        GPIO_2 = saupointer->SAU_RLAR;
        GPIO_3 = no_of_sau_regions;
        a_secure_function();
        __asm("DSB");
        __asm("MOV r12,0x1a00");
        __asm("MOVT r12,0x2000");
        __asm("BLXNS r12"); //; Call Non-secure function. This sets r14 to FUNC_RETURN value
        __asm("DSB");
        go_to_dsleep();
        while(1);
}



The C-code uses the following startup.s file:

Stack_Size EQU 0x00000a00
               AREA STACK,NOINIT,READWRITE,ALIGN=3
__stack_limit
Stack_Mem       SPACE Stack_Size
__initial_sp
; Heap
Heap_Size       EQU     0x00000C00;
                        AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_mem        SPACE Heap_Size
__heap_limit

        PRESERVE8
        THUMB


; Vector Table Mapped to Address 0 at Reset
 AREA RESET, DATA, READONLY
 EXPORT __Vectors
 EXPORT __Vectors_End
 EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
          DCD Reset_Handler ; Reset Handler
      
__Vectors_End

__Vectors_Size EQU __Vectors_End - __Vectors
                AREA |.text|, CODE, READONLY
Reset_Handler   PROC
                                EXPORT Reset_Handler [Weak]
                                IMPORT __main
                                MOV      r0,#0xed08 ; loading system registers set some bits to enable fpu mve
                                MOVW     r1,#0 ; registers are : CPACR reg, co-po access control reg
                                MOVT     r0,#0xe000 ; providing 'full access' to CP10 and CP11
                                MOVT     r1,#0x1000
                                STR      r1,[r0,#0]
                                LDR      r1,[r0,#0x80]
                                ORR      r1,r1,#0xf00000
                                STR      r1,[r0,#0x80]
                                MOVW     r0,#0xc
                                MOV      r1,#0x7840
                                MOVT     r0,#0x2000
                                MOVT     r1,#0x17d
                                STR      r1,[r0,#0]
                                LDR R0, =__main
                                BX  R0
                                ENDP
                                EXPORT   __stack_limit
                                EXPORT   __initial_sp
                                EXPORT   __heap_base
                                EXPORT   __heap_limit

                                END



The C-code also uses the following datatypes.h file:


typedef unsigned int uint32_t;
#define CPU_MPU_REG_BASE ((uint32_t) 0xE000ED90)
#define CPU_SAU_REG_BASE ((uint32_t) 0xE000EDD0)
#define PER_BASE ((uint_32) 0x40000000)
#define __IO
#define __RO
#define __RW   
#define CPU_ID_REG_ADDR (uint32_t *) (0xE000ED00)
#define SCR *((uint32_t *) (0xE000ED10))
#define GPIO_1 *((uint32_t *) (0x20000ff0))
#define GPIO_2 *((uint32_t *) (0x20000df0))
#define GPIO_3 *((uint32_t *) (0x20000cf0))
#define GPIO_4 *((uint32_t *) (0x20000bf0))
#define GPIO_5 *((uint32_t *) (0x20001bb0)) //lines in non-secure region
#define GPIO_6 *((uint32_t *) (0x20000bb0)) //lines in secure region
#define MYADDR (uint32_t *) (0x20002000)
//#define MPU_TYPE_REG *((uint32_t *) (0xE000ED90))
typedef struct {
        __RO uint32_t MPU_TYPE;
        __RW uint32_t MPU_CTRL; //MPU Control Reg
        __RW uint32_t MPU_RNR;  //MPU Region Number Regiser
        __RW uint32_t MPU_RBAR; //MPU Region Base Addr Reg
        __RW uint32_t MPU_RASR; //MPU Attribute and Size Reg
} CPU_MPU_REGS_TypeDef;
#define MPU_REGS ((CPU_MPU_REGS_TypeDef *) CPU_MPU_REG_BASE) //MPU_REGS should be an address.

typedef struct {
        __RW uint32_t SAU_CTRL; //SAU Control Reg
        __RO uint32_t SAU_TYPE; //SAU Control Reg
        __RW uint32_t SAU_RNR;  //SAU Region Number Regiser
        __RW uint32_t SAU_RBAR; //SAU Region Base Addr Reg
        __RW uint32_t SAU_RLAR; //SAU Limit Address Register
} CPU_SAU_REGS_TypeDef;
#define SAU_REGS ((CPU_SAU_REGS_TypeDef *) CPU_SAU_REG_BASE) //MPU_REGS should be an address.



How to compile:
Make a directory 'my_work'
Make directories 'my_work/common', 'my_work/csrc', 'my_work/compile_dir'
put 'main.c' in the directory 'my_work/csrc'
put 'startup.s' and 'datatypes.h' in the directory 'my_work/common'
go in the directory 'my_work/compile_dir' and issue the following commands:

/usr/6.13/bin/armclang main.c -c --target=arm-arm-none-eabi -mcpu=cortex-m33 -o c.o -O1 -I  ../common
/usr/6.13/bin/armasm startup.s --cpu=cortex-m33 -o a.o
/usr/6.13/bin/armlink a.o c.o --ro_base 0x00000000 --rw_base 0x20000000 --entry Reset_Handler --first __Vectors
/usr/6.13/bin/fromelf --text -c -s -t -z --output image.txt __image.axf
/usr/6.13/bin/fromelf -cvf __image.axf --vhx --8x1 -o image.hex
/usr/6.13/bin/fromelf --bin -o image.bin __image.axf


This will produce the following 4 files:


Click Here to Make Comments or ask Questions

SITE HOME