From Electriki
Jump to: navigation, search

back to project page

After reset

The 12kB boot block is mapped into 0x7d000. It's also visible at 0x7fff d000.

Bootloader checks for valid checksum of vectors, then hands off control to flash at 0x0, or start serial port shit.

Some explanation of startup (relevant to other MCUs too): On startup CPU jumps to location 0, and just starts executing code. Since there's only one instruction space, the first instruction is a branch to reset handler.

Reset handler needs to set up stacks. In this example it only sets up the current (Supervisor) mode stack, but it's easy to set them for other modes... something along these lines: MODE_FIQ ldr sp, =_ram_end-0x100

IF you use User mode... don't forget to switch to that mode last, because you can't switch back.

A word on sections

There's basically three differently handled sections:

  • .text/.rodata for code and readonly data
  • .data for initialized data
  • .bss for uninitialized data

.text and .rodata are obviously just saved into FLASH, and that's fine for them. .data is a bit more tricky, since addresses are from RAM, but data needs to be saved somewhere (well... FLASH, where else). So you need to have code that copies .data section from flash. And following that is the code to zero the .bss.

And that's it. C environment is ready!

ARM exception vector locations

ok, so these fuckers can be remapped:

* boot loader mode (on start up), boot block vectors are mapped here
* user flash mode (from boot code), activated by BL, needs valid program sig and non-forced BL. non re-mapped vectors (== stays in flash, bottom)
* user ram mode (from program), user program can remap vectors to bottom of SRAM

The 64-byte block is remapped. So some handlers can fit there.

arm vectors
0x0 Reset
0x4 Undefined Instruction
0x8 Software Interrupt
0xc Prefetch Abort
0x10 Data Abort
0x14 2's complement of checksum of vectors
0x18 IRQ
0x1c FIQ

Crt.s looks like this
        .section .vectors
        .code 32
        .align 0
        .global _vectors
.reset:         b       start
.undefined:     bl      endless
.swi:           bl      endless
.prefetchabort: bl      endless
.dataabort:     bl      endless
.checksum:      .word   0x92ffffec /* hand calculated, grr */
.irq:           bl      endless
.fiq:           bl      endless
        b       endless
        /* missing: setup of sp for other modes */
        /* setup sp for Supervisor mode */
        ldr     sp, =_ram_end
        bl      init
        bl      main
        b       endless

A mofo was also the linker script:
        FLASH (rx) :    ORIGIN = 0,             LENGTH = 512K
        RAM (rw) :      ORIGIN = 0x40000000,    LENGTH = 32K
/* http://sourceware.org/binutils/docs/ld/Output-Section-LMA.html */
_ram_end = ORIGIN(RAM) + LENGTH(RAM) - 4; /* quite sure -4 isn't necessary, but i'd need to check */
        .text :
        } >FLASH
        _fldata = . ;
        .data : ALIGN(4)
                _data = . ;
                _edata = . ;
        } >RAM AT>FLASH
        .bss : ALIGN(4)
                _bss = . ;
                _ebss = . ;
        } >RAM

But ok, it works now, and after crt, we can transfer more init to c code:
#include <types.h>
#include <board.h>
extern u32 _fldata, _data, _edata, _bss, _ebss, _ram_end;
void init()
        u32 *src = &_fldata;
        u32 *dest = &_data;
        /* copy .data from flash */
        while (dest < &_edata)
                *dest++ = *src++;
        /* zero .bss */
        dest = &_bss;
        while (dest < &_ebss)
                *dest++ = 0;
        /* poison the rest of ram */
        while (dest < (u32*)&src-16)
                *dest++ = 0xcbababe;

Hrm, code dumps are boring, but crt.s and linker script really took a while to make it work.