I recently bought an RPi 2, and set about following the various bare metal tutorials available.
After a while, I found dwelch67's excellent collection of examples, specifically "blink05", that goes through the various steps necessary to blink the LED through the use of the IRQ exception handler.
Turned out my code succeeded at every step including generating an interrupt. At that point, I could see that control was transferred someplace else, but it definitely wasn't to the exception vector I'd set up at 0x18. (Interesting excercise, btw, to debug code when the only I/O available is a blinking LED

I triad everything I could think of, and at last started checking all assumptions I'd made about the state of the system at various points. I ended up with the following bit of assembly:
Code: Select all
_start:
ldr r0, =_ex_table
mov r1, #0
ldmia r0!, {r2-r9}
stmia r1!, {r2-r9}
ldmia r0!, {r2-r9}
stmia r1!, {r2-r9}
mov sp, #0x8000000
// blink mode
mrs r0, CPSR
and r0, r0, #0xf
bl blink
// Switch to interrupt mode and set the interrupt mode stack pointer.
mrs r3, CPSR
bic r3, r3, #(MODE_MASK | FIQ_MASK_BIT | IRQ_MASK_BIT)
orr r3, r3, #(IRQ_MODE | FIQ_MASK_BIT | IRQ_MASK_BIT)
msr CPSR_c, r3
mov sp, #0x7f00000
// blink mode in interrupt mode
mrs r0, CPSR
and r0, r0, #0xf
bl blink
// Switch back to supervisor mode (our application mode).
//mrs r3, CPSR
//bic r3, r3, #MODE_MASK
//orr r3, r3, #(SVC_MODE | FIQ_MASK_BIT | IRQ_MASK_BIT)
mov r3, #(SVC_MODE | FIQ_MASK_BIT | IRQ_MASK_BIT)
msr CPSR_c, r3
mov sp, #0x8000000
// blink mode (again)
mrs r0, CPSR
and r0, r0, #0xf
bl blink
// Clear BSS
ldr r3, =__bss_start__
ldr r4, =__bss_end__
mov r5, #0
mov r6, #0
mov r7, #0
mov r8, #0
b 2f
1: stmia r3!, {r5-r8}
2: cmp r3, r4
blo 1b
svc #10
_hang: b _hang
_ex_table:
ldr pc, _reset_addr
ldr pc, _undefined_addr
ldr pc, _svc_addr
ldr pc, _prefetch_addr
ldr pc, _data_addr
ldr pc, _unused_addr
ldr pc, _irq_addr
ldr pc, _fiq_addr
_reset_addr: .word _reset_wrapper
_undefined_addr: .word _undefined_wrapper
_svc_addr: .word _svc_wrapper
_prefetch_addr: .word _prefetch_wrapper
_data_addr: .word _data_wrapper
_unused_addr: .word _unused_wrapper
_irq_addr: .word _irq_wrapper
_fiq_addr: .word _fiq_wrapper
_reset_wrapper:
mov sp, #0x7000000
1: mov r0, #1
bl blink
b 1b
_undefined_wrapper:
mov sp, #0x7000000
1: mov r0, #2
bl blink
b 1b
_svc_wrapper:
mov sp, #0x7000000
1: mov r0, #3
bl blink
b 1b
_prefetch_wrapper:
mov sp, #0x7000000
1: mov r0, #4
bl blink
b 1b
_data_wrapper:
mov sp, #0x7000000
1: mov r0, #5
bl blink
b 1b
_unused_wrapper:
mov sp, #0x7000000
1: mov r0, #6
bl blink
b 1b
_irq_wrapper:
mov sp, #0x7000000
1: mov r0, #7
bl blink
bl blink
b 1b
_fiq_wrapper:
mov sp, #0x7000000
1: mov r0, #8
bl blink
b 1b
First of all, the svc call still didn't result in the correct exception vector being called, that wasn't really surprising. What surprised me was that I got 3 x 10 blinks. That is, the system obviously started out in Hypervisor (HYP) mode, and both the tries to change mode was silently failing. Also, obviously the exception vector table was not placed at 0x0.
At last, I switched out the bootcode.bin and start.elf files I used to boot, with ones I found in one of the tutorials. After this, the code started working as it should, the mode changes did succeed, and now even the svc call did what it was supposed to.
So it looks like recent bootcode.bin / start.elf code has started initializing the processor differently from what it used to, and that that change may affect various bare metal projects.
So:
- Does anybody know the reason for this change in behaviour?
- Is there a way to get out of the HYP mode / set up exception vectors given the new behaviour, or should I just stick to the older init files?
--
Jo.