ARM
Cortex-M33, startup.s and main.c
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:
- Define a function say 'a_ns_function'. This function does
nothing but writes some bytes to some memory location.
- 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.
- 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).
- 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.
- 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:
- image.bin-> main binary file used for RTL simulation
with a suitable memory model
- __image.axf
- image.hex -> this can also be used for RTL simulation
with a suitable memory model
- image.txt-> Disassembly file
Click Here to Make Comments or ask Questions
SITE HOME