ARM Bootloader
The bootloader is the program that runs in an embedded processor immediately after a reset of the processor and is responsible for initializing the connected devices and starting the main software (for example, the kernel of an OS). The ARM bootloader defines the vector table of the computing environment.
Assume that the main program is coded in C and the entry function is called entry as shown below:
int entry(void) { return 0; }
which is compiled for the ARM Cortex-M0 (ARMv6-M architecture) target like this:
arm-none-eabi-gcc -c -mcpu=cortex-m0 hello_world.c -o hw-entry.o
We also create an assembly file (hw-startup.s) that specifies the vector table, including the reset handler:
/* Vector table for bootloader. Assemble via arm-none-eabi-as -mcpu=cortex-m0 hw-startup.s -o hw-startup.o */ .section INTERRUPT_VECTOR, "x" .global _Reset _Reset: b Reset_Handler /* Reset */ b . /* Undefined */ b . /* SWI */ b . /* Prefetch Abort */ b . /* Data Abort */ b . /* Reserved */ b . /* IRQ */ b . /* FIQ */ Reset_Handler: /* In Thumb mode we can not load into SP directly. Only into the eight low registers */ ldr r1, =stack_top mov sp, r1 /* In ARM mode we can simply write ldr sp, =stack_top */ bl entry b .
and assemble like this:
arm-none-eabi-as -mcpu=cortex-m0 hw-startup.s -o hw-startup.o
The object files are linked into an executable Linux binary in ELF format like this:
arm-none-eabi-ld -T hw-boot.ld hw-entry.o hw-startup.o -o hello_world.elf
where hw-boot.ld is the linker file that defines where the code from the object files will be placed into the executable:
ENTRY(_Reset) SECTIONS { . = 0x0; .text : { hw-startup.o (INTERRUPT_VECTOR) *(.text) } .data : { *(.data) } .bss : { *(.bss COMMON) } . = ALIGN(8); . = . + 0x100; /* allocating 4 KB for stack memory */ stack_top = .; }
The ELF file can be inspected with the readelf tool like this:
arm-none-eabi-readelf -A hello_world.elf Attribute Section: aeabi File Attributes Tag_CPU_name: "Cortex-M0" Tag_CPU_arch: v6S-M Tag_CPU_arch_profile: Microcontroller Tag_THUMB_ISA_use: Thumb-1 Tag_ABI_PCS_wchar_t: 4 Tag_ABI_FP_denormal: Needed Tag_ABI_FP_exceptions: Needed Tag_ABI_FP_number_model: IEEE 754 Tag_ABI_align_needed: 8-byte Tag_ABI_enum_size: small
and disassembled via objdump like this:
arm-none-eabi-objdump -d hello_world.elf hello_world.elf: file format elf32-littlearm Disassembly of section .text: 00000000 <_Reset>: 0: e006 b.n 10 <Reset_Handler> 2: e7fe b.n 2 <_Reset+0x2> 4: e7fe b.n 4 <_Reset+0x4> 6: e7fe b.n 6 <_Reset+0x6> 8: e7fe b.n 8 <_Reset+0x8> a: e7fe b.n a <_Reset+0xa> c: e7fe b.n c <_Reset+0xc> e: e7fe b.n e <_Reset+0xe> 00000010 <Reset_Handler>: 10: 4902 ldr r1, [pc, #8] ; (1c <Reset_Handler+0xc>) 12: 468d mov sp, r1 14: f000 f804 bl 20 <entry> 18: e7fe b.n 18 <Reset_Handler+0x8> 1a: 0000 .short 0x0000 1c: 00000130 .word 0x00000130 00000020 <entry>: 20: b580 push {r7, lr} 22: af00 add r7, sp, #0 24: 2300 movs r3, #0 26: 0018 movs r0, r3 28: 46bd mov sp, r7 2a: bd80 pop {r7, pc}
Finally, objcopy is used to remove the ELF header and convert the file into an executable that can be run as-is on the Cortex-M0.
arm-none-eabi-objcopy -O binary hello_world.elf hello_world.bin