I've been trying to get a watchpoint to trigger, but no luck.
There should be 4 watchpoints accordíng to DBGDIDR, DBGDSCR=0x0204000e, so there shouldn't be any problems there?
I use (just in case) the cp14 interface - write DBGWVR0 and DBGWCR0 and read them back to see that the values went there.
Then I access the memory location, but nothing happens. Oh, and there are no masks in the CPSR set.
The program runs in non-secure SVC-mode.
Here's the watchpoint setting code:
void rpi2_set_watchpoint(unsigned int num, unsigned int addr, unsigned int control) { char scratchpad[9]; SYNC; volatile uint32_t *pval; pval = (volatile uint32_t *)(dbg_reg_base + 0x088); #if 0 // if memory-mapped interface works // 96-111 0x180-0x1BC DBGWVRm 4 watchpoint values // 112-127 0x1C0-0x1FC DBGWCRm 4 watchpoint controls uint32_t *pval, *pctrl; pval = (volatile uint32_t *)(dbg_reg_base + 0x180); pctrl = (volatile uint32_t *)(dbg_reg_base + 0x1c0); pval[num] = (uint32_t)addr; pctrl[num] = control; #else // have to use cp14 switch (num) { case 0: serial_raw_puts("\r\nwatch0!\r\n"); // write to DBGWVR0 asm volatile ("mcr p14, 0, %[val], c0, c0, 6\n\t" ::[val] "r" (addr) :); // write to DBGWCR0 asm volatile ("mcr p14, 0, %[ctl], c0, c0, 7\n\t" ::[ctl] "r" (control) :); // debug asm volatile ("mrc p14, 0, %[val], c0, c0, 6\n\t" :[val] "=r" (addr) ::); asm volatile ("mrc p14, 0, %[ctl], c0, c0, 7\n\t" :[ctl] "=r" (control) ::); serial_raw_puts("DBGWVR0: "); util_word_to_hex(scratchpad, addr); serial_raw_puts(scratchpad); serial_raw_puts(" DBGWCR0: "); util_word_to_hex(scratchpad, control); serial_raw_puts(scratchpad); serial_raw_puts(" DBGDSCR: "); util_word_to_hex(scratchpad, *pval); serial_raw_puts(scratchpad); serial_raw_puts("\r\n"); break; case 1: serial_raw_puts("\r\nwatch1!\r\n"); // write to DBGWVR1 asm volatile ("mcr p14, 0, %[val], c0, c1, 6\n\t" ::[val] "r" (addr) :); // write to DBGWCR1 asm volatile ("mcr p14, 0, %[ctl], c0, c1, 7\n\t" ::[ctl] "r" (control) :); break; case 2: serial_raw_puts("\r\nwatch2!\r\n"); // write to DBGWVR2 asm volatile ("mcr p14, 0, %[val], c0, c2, 6\n\t" ::[val] "r" (addr) :); // write to DBGWCR2 asm volatile ("mcr p14, 0, %[ctl], c0, c2, 7\n\t" ::[ctl] "r" (control) :); break; case 3: serial_raw_puts("\r\nwatch3!\r\n"); // write to DBGWVR3 asm volatile ("mcr p14, 0, %[val], c0, c3, 6\n\t" ::[val] "r" (addr) :); // write to DBGWCR3 asm volatile ("mcr p14, 0, %[ctl], c0, c3, 7\n\t" ::[ctl] "r" (control) :); break; default: serial_raw_puts("\r\nwatch?!\r\n"); // do nothing; break; } #endif SYNC; }
The machine is Raspberry Pi 2B if that helps.
The output from the function (through dgb):
w \x00](gdb) watch g_testloc
Sending packet: $m8360,4#9e...[\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][
r +]Ack
[$][7][0][8][3][0][0][0][0][#][9][2]Packet received: 70830000
[
w \x00]Sending packet: $m8360,4#9e...[\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][
w \x00]Hardware watchpoint 1: g_testloc
(gdb) cont
Continuing.
w \x00]Sending packet: $Z2,8360,4#e9...[\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][
[\r][\n][w][a][t][c][h][ ][n][u][m][=][ ][0][0][0][0][0][0][0][0][ ][v][a][l][=][0][0][0][0][8][3][6][0][ ][c][t][r][l][0][0][0][0][2][1][f][7][\r][\n][\r][\n][w][a][t][c][h][0][!][\r][\n][D][B][G][W][V][R][0][:][ ][0][0][0][0][8][3][6][0][ ][D][B][G][W][C][R][0][:][ ][0][0][0][0][2][1][f][7][ ][D][B][G][D][S][C][R][:][ ][0][2][0][4][0][0][0][e][\r][\n][$][O][K][#][9][a]Packet received: OK
w \x00]Packet Z2 (write-watchpoint) is supported
Sending packet: $vCont?#49...[\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][\x00][
[$][#][0][0]Packet received:
The address of g_testloc is indeed 0x8360
Disassembly of section .bss:
00008360 <g_testloc>:
8360: 00000000 andeq r0, r0, r0
The memory mapped interface didn't work any better.
I found this in Linux sources:
/** In order to access the breakpoint/watchpoint control registers,* we must be running in debug monitor mode. Unfortunately, we can* be put into halting debug mode at any time by an external debugger* but there is nothing we can do to prevent that.*/
/*
* In order to access the breakpoint/watchpoint control registers,
* we must be running in debug monitor mode. Unfortunately, we can
* be put into halting debug mode at any time by an external debugger
* but there is nothing we can do to prevent that.
*/
Is that some Linux-specific thing (depending on the way things are handled in Linux), or general fact?
I haven't found anything like this in the documents.
I mean that the breakpoint/watchpoint registers must be set in debug monitor mode?
I started reading about debug modes instead of debug events, and...
Is it so that HW breakpoints and watchpoints generate debug events, and (invasive) debug mode must be enabled to 'catch' the debug events? And bkpts have worked without any debug mode because bkpt causes both debug event and PABT exception, and it's the 'PABT exception part' that has been working?
And if so, what kind of restrictions does invasive debug monitor mode introduce (if any) compared to the situation with both debug modes disabled?
Did some more searching and reading...
DBGEN The Debug Enable signal enables invasive debug
Is it so that HW breakpoints and watchpoints can only be used with an external debug POD?
And only bkpt instruction works without it?
There seems to be a possibility that the DBGEN can be changed by program if such register is implemented. I was wondering if there is a way to alter it via DCC registers?
False alarm: DBGAUTHSTATUS = 0xff.
DBGEN is high and invasive and non-invasibe secure and non-secure debug is enabled.
So what the heck is wrong?
The problem is solved. It was the OS lock.
Both double lock and dbg lock were clear.