Building a Secure image using the ARMv8-M Security Extensions
When building a Secure image, you must also generate an import library that specifies the entry points to the Secure image. The import library is used when building a Non-secure image that calls the Secure image.
The following procedure is not a complete example, and assumes that your code sets up the Secure Attribution Unit (SAU) and calls the Non-secure startup code.
Procedure
- Create an interface header file,
myinterface_v1.h
, to be used by Non-secure code:int entry1(int x); int entry2(int x);
- In the C program for your Secure code,
secure.c
, include the following:#include <arm_cmse.h> #include "myinterface_v1.h" int func1(int x) { return x; } int __attribute__((cmse_nonsecure_entry)) entry1(int x) { return func1(x) ; } int __attribute__((cmse_nonsecure_entry)) entry2(int x) { return entry1(x); } int main(void) { return 0; }
In addition to the implementation of the two entry functions, the code defines the function
func1()
that can only be called by Secure code.
- Create an object file using the armclang
-mcmse -mfloat-abi=soft
command-line options:$ armclang -c --target arm-arm-none-eabi -march=ARMv8-M.main -mcmse -mfpu=none secure.c -o secure.o
- To see the disassembly of the machine code that is generated by
armclang, enter:
$ armclang -c --target arm-arm-none-eabi -march=ARMv8-M.main -mcmse -mfloat-abi=soft -S secure.c
The disassembly is stored in the file
secure.s,
for example:.text ... .code 16 .thumb_func ... func1: .fnstart ... bx lr ... __acle_se_entry1: entry1: .fnstart @ BB#0: save {R7, LR} PUSH {R7, LR} ... BL func1 ... POP.W {R7, LR} ... BXNS LR ... __acle_se_entry2: entry2: .fnstart @ BB#0: .save {R7, LR} PUSH {R7, LR} ... BL entry1 ... POP.W {R7, LR} BXNS LR ... main: .fnstart @ BB#0: ... MOVS R0, #0 ... BX LR ...
The two symbols
__acle_se_entry_name
andentry_name
indicate the start of an entry function to the linker. An entry function does not start with a Secure Gateway (SG
) instruction.
- You can control the placement of the section with the veneers using a scatter file
and place it in your Non-secure Callable (NSC) region memory region. Create a
scatter file containing the
Veneer$$CMSE
selector to place the entry function veneers, for example:LOAD_REGION 0x0 0x3000 { EXEC_R 0x0 { *(+RO,+RW,+ZI) } EXEC_NSCR 0x4000 0x1000 { *(Veneer$$CMSE) } ARM_LIB_STACK 0x700000 EMPTY -0x10000 { } ARM_LIB_HEAP +0 EMPTY 0x10000 { } } ...
- Using armclang you can link the object file using the armlink
--fpu softvfp
and--import-cmse-lib-out
command-line options and the scatter file to create the Secure image:$ armlink secure.o -o secure.axf --cpu 8-M.Main --fpu SoftVFP --import-cmse-lib-out importlib_v1.o --scatter secure.scf
In addition to the final image, the link in this example also produces the import library,
importlib_v1.o
, for use when building a Non-secure image. Assuming that the section with veneers is placed at address0x4000
, the import library consists of a relocatable file containing only a symbol table with the following entries:
Symbol type |
Name |
Address |
STB_GLOBAL, SHN_ABS, STT_FUNC |
entry1 |
|
STB_GLOBAL, SHN_ABS, STT_FUNC |
entry2 |
|
Note
If you have an import library from a previous build of the Secure image, you can ensure that the addresses in the output import library do not change when producing a new version of the Secure image.
To do this, specify the --import-cmse-lib-in
command-line option together
with the --import-cmse-lib-out
option. However, make sure that the input
and output libraries have different names.
- When you link the relocatable file corresponding to this
assembly code into an image, the linker creates veneers in a
section containing only entry veneers. To see the entry veneers
generated by the linker, enter:
$ fromelf --text -s -c secure.axf
The following entry veneers are generated in the EXEC_NSCR execute-only (XO) region for this example:
... ** Section #3 'EXEC_NSCR' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR + SHF_ARM_NOREAD] Size : 32 bytes (alignment 32) Address: 0x00004000 $t entry1 0x00004000: E97FE97F .... SG ; [0x3E08] 0x00004004: F7FCB85E ..^. B __acle_se_entry1 ; 0xC4 entry2 0x00004008: E97FE97F .... SG ; [0x3E10] 0x0000400c: F7FCB86C ..l. B __acle_se_entry2 ; 0xE8 ...
The section with the veneers is aligned on a 32-byte boundary and padded to a 32-byte boundary.
If you do not use a scatter file, the entry veneers are placed in an ER_XO section as the first execution region, for example:
... ** Section #1 'ER_XO' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR + SHF_ARM_NOREAD] Size : 32 bytes (alignment 32) Address: 0x00008000 $t entry1 0x00008000: E97FE97F .... SG ; [0x7E08] 0x00008004: F000B85A ..Z. B.W __acle_se_entry1 ; 0x80BC entry2 0x00008008: E97FE97F .... SG ; [0x7E10] 0x0000800c: F000B868 ..h. B.W __acle_se_entry2 ; 0x80E0 ...
Postrequisites
After you have built your Secure image:
- Pre-load the Secure image onto your device.
- Deliver your device with the pre-loaded image, together with the import library package, to a party who develops the Non-secure code for this device. The import library package contains:
- The interface header file, h.
- The import library, importlib_v1.o.