alexhoppus
Posts: 10
Joined: Sat Feb 13, 2016 9:04 am

Vector table init at rpi2

Tue Mar 01, 2016 8:41 pm

Hi! I have troubles with printing some info about occurred exception.
As i mentioned in subj my target is rpi2 i.e. bcm2836 and cortex a-7
i followed this kind of setup https://github.com/dwelch67/raspberrypi/tree/master/mmu
This is how vectors are initialized and copied to zeroth address

Code: Select all

.globl _start
_start:
        ldr pc,add_handler_00
        ldr pc,add_handler_04
        ldr pc,add_handler_08
        ldr pc,add_handler_0C
        ldr pc,add_handler_10
        ldr pc,add_handler_14
        ldr pc,add_handler_18
        ldr pc,add_handler_1C
add_handler_00: .word reset
add_handler_04: .word handler_04
add_handler_08: .word handler_08
add_handler_0C: .word handler_0C
add_handler_10: .word handler_10
add_handler_14: .word handler_14
add_handler_18: .word handler_18
add_handler_1C: .word handler_1C

// Entry point for the uart bootloader
reset:
        mov r0,#0x8000
        mov r1,#0x0000
        // setup vectors
        ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
        stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
        ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
        stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
This is how exception handlers are look like:

Code: Select all

handler_04:
        mov r0,#0x04
        ldr r3, =exception_handler
        bx r3
...
handler_1C:
        mov r0,#0x1C
        ldr r3, =exception_handler
        bx r3
...
void exception_handler(uint32_t r0)
{
        guart->puts("Exception handler reached with code: ");
        guart->puts(int_to_str(exception_str, r0, 16));
        guart->puts("\n");
        while(1){};
}
in C code i initialize UART and print vector table to be sure that it's ok. Also i print SCTLR register, mostly it is interesting because of bit 13 - this bit selects the base address of the exception vectors.

Code: Select all

       for (int i = 0; i < 16; i++) {
                uart.puts(int_to_str(exception_str, vt[i], 16));
                uart.puts("\n");
        }
        uint32_t reg;
        asm volatile("mrc p15, 0, %[r], c1, c0, 0": [r]"=r" (reg)::);
        uart.puts("\n");
        uart.puts(int_to_str(exception_str, reg, 16));
This gives me the following output:

Code: Select all

E59FF018
E59FF018
E59FF018
E59FF018
E59FF018
E59FF018
E59FF018
E59FF018
8040
8094
80A0
80AC
80B8
80C4
80D0
80DC

C50878
This is OK according to objdump objdump

Code: Select all

