Now that the funny PABT-behaviour is found to be (probably) caused ny debug state, I'd like to exit debug state before return from PABT exception. The ARM v7-A/R ARM says that I should write RRQ to DBGDRCR, but it seems that in Cortex-A7 it's not accessible via CP14.
It should be accessible via memory-mapped registers, and the manual gives the offset, but offset from what?
I understood that the register offset is the register number multiplied by four, so for DBGDRCR the offset would be 36*4 = 144 (0x90).
In the TRM it says:
Table 10-26 Address mapping for debug trace components Address range Componenta 0x00000 - 0x00FFF ROM table 0x01000 - 0x0FFFF Reserved 0x10000 - 0x10FFF CPU 0 Debug 0x11000 - 0x11FFF CPU 0 PMU 0x12000 - 0x12FFF CPU 1 Debug 0x13000 - 0x13FFF CPU 1 PMU 0x14000 - 0x14FFF CPU 2 Debug 0x15000 - 0x15FFF CPU 2 PMU 0x16000 - 0x16FFF CPU 3 debug
Table 10-26 Address mapping for debug trace components
Address range Componenta
0x00000 - 0x00FFF ROM table
0x01000 - 0x0FFFF Reserved
0x10000 - 0x10FFF CPU 0 Debug
0x11000 - 0x11FFF CPU 0 PMU
0x12000 - 0x12FFF CPU 1 Debug
0x13000 - 0x13FFF CPU 1 PMU
0x14000 - 0x14FFF CPU 2 Debug
0x15000 - 0x15FFF CPU 2 PMU
0x16000 - 0x16FFF CPU 3 debug
Are these too offsets from somewhere, or absolute addresses?
Do I write to DBGDRCR by just writing the value into address 0x100090 (core 0, assuming not locked)?
Or do I need to calculate the register address from the contents of DBGDRAR?
And what's the ROM table?
Hello,
It is the offsets from somewhere.
The base address is product specific.
You seem to use Raspberry Pi2.
As I don't have Raspberry Pi2, I don't know it.
According to the searching results, it seems to be 0x80000000.
But I'm not sure.
Best regards,
Yasuhiko Koumoto.
Thanks. I started hunting for the info, and found out that the thing should start with reading the DBGDRAR (Debug ROM Address Register) then
Read the ROM Table entry for the component, and extract the Address offset for the component. The Address offset is bits [31:12] of the ROM Table entry
Read the ROM Table entry for the component, and extract the Address offset for the component. The Address
offset is bits [31:12] of the ROM Table entry
Now the thing is figuring out how to identify the right component. I haven't found any explanations of what kind of things are the 'components'. Is core 0 a component? And core 1 another component? How about peripherals? And Devices?
I guess I should find '0x9' (CoreSight compliant debug component) in the 'class'-field of component ID register of the right component?
And 'continuation code' (used as designer ID) 0x4 and identity code of 3B in the JEP-106 field of the 'conceptual 64-bit peripheral ID register'? And DBGDIDR version-field should be 0b0101 (ARMv7, v7.1 Debug architecture)?
Quite a mess just to exit the debug state.
Are there descriptions for other possible values in those fields and their meanings?
Ah, figured out the debug register accesses. Still can't tell from the ROM table and ID registers, which component is the right one.
(I know it's the first component, though.)
And I still don't seem to be able to return from the BKPT (added some debug about the components, unlocked the registers and wrote the RRQ-bit to exit debug state).
Not much better?
PIDR is actually a word formed from the lowest bytes of PIDR 3-0.
Finally! Got into main() DBGDRAR: 40020003 DBGDSAR: 40030003 DBGLSR: 00000003 DBGLSR2: 00000001 comp: 00000000 : 00010003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bbc07 comp: 00000001 : 00011003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bb9a7 comp: 00000002 : 00012003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bbc07 comp: 00000003 : 00013003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bb9a7 comp: 00000004 : 00014003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bbc07 comp: 00000005 : 00015003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bb9a7 comp: 00000006 : 00016003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bbc07 comp: 00000007 : 00017003 CIDR1: 00000090 PIDR5: 00000004 PIDR: 005bb9a7 comp: 00000008 : 00000000 trying SVC SVC EXCEPTION exc_addr: 000003e8 SPSR: 68000013 returned from SVC trying BKPT1 PABT EXCEPTION exc_addr: 000090d4 SPSR: 60000013 my_cpsr: 60000197 dbgdscr: 0204000e IFSR: 00000002 dbgdscr2: 0204000e i: 00000000returned UNDEFINED EXCEPTION exc_addr: 00900008 SPSR: 600103d3
Finally! Got into main()
DBGDRAR: 40020003 DBGDSAR: 40030003 DBGLSR: 00000003 DBGLSR2: 00000001
comp: 00000000 : 00010003
CIDR1: 00000090
PIDR5: 00000004
PIDR: 005bbc07
comp: 00000001 : 00011003
PIDR: 005bb9a7
comp: 00000002 : 00012003
comp: 00000003 : 00013003
comp: 00000004 : 00014003
comp: 00000005 : 00015003
comp: 00000006 : 00016003
comp: 00000007 : 00017003
comp: 00000008 : 00000000
trying SVC
SVC EXCEPTION
exc_addr: 000003e8
SPSR: 68000013
returned from SVC
trying BKPT1
PABT EXCEPTION
exc_addr: 000090d4
SPSR: 60000013
my_cpsr: 60000197
dbgdscr: 0204000e
IFSR: 00000002
dbgdscr2: 0204000e
i: 00000000returned
UNDEFINED EXCEPTION
exc_addr: 00900008
SPSR: 600103d3
Looks like it returned from PABT, but made an UNDEFINED exception right after, and the address is, to put it mildly, weird.
The mode was, however, SVC again, before the UNDEFINED EXCEPTION, and it didn't restart.
I haven't changed anything in the main below the first SVC. Added the component info dump before it, though.
Before this "debug circus" I found out that adding 3 debug prints in the PABT handler made it return fine, but removing any of them, caused different weird return problems depending on which print I removed.
I guess I'll try again with all this plus the debug prints.
My head hurts...
[EDIT]
With the debug prints, it booted 3 times and jammed.
This time the first time the exceptions were entered from SVC-mode (as expected), but the second time from FIQ (I don't have it in use) and the 3rd time from IRQ.
IFSR was 2 => the cause was BKPT.
[/EDIT]
[EDIT2]
Added some more debug, and seems like it's getting even more weird. The reboot seems to take place a more or less random time after returning from the PABT.
Also after restart the mode seems to be about random.
trying SVC SVC EXCEPTION exc_addr: 000003e8 SPSR: 68000013 returned from SVC trying BKPT1 PABT EXCEPTION exc_addr: 000090f4 SPSR: 60000013 my_cpsr: 60000197 dbgdscr: 0204000e IFSR: 00000002 PABT done my_cpsr: 60000013 returned from BKPT1 Finally! Got into main() ... trying SVC SVC EXCEPTION exc_addr: 000003e8 SPSR: 6800001f returned from SVC trying BKPT1 PABT EXCEPTION exc_addr: 000090f4 SPSR: 6000001f my_cpsr: 60000197 dbgdscr: 0204000e IFSR: 00000002 PABT done my_cpsr: 6000001f returned from BKPT1 entering main
exc_addr: 000090f4
PABT done
my_cpsr: 60000013
returned from BKPT1
...
SPSR: 6800001f
SPSR: 6000001f
my_cpsr: 6000001f
entering main
and then nothing. The echoing doesn't work, and even the rest of the string is not printed (should be "entering main loop").
[/EDIT2]
Yeah. The PABT-problem is solved.
The debug state was not entered at all.
I realized that everything worked as long as I used the 'raw write', but as soon as I called the interrupt driven serial I/O, bad things happened.
And I found the cause: when the string has been written into the serial buffer, the tx interrupts are enabled and characters are read from the buffer and written into the tx FIFO (if it wasn't full) to put the ball rolling. It was done in serial_start_tx().
void serial_start_tx() { uint32_t cpsr_store; // no messing with tx interrupt cpsr_store = disable_save_ints(); // re-enable tx interrupts *((volatile uint32_t *)UART0_IMSC) |= (1<<5); (void) serial_tx(); // Clear transmit interrupt - probably not needed //*((volatile uint32_t *)UART0_ICR) = (1<<5); restore_ints(cpsr_store); }
To not mess up with the interrupts (simultaneous reading from the tx buffer by both serial_start_tx and tx interrupt) the IRQs were disabled before starting the transmission and restored after that, but there was a small bug in the restoring:
static inline uint32_t disable_save_ints() { uint32_t status; asm volatile ( "mrs %[var_reg], cpsr\n\t" "dsb\n\t" "cpsid aif\n\t" :[var_reg] "=r" (status):: ); return status; } static inline void restore_ints(uint32_t status) { asm volatile ( "msr cpsr_fsxc, %[var_reg]\n\t" :[var_reg] "=r" (status):: ); }
In the definition I promised that the restote_ints() doesn't return anything...
This solved the problem:
static inline void restore_ints(uint32_t status) { asm volatile ( "msr cpsr_fsxc, %[var_reg]\n\t" ::[var_reg] "r" (status): ); }
The good news is that while debugging the problem, I learned A LOT about the debug HW!
Congratulations on finding this bug. Such bugs are really annoying.
I can recognize this situation; I've been there a lot of times:
The Debuging-code contains error.
-I do not know why this happens so often (probably more often than errors in the actual code); perhaps because the debugging code is usually written (too) quickly ?
My best advice is to keep debug code simple; but of course it won't be any guarantee against bugs.
I think it's because when something simple doesn't seem to work, you just add little something to check... and that's when such bugs get introduced...
Mine was obviously a copy-paste - didn't pay too much attention... and it bit me.