Disassembly of section .text:
00008000 <__start>:
    8000:       e59ff018        ldr     pc, [pc, #24]   ; 8020 <add_handler_00>
    8004:       e59ff018        ldr     pc, [pc, #24]   ; 8024 <add_handler_04>
    8008:       e59ff018        ldr     pc, [pc, #24]   ; 8028 <add_handler_08>
    800c:       e59ff018        ldr     pc, [pc, #24]   ; 802c <add_handler_0C>
    8010:       e59ff018        ldr     pc, [pc, #24]   ; 8030 <add_handler_10>
    8014:       e59ff018        ldr     pc, [pc, #24]   ; 8034 <add_handler_14>
    8018:       e59ff018        ldr     pc, [pc, #24]   ; 8038 <add_handler_18>
    801c:       e59ff018        ldr     pc, [pc, #24]   ; 803c <add_handler_1C>

00008020 <add_handler_00>:
    8020:       00008040        .word   0x00008040
....
0000803c <add_handler_1C>:
    803c:       000080dc        .word   0x000080dc
Then i try to generate the exception in the following way:

Code: Select all

asm("b 0x20");
i.e. i jump to the addr with content 0x00008040 what is undefinstr
And see .. nothing! I am not getting into exception vector printing. According to the SCTLR value, the vector table is mapped to 0x00000000 address, which means undef instruction vector is located at addr 0x04. If i jump to the exception vector from the place i try to generate exception directly (i.e. asm("b 0x04")) the exception printing function works ok! So it's looks like it jumps to another addr when exception is generated (for which reason?) Please, could anyone help me in resolving this issue?

dwelch67
Posts: 967
Joined: Sat May 26, 2012 5:32 pm

Re: Vector table init at rpi2

Tue Mar 01, 2016 10:28 pm

I keep meaning to check out/work on the mmu stuff for the rpi2. Now the rpi3 is coming so that is extra fun. Ill try to get motivated. the big difference is as lf late last year the rpi2 is in HYP mode, where the rpi1 is not/doesnt have that mode it has the traditional svc, user, irq, fiq modes. So there is likely a combination of stuff you cant get to and/or the addresses are wrong because of the mode is my guess, I have not looked at it, I have not finished porting my examples to the rpi A/B+ nor the rpi2, I did some of the blinking led ones and the interrupt one.

swarren
Posts: 45
Joined: Tue Mar 01, 2016 5:56 am

Re: Vector table init at rpi2

Wed Mar 02, 2016 4:06 am

Make sure your startup (reset) code has set up stack pointer for each CPU mode (SVC, MON, ABT, ...) so that it's valid when the exception is taken. Of course, if the stack isn't actually used, this may not be relevant.

Also, did you set up VBAR to point at your exception table, and enable whatever bit it is that causes the CPU to pull vectors from the location pointed at by VBAR rather than the HW default location.

You might want to look at some OSS low-level project for tips on CPU startup code and setting up exception vectors, such as U-Boot.

alexhoppus
Posts: 10
Joined: Sat Feb 13, 2016 9:04 am

Re: Vector table init at rpi2

Wed Mar 02, 2016 11:03 am

I have done the following things:
1.) Set up stacks for every mode
2.) Initialized VBAR register to point to 0x0
3.) Insert a one char printing from exception handler directly to uart port
4.) I have looked into u-boot source early init and stole 1-3 things from there.

Also i have mentioned that it starts in HYP mode, anyway further i switch it to SVC.

Still nothing. Please, if somebody can help me with that here is the reference code in the current state
https://github.com/alexhoppus/rpios/blo ... r/main.cpp
https://github.com/alexhoppus/rpios/blo ... der/boot.S

dradford
Posts: 18
Joined: Mon Feb 15, 2016 3:33 pm

Re: Vector table init at rpi2

Wed Mar 02, 2016 11:07 am

I wouldn't mess with SCTLR, use the VBAR registers instead. They are set to 0 on boot, so they should be fine. There will be 3/4 you need to program: one for secure PL1, one for non-secure PL1, one for monitor mode, and one for hypervisor mode.

The ARM boots in secure SVC mode. On a Pi1 your kernel will be entered in this state, with interrupts and cache disabled. However, for some reason I don't rightly understand, on a Pi2 the bootloader switches to non-secure HYP before starting. (It does, however, do something to send cores 1-3 into an infinite loop until they are sent a wake-up message - I haven't looked into this yet.) This is handled by the small block of code it inserts at address 0 before it sets the ARM running. You may be overwriting that, so that's something to check.

There are multiple vector tables, and the table used depends on the target mode and security state. There are all sorts of control settings that let you alter which mode will be switched to in various circumstances, and it all gets a bit complicated, but the default is something like this:
- if an exception happens while you are in secure state, and the target mode is not MON or HYP, then it jumps through the secure PL1 vector table, and arrives in a secure PL1 mode.
- if an exception happens while you are in a non-secure state, and the target mode is not MON or HYP, then it jumps through the non-secure PL1 vector table, and arrives in a non-secure PL1 mode.
- if an exception goes to MON mode (ie. the SMC instruction, which only works from a PL1 mode), then it jumps through the monitor-mode vector table
- exceptions going to HYP mode (maybe also exceptions while *in* HYP mode, I can't remember off-hand) use the hypervisor vector table (eg. the SVC instruction) [I've not looked much at this - digging into Pi2 is on my to-do list.]

Pi1 doesn't have the virtualisation extension, so there's no hypervisor, and only 3 vector tables. Pi2 has a hypervisor and 4 vector tables. But the addresses are all set to 0 on a reset, so that shouldn't be a problem.

As someone else mentioned, make sure you have a stack set up if your exception handler requires one. But importantly, make sure it has a stack set up *for that mode*!! So SVC calls will require an SVC-mode stack set up; interrupts will require an IRQ-mode stack set up, etc. They'll need to be separate stacks as well, as each mode has its own r13. Your branch will not be switching to the correct mode, of course, but for your test code it won't matter.

Not 100% sure from context that the asm() is correct - the branch instruction is pc-relative so it will depend where it's actually executing. Try something like: "mov pc, #0x20" instead?

I've recently been messing with exception handling stuff myself. I ended up writing a little crash monitor using a display-o-tron hat. Whenever the pi crashes, I can view the registers, mode, irq state and so on. (Eventually I want to be able to examine memory too!) It's a real boon if you're not using jtag.

dradford
Posts: 18
Joined: Mon Feb 15, 2016 3:33 pm

Re: Vector table init at rpi2

Wed Mar 02, 2016 11:09 am

Sorry, I seem to have taken so long to write that that it's already out-of-date ;)

dradford
Posts: 18
Joined: Mon Feb 15, 2016 3:33 pm

Re: Vector table init at rpi2

Wed Mar 02, 2016 11:28 am

Insert ".align 2" before the "uart_port:" label? It looks like it would be an unaligned load, which by default is a data abort (on pi1 anyway).

dradford
Posts: 18
Joined: Mon Feb 15, 2016 3:33 pm

Re: Vector table init at rpi2

Wed Mar 02, 2016 11:38 am

Actually, why would you want to b 0x20 anyway? There's no instruction there, just data.

alexhoppus
Posts: 10
Joined: Sat Feb 13, 2016 9:04 am

Re: Vector table init at rpi2

Wed Mar 02, 2016 12:01 pm

That is not so obvious way of generating undefinstr exception. What i want to see is printing from exception_handler. I should make a comment about that.

dradford
Posts: 18
Joined: Mon Feb 15, 2016 3:33 pm

Re: Vector table init at rpi2

Wed Mar 02, 2016 12:12 pm

Ah, I get you now. But surely 0x00008040 is a defined instruction? ANDEQ.

Try asm(".word 0xe0700000") instead of the branch. I think that's an undefined mul on cortex-a7. I'll have to wait till I get home to double-check the one I normally use.

alexhoppus
Posts: 10
Joined: Sat Feb 13, 2016 9:04 am

Re: Vector table init at rpi2

Wed Mar 02, 2016 1:20 pm

Tried different variants including the one used in BUG()
http://lxr.free-electrons.com/source/ar ... /bug.h#L17
The undefinstr is happened (or at least some kind of exception is happened) bcause i can't see further printing

dwelch67
Posts: 967
Joined: Sat May 26, 2012 5:32 pm

Re: Vector table init at rpi2

Wed Mar 02, 2016 2:19 pm

I didnt fix the mmu stuff yet but reading the posts here, have some comments. for the rpi2, you dont mess with the stacks for the various modes because you cant get to them, you are in hyp mode, different than the old days.

There are other threads in this forum about the changes in the code that is placed to boot the arm before it branches to 0x8000. The other three cores are waiting in a loop for a mailbox register to change, pretty sure they are all in hyp mode as well.

I dont think you can get at VBAR, but can get at HVBAR, which at the time I tried it was not set for us.

so from my blinker05 example (and now I see that I should have updated blinker06 and 07) we have to set the HVBAR, we dont care about the other modes stacks, and we cant use SUBS PC,LR with a non-zero number or some such rule.

A new develoment late 2015 is that the raspberry pi start.elf code now
puts the rpi 2 in HYP mode. The two changes I needed to make were
to set the HVBAR, might as well set it to 0x00008000 rather than copy
the vector table to 0x00000000. so the lines up front that copied
the vector table are now replaced with remapping.

mov r0,#0x8000
MCR p15, 4, r0, c12, c0, 0

The other change being you are supposed to return from hypervisor
exceptions using the eret instruction.

;@subs pc,lr,#4
eret

alexhoppus
Posts: 10
Joined: Sat Feb 13, 2016 9:04 am

Re: Vector table init at rpi2

Wed Mar 02, 2016 5:40 pm

I can get exceptions with this setup. thanks!

Code: Select all

mov sp, #0x8000
mov	r0, #0x8000
mcr	p15, 4, r0, c12, c0, 0	@Set HVBAR 
however if i try to do the same thing but for VBAR from the SVC mode it doesn't work.
i.e.:

Code: Select all

# Goto SVC mode
mrs	r0, cpsr
bic	r0, r0, #0x1f
orr	r0, r0, #SVC_MODE
msr	cpsr, r0
mov sp, #0x8000

mov	r0, #0x8000
mcr	p15, 0, r0, c12, c0, 0	@Set VBAR
Do you know what could be the reason?

dwelch67
Posts: 967
Joined: Sat May 26, 2012 5:32 pm

Re: Vector table init at rpi2

Wed Mar 02, 2016 11:13 pm

cause you are not in svc mode would be my guess. try going to svc mode then print out the mode you are in...

dradford
Posts: 18
Joined: Mon Feb 15, 2016 3:33 pm

Re: Vector table init at rpi2

Thu Mar 03, 2016 2:56 am

In that fragment there are 3 small gotchas:
1) You can't go to SVC mode directly from HYP. You need to ERET.
2) Setting an SVC stack won't help if the exception arrives in (say) UND (but I think you set up all the stacks earlier, so it doesn't matter).
3) VBAR is banked (secure and non-secure). Most exceptions will preserve the current security state, unless they occurred in MON mode or are going to MON or HYP. (But that shouldn't apply here.)

Try something like:

Code: Select all

# Goto SVC mode
mrs   r0, spsr // note: spsr not cpsr (spsr_hyp)
bic   r0, r0, #0x1f
orr   r0, r0, #SVC_MODE
msr   spsr, r0
mov r14, pc // (r14_hyp) - return to instruction after eret
eret
mov sp, #0x8000 // this will be r13_svc

mov   r0, #0x8000
mcr   p15, 0, r0, c12, c0, 0   @Set VBAR

swarren
Posts: 45
Joined: Tue Mar 01, 2016 5:56 am

Re: Vector table init at rpi2

Thu Mar 03, 2016 5:37 am

BTW, if you want the Pi2 to not start in HYP mode (but instead IIRC in secure SVC mode), you can add "kernel_old=1" to config.txt. kernel.img will then be loaded at address 0 rather than 0x8000 and the stub firmware won't be loaded/executed, so all 4 cores will jump into your code. You may need to do something to stop cores 1..3 doing anything much if you don't want them to all run your code in parallel.

dwelch67
Posts: 967
Joined: Sat May 26, 2012 5:32 pm

Re: Vector table init at rpi2

Fri Mar 04, 2016 2:14 am

I am struggling to get dradfords code to work to switch to svc. Anyone else have luck with that?

alexhoppus
Posts: 10
Joined: Sat Feb 13, 2016 9:04 am

Re: Vector table init at rpi2

Fri Mar 04, 2016 5:40 am

dwelch67 wrote:I am struggling to get dradfords code to work to switch to svc. Anyone else have luck with that?
The same thing. I thought for the first time that it is incorrect PC magic, and i jumping to wrong instruction, but it seems that there is something else. I don't know what happening concretely, but when i add eret to code flow at early init i can't see anything in console. Strange, because according to ARM Info Center this instruction performs very simple thing
When executed in Hyp mode, ERET loads the PC from ELR_hyp and loads the CPSR from SPSR_hyp.

xboot
Posts: 3
Joined: Wed Mar 02, 2016 2:30 am

Re: Vector table init at rpi2

Fri Mar 04, 2016 10:05 am

The same thing, how to change cpu running mode from hyp to svc?
https://github.com/xboot/xboot

dradford
Posts: 18
Joined: Mon Feb 15, 2016 3:33 pm

Re: Vector table init at rpi2

Fri Mar 04, 2016 11:40 am

I had to write it blind, so I may have got it wrong. I need to sort this out myself (properly), so I'll try and make some time to play with it at the weekend and let you know.

User avatar
Arjan
Posts: 265
Joined: Sat Sep 08, 2012 1:59 pm

Re: Vector table init at rpi2

Fri Mar 04, 2016 7:18 pm

This startup code https://github.com/vanvught/rpidmx512/b ... /vectors.s
works on all Model 1's and Model 2 with latest firmware.

Not yet tested with Model 3.
http://www.raspberrypi-dmx.org/
Open Source DMX/RDM/MIDI/OSC/Art-Net/sACN solutions

alexhoppus
Posts: 10
Joined: Sat Feb 13, 2016 9:04 am

Re: Vector table init at rpi2

Fri Mar 04, 2016 8:07 pm

Arjan wrote:This startup code https://github.com/vanvught/rpidmx512/b ... /vectors.s
works on all Model 1's and Model 2 with latest firmware.

Not yet tested with Model 3.
That works for me! Thanks. But still can't catch the intention of this (why raw instructions?)
.word 0xE12EF30E @ msr ELR_hyp, lr
.word 0xE160006E @ eret
Looks like this startup code and related things came from Linux code see safe_svcmode_maskall
https://github.com/torvalds/linux/blob/ ... ssembler.h
p.s.
it turned out that HYP mode have no banked LR register, instead it have ELR_hyp which could be accessed using msr instruction. So the previous code snippet dosen't work because of this

Code: Select all

mov r14, pc // (r14_hyp) - return to instruction after eret
should be

Code: Select all

msr     ELR_hyp, lr
Last edited by alexhoppus on Fri Mar 04, 2016 8:42 pm, edited 1 time in total.

User avatar
Arjan
Posts: 265
Joined: Sat Sep 08, 2012 1:59 pm

Re: Vector table init at rpi2

Fri Mar 04, 2016 8:40 pm

alexhoppus wrote:But still can't catch the intention of this (why raw instructions?)
.word 0xE12EF30E @ msr ELR_hyp, lr
.word 0xE160006E @ eret
The compiler does not recognize the msr and eret instructions. At least my (http://www.raspberrypi-dmx.com/raspberr ... nvironment) version of the gcc cross compiler does not recognize these instructions.
http://www.raspberrypi-dmx.org/
Open Source DMX/RDM/MIDI/OSC/Art-Net/sACN solutions

xboot
Posts: 3
Joined: Wed Mar 02, 2016 2:30 am

Re: Vector table init at rpi2

Sat Mar 05, 2016 8:08 am

Arjan wrote:
alexhoppus wrote:But still can't catch the intention of this (why raw instructions?)
.word 0xE12EF30E @ msr ELR_hyp, lr
.word 0xE160006E @ eret
The compiler does not recognize the msr and eret instructions. At least my (http://www.raspberrypi-dmx.com/raspberr ... nvironment) version of the gcc cross compiler does not recognize these instructions.
you can using this code to recognize these instructions

Code: Select all

.arch_extension sec
.arch_extension virt
https://github.com/xboot/xboot

User avatar
Arjan
Posts: 265
Joined: Sat Sep 08, 2012 1:59 pm

Re: Vector table init at rpi2

Sat Mar 05, 2016 12:00 pm

xboot wrote:

Code: Select all

.arch_extension sec
.arch_extension virt
Thank you!
http://www.raspberrypi-dmx.org/
Open Source DMX/RDM/MIDI/OSC/Art-Net/sACN solutions

Return to “Bare metal, Assembly language”