Skip to content

Instantly share code, notes, and snippets.

@tonosaman
Last active April 27, 2023 14:01
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonosaman/62a31e7991a41edb19c5 to your computer and use it in GitHub Desktop.
Save tonosaman/62a31e7991a41edb19c5 to your computer and use it in GitHub Desktop.
Olimex ARM-USB-OCD-H / openocd-0.9.0 / libftd2xx1.1.12 / Raspberry Pi 2 / Ubuntu 15.04

for RPi2 JTAG debugging with Olimex ARM-USB-OCD-H

System constitution

  • probe device: Olimex ARM-USB-OCD-H
  • target device: Raspberry Pi 2
    • files for booting: bootcode.bin, start.elf, config.txt from here
    • jtag target image armjtag.bin: from here
    • config.txt: edit to add a line kernel=armjtag.bin
  • host machine: Ubuntu 15.04
    • openocd-0.9.0 as debugger host:
      • probe device driver: libftd2xx1.1.12
      • probe device configuration: olimex-arm-usb-ocd-h.cfg (@see below)
      • target device configuration: openocd-rpi2.cfg (@see below)
    • debug client: telnet or gdb
  • pin assign between Olimex ARM-USB-OCD-H and Raspberry Pi 2

Setup FTDI proprietary D2XX driver

This method is obsolete. By openocd warning message, you should use libftdi.

locate libftd2xx.a libftd2xx.so.1.1.12

  • download FTDI proprietary D2XX driver for linux from here
  • installation guide is here
  • extract to ./libftd2xx1.1.12/
  • (optional) locate libraries to /usr/local/lib/
sudo cp libftd2xx1.1.12/build/x86_64/libftd2xx.a /usr/local/lib/
sudo cp libftd2xx1.1.12/build/x86_64/libtd2xx.so.1.1.12 /usr/local/lib/
sudo ln -s /usr/local/lib/libtd2xx.so.1.1.12 /usr/local/lib/libftd2xx.so
sudo chmod 0755 /usr/local/lib/libtd2xx.so.1.1.12

Build OpenOCD

Download "openocd-0.9.0 release" from here

extract to ./openocd-0.9.0

configure options

$ cd openocd-0.9.0
$ ./configure --enable-maintainer-mode --enable-legacy-ft2232_ftd2xx --with-ftd2xx-lib=static --with-ftd2xx-linux-tardir=../libftd2xx1.1.12

Add ld linkage to libpthread

--- src/Makefile.org	2015-07-16 17:51:11.333497970 +0900
+++ src/Makefile	2015-07-16 17:52:06.797236301 +0900
@@ -275,11 +275,11 @@
 INSTALL_SCRIPT = ${INSTALL}
 INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
 LD = /usr/bin/ld -m elf_x86_64
-LDFLAGS =  -L/home/tono/OpenOCD/libftd2xx1.1.12/build/x86_64
+LDFLAGS =  -L/home/tono/OpenOCD/libftd2xx1.1.12/build/x86_64 -L/lib64
 LIBFTDI_CFLAGS = 
 LIBFTDI_LIBS = 
 LIBOBJS = 
-LIBS = -lftd2xx -lrt -ldl 
+LIBS = -lftd2xx -lrt -ldl -lpthread
 LIBTOOL = $(SHELL) $(top_builddir)/libtool
 LIBTOOL_DEPS = ./ltmain.sh
 LIBUSB0_CFLAGS = 

make

$ ldd openocd-0.9.0/src/openocd
	linux-vdso.so.1 =>  (0x00007ffc599bc000)
	libusb-0.1.so.4 => /lib/x86_64-linux-gnu/libusb-0.1.so.4 (0x00007f5dace03000)
	libusb-1.0.so.0 => /lib/x86_64-linux-gnu/libusb-1.0.so.0 (0x00007f5dacbeb000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5dac8e3000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5dac6df000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5dac4c1000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5dac0f7000)
	libudev.so.1 => /lib/x86_64-linux-gnu/libudev.so.1 (0x00007f5dabee4000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5dad00c000)

Paste to olimex-arm-usb-ocd-h.cfg : Configuretion file for openocd 1 of 2

# Olimex ARM-USB-OCD-H
# http://www.olimex.com/dev/arm-usb-ocd-h.html
interface ft2232
ft2232_device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H"
ft2232_layout olimex-jtag
ft2232_vid_pid 0x15ba 0x002b

Paste to openocd-rpi2.cfg : Configuretion file for openocd 2 of 2

from here Thanks jitomesky! I bought your book!

# ref: http://www.raspberrypi.org/forums/viewtopic.php?f=72&t=100268
#    : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0464f/ch10s06s01.html
 
adapter_khz 1000
adapter_nsrst_delay 400
reset_config none

gdb_breakpoint_override hard

if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME rpi2
}
 
#
# Main DAP
#
if { [info exists DAP_TAPID] } {
   set _DAP_TAPID $DAP_TAPID
} else {
   set _DAP_TAPID 0x4ba00477
}
jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0xf -expected-id $_DAP_TAPID
 
set _TARGETNAME $_CHIPNAME.cpu.0
target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap -coreid 0 -dbgbase 0x80010000
set _TARGETNAME $_CHIPNAME.cpu.1
target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap -coreid 1 -dbgbase 0x80012000
set _TARGETNAME $_CHIPNAME.cpu.2
target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap -coreid 2 -dbgbase 0x80014000
set _TARGETNAME $_CHIPNAME.cpu.3
target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap -coreid 3 -dbgbase 0x80016000
 
$_TARGETNAME configure -event reset-assert-post "cortex_a dbginit"
 
$_TARGETNAME configure -event gdb-attach { halt }

Run openocd

$ rmmod ftdi_sio usbserial
$ sudo src/openocd -f olimex-arm-usb-ocd-h.cfg -f openocd-rpi2.cfg 
[sudo] password for tono: 
Open On-Chip Debugger 0.9.0 (2015-07-16-17:40)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
adapter speed: 1000 kHz
adapter_nsrst_delay: 400
none separate
Warn : Using DEPRECATED interface driver 'ft2232'
Info : Consider using the 'ftdi' interface driver, with configuration files in interface/ftdi/...
Info : device: 6 "2232H"
Info : deviceID: 364511275
Info : SerialNumber: OLYPBH2QA
Info : Description: Olimex OpenOCD JTAG ARM-USB-OCD-H A
Info : max TCK change to: 30000 kHz
Info : clock speed 1000 kHz
Info : JTAG tap: rpi2.dap tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
Info : rpi2.cpu.0: hardware has 6 breakpoints, 4 watchpoints
Info : rpi2.cpu.1: hardware has 6 breakpoints, 4 watchpoints
Info : rpi2.cpu.2: hardware has 6 breakpoints, 4 watchpoints
Info : rpi2.cpu.3: hardware has 6 breakpoints, 4 watchpoints

Now connection established, you can see the brinking LED on top of ARM-USB-OCD-H.

connect to openocd server

open another terminal

$ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt                  
ttbcr 0ttbr0 ca5eaa5attbr1 fd7c7f73
rpi2.cpu.3 rev 5, partnum c07, arch f, variant 0, implementor 41
number of cache level 2
cache l2 present :not supported
rpi2.cpu.3 cluster f core 3 multi core
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x000000c4
MMU: disabled, D-Cache: disabled, I-Cache: disabled

connect to openocd server with using gdb

Download gcc-arm-none-eabi-4_9-2015q1-20150306-linux.tar.bz2 or later from here .

@tonosaman
Copy link
Author

JTAG hook HYP mode on RPi-2

BOOT/armjtag.hyp

Download special bootcode bcm2836-raspi2-bootblk.bin.ift from here and concatenate .

$ cat bcm2836-raspi2-bootblk.bin.ift armjtag.bin > armjtag.hyp

BOOT/config.txt

kernel_old=1
kernel=armjtag.hyp

Boot RPi-2

Run OpenOCD

Connect to openocd server

% telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> targets rpi2.cpu.0
> halt
invalid mode value encountered 26
ttbcr 0ttbr0 5637fb7bttbr1 fa7e707a
rpi2.cpu.0 rev 5, partnum c07, arch f, variant 0, implementor 41
number of cache level 2
cache l2 present :not supported
rpi2.cpu.0 cluster f core 0 multi core
target state: halted
unrecognized psr mode: 0x1a
target halted in ARM state due to debug-request, current mode: UNRECOGNIZED
cpsr: 0x800001da pc: 0x000080d8
MMU: disabled, D-Cache: disabled, I-Cache: disabled

cpsr: 0x600001da ... Mode field(bits [4:0]) indicates that we are in HYP(0b11010).

umm... openocd-0.9 does not recognize Hypervisor mode of Cortex-A7 MPCore architecture correctly.

Research for rebuilding OpenOCD

About details, refer to the "How to enable debugging in HYP-mode" described below comment.

Research about bootstrap code for HYP

Enable HYP mode on RPi-2 when booting #369

bootcode.bin is the GPU bootcode - nothing to do with the arm startup code.
The arm boot code we use is here and you can easily use kernel_old=1 and prepend your own bootcode to the kernel if you want to change it.

By default we insert some startup code at address 0x0 - 0xff, which comes from here.
This does switch to non-secure monitor mode, which is required to write to CNTVOFF.

For bare metal I'd have thought you'd want to avoid our startup code (with kernel_old=1) and start your kernel from 0x0.

Cortex-A7 initialization code & TrustZone/ Secure Boot @ AMR Connected Community

original boot code if a line of kernel_old=1 is not described in config.txt

#define CPUID_ARM_VIRT_SHIFT        12
#define CPUID_ARM_VIRT_MASK     (0xF << CPUID_ARM_VIRT_SHIFT)
#define CPUID_ARM_GENTIMER_SHIFT    16
#define CPUID_ARM_GENTIMER_MASK     (0xF << CPUID_ARM_GENTIMER_SHIFT)

#define BCM2708_PERI_BASE 0x3f000000

.arch_extension sec
.arch_extension virt

.section .init
.globl _start
/* the vector table for secure state and HYP mode */
_start:
    b jmp_loader    /* reset */
    .word 0 /* undef */
    adr pc, _secure_monitor
    .word 0
    .word 0
    .word 0
    .word 0
    .word 0

/*
 * secure monitor handler
 * U-boot calls this "software interrupt" in start.S
 * This is executed on a "smc" instruction, we use a "smc #0" to switch
 * to non-secure state.
 * We use only r0 and r1 here, due to constraints in the caller.
 * @see [4.3.33. Secure Configuration Register](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0464f/BABGIHHJ.html)
 */
_secure_monitor:
    mrc p15, 0, r1, c1, c1, 0       @ read SCR
    bic r1, r1, #0x4e           @ clear IRQ, FIQ, EA, nET bits
    orr r1, r1, #0x31           @ enable NS, AW, FW bits

    @mrc    p15, 0, r0, c0, c1, 1       @ read ID_PFR1
    @and    r0, r0, #CPUID_ARM_VIRT_MASK    @ mask virtualization bits
    @cmp    r0, #(1 << CPUID_ARM_VIRT_SHIFT)
    orr r1, r1, #0x100          @ allow HVC instruction

    mcr p15, 0, r1, c1, c1, 0       @ write SCR (with NS bit set)

    mrc p15, 0, r0, c12, c0, 1      @ get MVBAR value
    mcr p15, 4, r0, c12, c0, 0      @ write HVBAR

    @ Reset CNTVOFF to 0 before leaving monitor mode
    mov r0, #0
    mcrr    p15, 4, r0, r0, c14     @ Reset CNTVOFF to zero
1:
    movs    pc, lr              @ return to non-secure SVC

jmp_loader:
@ Check which proc we are and run proc 0 only

    mrc p15, 0, r0, c1, c0, 0 @ Read System Control Register
    orr r0, r0, #(1<<2)       @ cache enable
    orr r0, r0, #(1<<12)      @ icache enable
    mcr p15, 0, r0, c1, c0, 0 @ Write System Control Register

    mrc p15, 0, r0, c1, c0, 1 @ Read Auxiliary Control Register
    orr r0, r0, #(1<<6)       @ SMP
    mcr p15, 0, r0, c1, c0, 1 @ Write Auxiliary Control Register

    mov r0, #1
    mcr p15, 0, r0, c14, c3, 1 @ CNTV_CTL (enable=1, imask=0)

@ set to non-sec
    movw    r1, #0x3fff
    movt    r1, #0x0006
    mcr p15, 0, r1, c1, c1, 2       @ NSACR = all copros to non-sec
@ timer frequency
    ldr r1, =19200000
    mcr p15, 0, r1, c14, c0, 0      @ write CNTFRQ

    adr r1, _start
    mcr p15, 0, r1, c12, c0, 1      @ set MVBAR to secure vectors
    mrc p15, 0, ip, c12, c0, 0      @ save secure copy of VBAR

    isb
    smc #0              @ call into MONITOR mode

    mcr p15, 0, ip, c12, c0, 0      @ write non-secure copy of VBAR

    mov r4, #0x8000
    mrc     p15, 0, r0, c0, c0, 5
    ubfx    r0, r0, #0, #2
    cmp     r0, #0
    beq     9f

    cmp     r0, #0xff
    bge 10f

    ldr r5, =0x4000008C     @ mbox
    ldr r3, =0x00000000     @ magic
    str r3, [r5, r0, lsl #4]

    ldr r5, =0x400000CC     @ mbox
1:
    ldr r4, [r5, r0, lsl #4]
    cmp r4, r3
    beq 1b

@ clear mailbox
    str r4, [r5, r0, lsl #4]

9:
    @ldr    r5, = (BCM2708_PERI_BASE + 0x300c)      @ stc0
    @ldr    r6, = 0xaff0aff0
    @str    r4, [r5, r0, lsl #2]


@   msr     cpsr_fsxc, #0xd3
    mov r0, #0
    ldr r1, =3138       @ BCM2708 machine id
    ldr r2, =0x100      @ ATAGS
    bx  r4
10:
    wfi
    b   10b

xvisor-next/docs/arm/bcm2836-raspi2-bootblk.bin.ift

$ gcc-linaro-arm-linux-gnueabihf-4.8-2014.04_linux/bin/arm-linux-gnueabihf-objdump \
    -D -b binary -marm xvisor-next/docs/arm/bcm2836-raspi2-bootblk.bin.ift 
/* the vector table for secure state and HYP mode */
_start:
       0:       ea000011        b       0x4c  /* b jmp_loader   @ reset */
       4:       00000000
       8:       e28ff010        add     pc, pc, #16  /* adr pc, _secure_monitor */
       c:       00000000
      10:       00000000
      14:       00000000
      18:       00000000
      1c:       00000000
/*
 * secure monitor handler
 * U-boot calls this "software interrupt" in start.S
 * This is executed on a "smc" instruction, we use a "smc #0" to switch
 * to non-secure state.
 * We use only r0 and r1 here, due to constraints in the caller.
 */
_secure_monitor:
      20:       ee111f11        mrc     15, 0, r1, cr1, cr1, {0}    @ read SCR
      24:       e3c1104e        bic     r1, r1, #78     ; 0x4e    @ clear IRQ, FIQ, EA, nET bits
      28:       e3811031        orr     r1, r1, #49     ; 0x31    @ enable NS, AW, FW bits
      2c:       e3811c01        orr     r1, r1, #256    ; 0x100  @ allow HVC instruction
      30:       ee011f11        mcr     15, 0, r1, cr1, cr1, {0}  @ write SCR (with NS bit set)
/* DDI0406BJ_arm_architecture_reference_manual.pdf pp.1160 "Format of the CPSR and SPSRs"
 * E, bit [9] ... 0(Little endian operation)
 * A, bit [8] ... 1(Exception disabled) Asynchronous abort disable bit. Used to mask asynchronous aborts.
 * I, bit [7] ... 1(Exception disabled) Interrupt disable bit. Used to mask IRQ interrupts.
 * F, bit [6] ... 1(Exception disabled) Fast interrupt disable bit. Used to mask FIQ interrupts.
 * T, bit [5] ... 0(Not Thumb) Thumb execution state bit.
 * M[4:0], bits [4:0] ... 0b11010(HYP) Mode field. [ARMv7-A Processor mode](http://infocenter.arm.com/help/topic/com.arm.doc.dui0473kj/dom1359731126962_00007.html)
 */
      34:       e3a00d07        mov     r0, #448        ; 0x1c0
      38:       e380001a        orr     r0, r0, #26    ; 0x1a (0b11010) @ HYP mode
      3c:       e16ff000        msr     SPSR_fsxc, r0
@ Reset CNTVOFF to 0 before leaving monitor mode
      40:       e3a00000        mov     r0, #0
      44:       ec400f4e        mcrr    15, 4, r0, r0, cr14    @ Reset CNTVOFF to zero
      48:       e1b0f00e        movs    pc, lr    @ return to non-secure SVC

jmp_loader:
@ Check which proc we are and run proc 0 only

      4c:       ee110f10        mrc     15, 0, r0, cr1, cr0, {0}  @ Read System Control Register
      50:       e3800004        orr     r0, r0, #4       @ cache enable
      54:       e3800a01        orr     r0, r0, #4096   ; 0x1000 @ icache enable
      58:       ee010f10        mcr     15, 0, r0, cr1, cr0, {0}  @ Write System Control Register
      5c:       ee110f30        mrc     15, 0, r0, cr1, cr0, {1}  @ Read Auxiliary Control Register
      60:       e3800040        orr     r0, r0, #64     ; 0x40  @ SMP
      64:       ee010f30        mcr     15, 0, r0, cr1, cr0, {1}  @ Write Auxiliary Control Register
      68:       e3a00001        mov     r0, #1
      6c:       ee0e0f33        mcr     15, 0, r0, cr14, cr3, {1}  @ CNTV_CTL (enable=1, imask=0)
@ set to non-sec
      70:       e3031fff        movw    r1, #16383      ; 0x3fff
      74:       e3401006        movt    r1, #6
      78:       ee011f51        mcr     15, 0, r1, cr1, cr1, {2}  @ NSACR = all copros to non-sec
@ timer frequency
      7c:       e59f1068        ldr     r1, [pc, #104]  ; 0xec
      80:       ee0e1f10        mcr     15, 0, r1, cr14, cr0, {0}

      84:       e24f108c        sub     r1, pc, #140    ; 0x8c
      88:       ee0c1f30        mcr     15, 0, r1, cr12, cr0, {1}  @ set MVBAR to secure vectors
      8c:       ee1ccf10        mrc     15, 0, ip, cr12, cr0, {0}  @ save secure copy of VBAR

      90:       f57ff06f        isb     sy
      94:       e1600070        smc     0 @ call into MONITOR mode

      98:       ee0ccf10        mcr     15, 0, ip, cr12, cr0, {0} @ write non-secure copy of VBAR

      9c:       e3a04902        mov     r4, #32768      ; 0x8000
      a0:       ee100fb0        mrc     15, 0, r0, cr0, cr0, {5}  @ Read Multiprocessor Affinity Register
      a4:       e7e10050        ubfx    r0, r0, #0, #2 @ CPUID bits[1:0]
      a8:       e3500000        cmp     r0, #0
      ac:       0a000008        beq     0xd4
      b0:       e35000ff        cmp     r0, #255        ; 0xff  @ I think this should be 4, because Core x Mailbox 3's upper limit is 3.
      b4:       aa00000a        bge     0xe4
/* if CPUID > 0 && CPUID < 255 */
      b8:       e59f5030        ldr     r5, [pc, #48]   ; 0xf0
      bc:       e3a03000        mov     r3, #0
      c0:       e7853200        str     r3, [r5, r0, lsl #4]
      c4:       e59f5028        ldr     r5, [pc, #40]   ; 0xf4

      c8:       e7954200        ldr     r4, [r5, r0, lsl #4]
      cc:       e1540003        cmp     r4, r3
      d0:       0afffffc        beq     0xc8  @ Loop till Core [1-3] Mailbox 3 becomes non-zero 
                @ r4 = <<per CPU jump destination address>>
                @ xvisor expects to jump to <_start_secondary> or <_start_secondary_nopen>
/* if CPUID == 0 || (CPUID > 0 && CPUID < 255) */
      d4:       e3a00000        mov     r0, #0
      d8:       e59f1018        ldr     r1, [pc, #24]   ; 0xf8
      dc:       e3a02c01        mov     r2, #256        ; 0x100
      e0:       e12fff14        bx      r4
/* if CPUID >= 255 */ ** infinit loop **
      e4:       e320f003        wfi
      e8:       eafffffd        b       0xe4

      ec:       0124f800        ; #19200000
      f0:       4000008c  @ mbox
      f4:       400000cc  @ mbox
      f8:       00000c42
      fc:       00000001
     100:       00000003
     104:       00000002
        ...
     114:       00000164        andeq   r0, r0, r4, ror #2
        ...
     13c:       00010003        andeq   r0, r1, r3
     140:       00000001        andeq   r0, r0, r1
     144:       00000120        andeq   r0, r0, r0, lsr #2
     148:       00000000        andeq   r0, r0, r0
     14c:       00040000        andeq   r0, r4, r0
     150:       6d695f00        stclvs  15, cr5, [r9, #-0]
     154:       5f656761        svcpl   0x00656761
     158:       616e6962        cmnvs   lr, r2, ror #18
     15c:       655f7972        ldrbvs  r7, [pc, #-2418]        ; 0xfffff7f2
     160:       ff00646e                        ; <UNDEFINED> instruction: 0xff00646e
     164:       00000004        andeq   r0, r0, r4
     168:       000000fc        strdeq  r0, [r0], -ip
     16c:       00000005        andeq   r0, r0, r5
     170:       00000150        andeq   r0, r0, r0, asr r1
     174:       00000006        andeq   r0, r0, r6
     178:       00000120        andeq   r0, r0, r0, lsr #2
     17c:       0000000a        andeq   r0, r0, sl
     180:       00000013        andeq   r0, r0, r3, lsl r0
     184:       0000000b        andeq   r0, r0, fp
     188:       00000010        andeq   r0, r0, r0, lsl r0
     18c:       00000015        andeq   r0, r0, r5, lsl r0
        ...
     1c4:       7273752f        rsbsvc  r7, r3, #197132288      ; 0xbc00000
     1c8:       62696c2f        rsbvs   r6, r9, #12032  ; 0x2f00
     1cc:       2e646c2f        cdpcs   12, 6, cr6, cr4, cr15, {1}
     1d0:       312e6f73        teqcc   lr, r3, ror pc
        ...

u-boot/arch/arm/cpu/armv7/nonsec_virt.S

Perhaps, special bootcode bcm2836-raspi2-bootblk.bin.ift has built from nonsec_virt.S .

@tonosaman
Copy link
Author

References for reading bcm2836-raspi2-bootblk.bin.ift

Title Holder
Cortex-A7 MPCore Technical Reference Manual Revision: r0p5 Online document
ARM Architecture Reference Manual® ARMv7-A and ARMv7-R edition DDI0406C_C_arm_architecture_reference_manual.pdf
ARM Quad A7 Core Rev 3.4, 18-08-2014 QA7_rev3.4.pdf
BCM2835 ARM Peripherals BCM2835-ARM-Peripherals.pdf

CNTVOFF

usecase

@ Reset CNTVOFF to 0 before leaving monitor mode
      40:       e3a00000        mov     r0, #0
      44:       ec400f4e        mcrr    15, 4, r0, r0, cr14    @ Reset CNTVOFF to zero

9.3. Timer programmers model > Table 9.1. System Timer registers > CNTVOFF

CRn Op1 CRm Op2 Name Reset behavior Width Description
c14 4 c14 1 CNTVOFF UNK 64-bit Counter Virtual Offset Register, see the ARM Architecture Reference Manual

B4.1.35 CNTVOFF, Virtual Offset register, VMSA (pp. B4-1547)


CNTV_CTL

usecase

68:       e3a00001        mov     r0, #1
6c:       ee0e0f33        mcr     15, 0, r0, cr14, cr3, {1}  @ CNTV_CTL (enable=1, imask=0)

9.3. Timer programmers model > Table 9.1. System Timer registers > CNTV_CTL

CRn Op1 CRm Op2 Name Reset behavior Width Description
c14 0 c3 1 CNTV_CTL The reset value for bit [0] is 0. 32-bit Counter PL1 Virtual Timer Control Register, see the ARM Architecture Reference Manual

NSACR

usecase

70:       e3031fff        movw    r1, #16383      ; 0x3fff
74:       e3401006        movt    r1, #6
78:       ee011f51        mcr     15, 0, r1, cr1, cr1, {2}  @ NSACR = all copros to non-sec

bits of r1 is 0b 0110.0011.1111.1111.1111.

4.2.2. c1 registers > NSACR

CRn Op1 CRm Op2 Name Reset behavior Description
c1 0 c1 2 NSACR The reset value depends on the FPU and NEON configuration. In BCM2836, FPU and Advanced SIMD are implemented, then the reset value is 0x00000000. Non-Secure Access Control Register

4.3.34. Non-Secure Access Control Register

  • Read/write in Secure PL1 modes.
Bits Name Val Function
[18] NS_SMP 1 = A write to ACTLR in Non-secure state can modify the value of the SMP bit. Other bits in the ACTLR are write-ignored. Determines if the SMP bit of the Auxiliary Control Register (ACTLR) is writable in Non-secure state:
[17] NS_L2ERR 1 = A write to L2ECTLR in Non-secure state can modify the value of the L2 AXI asynchronous error bit. Other bits in the L2ECTLR are write-ignored. NS_L2ERR Determines if the L2 AXI asynchronous error bit of the L2 Extended Control Register (L2ECTLR), are writable in Non-secure state:
[15] NSASEDIS 0 = A write to CPACR.ASEDIS in Non-secure state can modify that value. Disable Non-secure Advanced SIMD functionality
[14] NSD32DIS 0 = A write to CPACR.D32DIS in Non-secure state can modify that value. Disable the Non-secure use of D16-D31 of the VFP register file
[11] cp11 1 = Secure or Non-secure access to CPACR.cp11. Non-secure access to coprocessor 11 enable
[10] cp10 1 = Secure or Non-secure access to CPACR.cp11. Non-secure access to coprocessor 10 enable

Core [1-3] Mailbox 3

usecase

Core 1, 2 and 3 are wait till Mailbox 3 becomes non-zero.

      b8:       e59f5030        ldr     r5, =0x4000008C     @ Addr of Core 0 Mailbox 3 write-set (WO)
      bc:       e3a03000        mov     r3, #0  @ magic
      c0:       e7853200        str     r3, [r5, r0, lsl #4]  @ Set 0 to Core [1-3] Mailbox 3
      c4:       e59f5028        ldr     r5, =0x400000CC     @ Addr of Core 0 Mailbox 3 read & write-high-to-clear

      c8:       e7954200        ldr     r4, [r5, r0, lsl #4]  @ Read from Core [1-3] Mailbox 3
      cc:       e1540003        cmp     r4, r3
      d0:       0afffffc        beq     0xc8

@tonosaman
Copy link
Author

How to enable debugging in HYP-mode

Vanilla OpenOCD-0.9.0 failed to break

> targets rpi2.cpu.0
> halt
> load_image vmm.elf
1419164 bytes written at address 0x10000000
downloaded 1419164 bytes in 44.374302s (31.232 KiB/s)
> step 0x10000000
(...Timeout occured)

Can't break in HYP mode. (Supervisor is breakable. So, my JTAG architecture is works fine.)
What's wrong?

OpenOCD v0.9.0 (released at 2015-05-17)

$ git clone git://git.code.sf.net/p/openocd/code openocd-code
commit on is contained in v0.9.0?
arm_adi_v5: add Cortex-A7 peripheral IDs 2015-05-08 No
cortex_a: Add support for A7 MPCore 2015-01-10 Yes
History for
openocd/src/target/arm_adi_v5.c v0.9.0 master
openocd/src/target/cortex_a.c v0.9.0 master

I could not find useful information.
I have to learn more about breakpoint management under HYP.

10.4.6. Breakpoint Control Registers > DBGBCR

C11.11.2 DBGBCR, Breakpoint Control Registers (page C11-2233)

  • SC, bits[15:14], Implementation includes the Security Extensions

    Security state control. In an implementation that includes the Security Extensions, this field enables
    the breakpoint to be conditional on the security state of the processor.
    This field is used with the HMC, Hyp mode control, and PMC, Privileged mode control, fields. See
    Breakpoint state control fields on page C11-2217 for possible values.
    This field must be programmed to 0b00 if DBGBCR.BT is programmed for Linked Context match.
    If this is not done, the generation of debug events by this breakpoint is UNPREDICTABLE .

    Note

    When this field is set to a value other than 0b00 , the SSC field controls the processor security state
    in which the access matches, not the required security attribute of the access.
    See also Generation of debug events on page C3-2076.

  • HMC, bit[13], Implementation includes the Virtualization Extensions

    Hyp mode control bit.
    This field is used with the SSC, Security state control, and PMC, Privileged mode control, fields.
    See Breakpoint state control fields on page C11-2217 for possible values.
    This field must be programmed to 0 if DBGBCR.BT is programmed for Linked Context match. If
    this is not done, the generation of debug events by this breakpoint is UNPREDICTABLE .

  • PMC, bits[2:1], Privileged mode control.
    This field enables breakpoint matching conditional on the mode of the
    processor.
    This field is used with the SSC, Security state control, and HMC, Hyp mode control, fields. See
    Breakpoint state control fields on page C11-2217 for possible values.
    This field must be programmed to 0b11 if DBGBCR.BT is programmed for Linked Context match.
    If this is not done, the generation of debug events by this breakpoint is UNPREDICTABLE .

  • E, bit[0], Breakpoint enable.
    The meaning of this bit is: 1 = Breakpoint enabled.
    A breakpoint never generates debug events when it is disabled.

  • BAS, bits[8:5], Byte address select.
    This field enables match or mismatch comparisons on only certain bytes of the word address held in the DBGBVR.
    1111 ... Breakpoint programmed for Match by Hit

Table C11-15 Breakpoint state control

SSC, bits[15:14] HMC, bit[13] PMC, bits[2:1] Secure modes Non-secure modes
0b00 0b1 0b11 All modes All modes

value for DBGBCR to hit HYP

SSC, bits[15:14] HMC, bit[13] BAS, bits[8:5] PMC, bits[2:1] E, bits[0]
0b00 0b1 0b1111 0b11 0b1

0b 0010.0001.1110.0111 = 0x21E7

Table C11-5 Software debug event registers

Name Register number Offset rpi2.cpu0 rpi2.cpu1 rpi2.cpu2 rpi2.cpu3 Type Description
DBGBCR 80-95 0x140 - 0x17C 0x80010140 - 0x8001017C 0x80012140 - 0x8001217C 0x80014140 - 0x8001417C 0x80016140 - 0x8001617C RW DBGBCR, Breakpoint Control Registers on page C11-2213
DBGBVR 64-79 0x100 - 0x13C 0x80010100 - 0x8001013C 0x80012100 - 0x8001213C 0x80014100 - 0x8001413C 0x80016100 - 0x8001613C RW DBGBVR, Breakpoint Value Registers on page C11-2218

C6.4.1 Using CP14 to access debug registers (page C6-2122)

The form of the MRC and MCR instructions used for accessing debug registers through the CP14 interface is:

MRC p14, 0, <Rt>, <CRn>, <CRm>, <opc2>  ; Read
MCR p14, 0, <Rt>, <CRn>, <CRm>, <opc2>  ; Write

Where <Rt> refers to any of the ARM core registers R0-R14. Use of R13 is UNPREDICTABLE in Thumb and ThumbEE states, and is deprecated in ARM state. <CRn> , <CRm> , and <opc2> are mapped from the debug register number as shown in Figure C6-1

Table C6-3 Mapping of CP14 MCR and MRC instruction arguments to registers

Register number CRn opc2 CRm Access Register name Description
80-95 c0 5 c0-15 RW DBGBCRm Breakpoint Control
64-79 c0 4 c0-15 RW DBGBVRm Breakpoint Value

OpenOCD command

example nemonic OpenOCD command
Read DBGBCR3 MRC p14, 0, r2, c0, c3, 5 rpi2.cpu3 arm mrc 14 0 0 3 5
Read DBGBVR3 MRC p14, 0, r2, c0, c3, 4 rpi2.cpu3 arm mrc 14 0 0 3 4

16 Architecture and Core Commands > 16.2 Generic ARM > mrc

> help rpi2.cpu3 arm mrc 
    rpi2.cpu3 arm mrc cpnum op1 CRn CRm op2
          read coprocessor register
  • rpi2.cpu3 arm mrc <cpnum> <opc1> <CRn> <CRm> <opc2>
    • <cpnum> ... 14 (fixed)
    • <opc1> ... 0 (fixed)
    • <CRn> ... 0 (fixed)
    • <CRm> ... 0-5 (by Info : rpi2.cpu3: hardware has 6 breakpoints, 4 watchpoints)
    • <opc2> ... 4-5 (4...DBGBVRn, 5...DBGBCR3)

16 Architecture and Core Commands > 16.2 Generic ARM > mcr

> help rpi2.cpu3 arm mcr 
    rpi2.cpu3 arm mcr cpnum op1 CRn CRm op2 value
          write coprocessor register
  • rpi2.cpu3 arm mcr <cpnum> <opc1> <CRn> <CRm> <opc2> <value>
    • <value> ... 0x21E7 (SSC[15:14]=0b00, HMC[13]=0b1, BAS[8:5]=0b1111, PMC[2:1]=0b11, E[0]=0b1)

Hyp debugging by hand

> targets rpi2.cpu3
> halt
> reg pc
pc (/32): 0x000000C8
> arm disassemble 0xc8 3 
0x000000c8      0xe7954200      LDR r4, [r5, r0, LSL #0x4]
0x000000cc      0xe1540003      CMP r4, r3
0x000000d0      0x0afffffc      BEQ 0x000000c8
> bp 0xcc 0 0 hw
breakpoint set at 0x000000cc
> bp
Breakpoint(IVA): 0x000000cc, 0x0, 5
> arm mrc 14 0 0 4 4
204
> arm mrc 14 0 0 4 5
487 // =0x01e7 ... lack of "HMC, bit[13]" for Hypervisor break
> arm mcr 14 0 0 4 5 0x21e7
> arm mrc 14 0 0 4 5
8679 // =0x21e7
> step
target state: halted
target halted in ARM state due to breakpoint, current mode: Hypervisor
cpsr: 0x600001da pc: 0x000000cc
MMU: disabled, D-Cache: disabled, I-Cache: disabled
> targets
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0  rpi2.cpu0          cortex_a   little rpi2.dap           running
 1  rpi2.cpu1          cortex_a   little rpi2.dap           running
 2  rpi2.cpu2          cortex_a   little rpi2.dap           running
 3* rpi2.cpu3          cortex_a   little rpi2.dap           halted

Success!

Patch to openocd-0.9.0

diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 207fb81..17e476c 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -1440,6 +1440,8 @@ static int cortex_a_set_breakpoint(struct target *target,
                if (breakpoint->length == 2)
                        byte_addr_select = (3 << (breakpoint->address & 0x02));
                control = ((matchmode & 0x7) << 20)
+                       | (0 << 14)
+                       | (1 << 13)
                        | (byte_addr_select << 5)
                        | (3 << 1) | 1;
                brp_list[brp_i].used = 1;
@@ -1508,6 +1510,8 @@ static int cortex_a_set_context_breakpoint(struct target *target,

        breakpoint->set = brp_i + 1;
        control = ((matchmode & 0x7) << 20)
+               | (0 << 14)
+               | (1 << 13)
                | (byte_addr_select << 5)
                | (3 << 1) | 1;
        brp_list[brp_i].used = 1;
@@ -1574,6 +1578,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi
        control_CTX = ((CTX_machmode & 0x7) << 20)
                | (brp_2 << 16)
                | (0 << 14)
+               | (1 << 13)
                | (CTX_byte_addr_select << 5)
                | (3 << 1) | 1;
        brp_list[brp_1].used = 1;
@@ -1592,6 +1597,8 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi

        control_IVA = ((IVA_machmode & 0x7) << 20)
                | (brp_1 << 16)
+               | (0 << 14)
+               | (1 << 13)
                | (IVA_byte_addr_select << 5)
                | (3 << 1) | 1;
        brp_list[brp_2].used = 1;

To examine

Load vmm.elf via JTAG and step into _start

When halted at first, rpi2.cpu0 is in infinite loop at armjtag.c#L78

> targets rpi2.cpu.0
> halt
> load_image vmm.elf
1419164 bytes written at address 0x10000000
downloaded 1419164 bytes in 44.374302s (31.232 KiB/s)
> step 0x10000000
target state: halted
target halted in ARM state due to breakpoint, current mode: Hypervisor
cpsr: 0x800001da pc: 0x10000004
MMU: disabled, D-Cache: disabled, I-Cache: disabled
> arm disassemble 0x10000000 20

@tonosaman
Copy link
Author

Debug with gdb

$ gcc-linaro-arm-linux-gnueabihf-4.8-2014.04_linux/bin/arm-linux-gnueabihf-gdb xvisor-next/build/vmm.elf
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
0x00000000 in ?? ()
(gdb) monitor reset
JTAG tap: rpi2.dap tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
rpi2.cpu0: hardware has 6 breakpoints, 4 watchpoints
rpi2.cpu1: hardware has 6 breakpoints, 4 watchpoints
rpi2.cpu2: hardware has 6 breakpoints, 4 watchpoints
rpi2.cpu3: hardware has 6 breakpoints, 4 watchpoints
rpi2.cpu0: how to reset?
in procedure 'reset' 
in procedure 'ocd_bouncer'


(gdb) monitor targets
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0  rpi2.cpu0          cortex_a   little rpi2.dap           running
 1  rpi2.cpu1          cortex_a   little rpi2.dap           running
 2  rpi2.cpu2          cortex_a   little rpi2.dap           running
 3* rpi2.cpu3          cortex_a   little rpi2.dap           halted
(gdb) monitor resume
(gdb) monitor targets rpi2.cpu0
(gdb) monitor halt
ttbcr 0ttbr0 56b7fb7bttbr1 fa74707a
rpi2.cpu0 rev 5, partnum c07, arch f, variant 0, implementor 41
number of cache level 2
cache l2 present :not supported
rpi2.cpu0 cluster f core 0 multi core
target state: halted
target halted in ARM state due to debug-request, current mode: Hypervisor
cpsr: 0x800001da pc: 0x00008018
MMU: disabled, D-Cache: disabled, I-Cache: disabled
(gdb) load
Loading section .text, size 0xdbcdc lma 0x10000000
Loading section .text.unlikely, size 0xd8 lma 0x100dbcdc
Loading section .init, size 0x26850 lma 0x100dc000
Loading section .cpuinit, size 0x2980 lma 0x10103000
Loading section .spinlock, size 0x4b0 lma 0x10106000
Loading section .rodata, size 0x3f630 lma 0x10107000
Loading section .percpu, size 0x1d8 lma 0x10147000
Loading section .data, size 0x126d8 lma 0x10148000
Loading section __clk_of_table_end, size 0xc4 lma 0x1015a6d8
Start address 0x10000000, load size 1405912
Transfer rate: 29 KB/sec, 15281 bytes/write.
(gdb) p $pc
$1 = (void (*)()) 0x10000000 <_text_start>
(gdb) disass $pc
Dump of assembler code for function _text_start:
=> 0x10000000 <+0>:     sub     r4, pc, #8
   0x10000004 <+4>:     ldr     r6, [pc, #712]  ; 0x100002d4 <__exec_start>
   0x10000008 <+8>:     ldr     r7, [pc, #712]  ; 0x100002d8 <__exec_end>
   0x1000000c <+12>:    sub     r3, r7, r6
   0x10000010 <+16>:    add     r5, r4, r3
   0x10000014 <+20>:    ldr     r3, [pc, #684]  ; 0x100002c8 <__boot_reg0>
...
(gdb) disass/m $pc,+20
Dump of assembler code from 0x10000000 to 0x10000014:
45              add     r4, pc, #-0x8
=> 0x10000000 <_text_start+0>:  sub     r4, pc, #8

46              ldr     r6, __exec_start
   0x10000004 <_text_start+4>:  ldr     r6, [pc, #712]  ; 0x100002d4 <__exec_start>

47              ldr     r7, __exec_end
   0x10000008 <_text_start+8>:  ldr     r7, [pc, #712]  ; 0x100002d8 <__exec_end>

48              sub     r3, r7, r6
   0x1000000c <_text_start+12>: sub     r3, r7, r6

49              add     r5, r4, r3
   0x10000010 <_text_start+16>: add     r5, r4, r3

50
51              /* Save boot reg0 (i.e. r0) */
52              ldr     r3, __boot_reg0
   0x10000014 <_text_start+20>: ldr     r3, [pc, #684]  ; 0x100002c8 <__boot_reg0>

@tonosaman
Copy link
Author

Auto start-up configuration by using GDB script

$ gcc-linaro-arm-linux-gnueabihf-4.8-2014.04_linux/bin/arm-linux-gnueabihf-gdb -x rpi2.gdb xvisor-next/build/vmm.elf

rpi2.gdb

target remote localhost:3333
monitor rpi2.cpu3 arp_halt
monitor rpi2.cpu2 arp_halt
monitor rpi2.cpu1 arp_halt
monitor targets rpi2.cpu0
monitor halt
monitor reset halt
monitor targets
load

@tonosaman
Copy link
Author

Research: Outer Cache prevents JTAG debugging?

References

  • Translation table walk using the Long-descriptor translation table format for stage 1 (p. B3-1510)
  • Stage 2 translation table walk (p. B3-1516)
  • B4.1.74 HTCR, Hyp Trtanslation Control Register, Virtualization Extensions (p. B4-1597)
  • B4.1.159 VTCR, Virtualization Trtanslation Control Register, Virtualization Extensions (p. B4-1738)
  • B3.2.1 VMSA behavior when a stage 1 MMU is disabled (p. B3-1314)
  • B4.1.71 HSCTLR, Hyp System Control Register, Virtualization Extensions (p. B4-1591)

HSCTLR 0x30c50878 -> 0x30c5187d
0x30c50878 ... 0b0011.0000.1100.0101.0000.1000.0111.1000
0x30c5187d ... 0b0011.0000.1100.0101.0001.1000.0111.1101

Bits Name Val Function
[12] I 0b1 Instruction cache enable bit: This is a global enable bit for instruction caches, for memory accesses made in Hyp mode.
[2] C 0b1 Cache enable bit. This is a global enable bit for data and unified caches, for memory accesses made in Hyp mode.
[1] M 0b1 MMU enable bit. This is a global enable bit for the PL2 stage 1 MMU.

Trial Memo

HTCR bits Meaning RPi2 default XVisor set to
ORGN0[11:10] 0b01 Ourter Write-Back Write-Allocate Cacheable Ourter Write-Back Write-Allocate Cacheable Ourter Write-Back Write-Allocate Cacheable
IRGN0[9:8] 0b00 Inner Non-cacheable Inner Non-cacheable Inner Write-Back Write-Alocate Cacheable

set *((int *)__htcr_set) = 0x80803400

VTCR bits Meaning RPi2 default XVisor set to
ORGN0[11:10] 0b00 Ourter Non-cacheable Ourter Non-cacheable Outer Write-Back Write-Allocate Cacheable
IRGN0[9:8] 0b00 Inner Non-cacheable Innver Wirte-Back no Write-Allocate Cacheable Inner Write-Back Write-Alocate Cacheable

set *((int *)__vtcr_set) = 0x80003059

@tonosaman
Copy link
Author

[Solved] Issue: Out of GDB control after enabling MMU with Stage 2 TLB mapping

I have lost GDB debugging control after isb or dsb instruction.

Solution

Add a line gdb_breakpoint_override hard to openocd-rpi2.cfg (config file for openocd).
See detail "Conjecture 3".

Conjecture 1: Some configuration about instruction fetching cause

BUSTED 👎

OpenOCD error message says data about occured.

Error: data abort at 0x696e486c, dfsr = 0x0000004b
Error: data abort at 0xe200001f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b
Error: data abort at 0xf57ff04f, dfsr = 0x0000004b

I guessed this might be caused by using memory mapped debug registers.

  • Table C6-9 v7 Debug memory-mapped and external debug interfaces access behavior (p. C6-2136)

  • Table C6-14 v7.1 Debug memory-mapped and external debug interfaces access behavior

  • OpenOCD access routine @openocd-0.9.0/src/target/cortex_a.c:495

    static int cortex_a_dap_write_memap_register_u32(struct target *target,
    

Conjecture 2: Memory mapped DAP registers can't access from OpenOCD

BUSTED 👎

  • C11.11.21 DBGDSMCR, Debug State MMU Control Register (p. C11-2259)

DAP(0xc0010000, 0xc0012000, 0xc0014000, 0xc0016000) described in openocd-rpi2.cfg are VideoCore's bus-address, not ARM side physical address.

But, JTAG might use peripheral via ARM physical memory range 0x3f000000 to 0x3fffffff(VideoCore map that range to peripheral bus addresses 0x7e000000 to 0x7effffff).

Investigate this hypothesis in next comment.

Info: need appropriate flush TLB while debugging

  • C11.11.21 DBGDSMCR, Debug State MMU Control Register (p. C11-2259)

    If TLB matching is disabled, and TLB maintenance functions have not been correctly performed by the system being debugged, for example, if the TLB has not been flushed following a change to the translation tables, memory accesses made by the debugger might not undergo the same virtual to physical memory mappings as the application being debugged.

    Therefore some debugger disable outer(L2) cache.

Info: What about isb does

In this context, isb means:

> • completed cache, TLB, and branch predictor maintenance operations
  • DDI0406C_C_arm_architecture_reference_manual.pdf (p. A3-153)

    Instruction Synchronization Barrier (ISB)
    An ISB instruction flushes the pipeline in the processor, so that all instructions that come after the ISB instruction in program order are fetched from cache or memory only after the ISB instruction has completed. Using an ISB ensures that the effects of context-changing operations executed before the ISB are visible to the instructions fetched after the ISB instruction. Examples of context-changing operations that require the insertion of an ISB instruction to ensure the effects of the operation are visible to instructions fetched after the ISB instruction are:
    • completed cache, TLB, and branch predictor maintenance operations
    • changes to system control registers.
    Any context-changing operations appearingin program order after the ISB instruction only take effect after the ISB has been executed.

Conjecture 3: gdb step command using rewrite instruction cause broken cache coherency.

From openocd debug log message with -d 3 option.

Debug: 5240 4637036 breakpoints.c:106 breakpoint_add_internal(): added software breakpoint at 0x10000294 of length 0x00000004, (BPID: 21)

Otherwise, according to cortex_a.c it looks like using hardware break point.

static int cortex_a_step(struct target *target, int current, uint32_t address, int handle_breakpoints)
    -> cortex_a_unset_breakpoint()
    stepbreakpoint.type = BKPT_HARD
    -> cortex_a_set_breakpoint(target, &stepbreakpoint, 0x04)

GDB 'step' packet reqired BKPT_SOFT.

Debug: 5504 205298 gdb_server.c:1563 gdb_breakpoint_watchpoint_packet(): -
(gdb) bt
#0  breakpoint_add (target=target@entry=0x86d120, address=address@entry=268436116, length=4, type=type@entry=BKPT_SOFT) at breakpoints.c:226
#1  0x0000000000434414 in gdb_breakpoint_watchpoint_packet (packet=0x7febe0 <gdb_packet_buffer> "Z0,10000294,4", packet_size=<optimized out>, connection=<optimized out>) at gdb_se\
rver.c:1603
#2  gdb_input_inner (connection=<optimized out>) at gdb_server.c:2709
#3  gdb_input (connection=<optimized out>) at gdb_server.c:2876
#4  0x00000000004359fb in server_loop (command_context=0x8193b0) at server.c:473
#5  0x0000000000405563 in openocd_thread (argc=7, argv=0x7fffffffdd98, cmd_ctx=0x8193b0) at openocd.c:301
#6  0x000000000040563e in openocd_main (argc=7, argv=0x7fffffffdd98) at openocd.c:338
#7  0x0000000000404f99 in main (argc=7, argv=0x7fffffffdd98) at main.c:41
(gdb) p type
$15 = BKPT_SOFT
(gdb) p/x address
$17 = 0x10000294

The key for solution is gdb_breakpoint_override_type.
gdb_breakpoint_override_type@openocd-0.9.0/src/server/gdb_server.c#L1583

static int gdb_breakpoint_watchpoint_packet(struct connection *connection, char const *packet, int packet_size)
{
        ...
        if (type == 0)  /* memory breakpoint */
                bp_type = BKPT_SOFT;
        else if (type == 1)     /* hardware breakpoint */
                bp_type = BKPT_HARD;
        ...
        if (gdb_breakpoint_override && ((bp_type == BKPT_SOFT) || (bp_type == BKPT_HARD)))
                bp_type = gdb_breakpoint_override_type;

Add a line to openocd-rpi2.cfg (config file for openocd).

gdb_breakpoint_override hard

Thus, now step working with hardware breakpoint.

Debug: 5148 129070 gdb_server.c:1563 gdb_breakpoint_watchpoint_packet(): -
(gdb) bt
#0  breakpoint_add (target=target@entry=0x86d600, address=address@entry=268436116, length=4, type=type@entry=BKPT_HARD) at breakpoints.c:226
#1  0x0000000000434414 in gdb_breakpoint_watchpoint_packet (packet=0x7febe0 <gdb_packet_buffer> "Z0,10000294,4", packet_size=<optimized out>, connection=<optimized out>) at gdb_se\
rver.c:1603
#2  gdb_input_inner (connection=<optimized out>) at gdb_server.c:2709
#3  gdb_input (connection=<optimized out>) at gdb_server.c:2876
#4  0x00000000004359fb in server_loop (command_context=0x8193b0) at server.c:473
#5  0x0000000000405563 in openocd_thread (argc=7, argv=0x7fffffffdd98, cmd_ctx=0x8193b0) at openocd.c:301
#6  0x000000000040563e in openocd_main (argc=7, argv=0x7fffffffdd98) at openocd.c:338
#7  0x0000000000404f99 in main (argc=7, argv=0x7fffffffdd98) at main.c:41
(gdb) p type
$14 = BKPT_HARD

Conjecture 4:

OpenOCD(=gdbserver) does not recognize that Hypervisor MMU has been enabled.

                LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
                        state[armv7a->armv7a_mmu.mmu_enabled],
                        state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
                        state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);

In this current situation, this matter does not affect the function of step.
Because, we have just set the hypervisor level1 TLB to straight map between virtual address and physical address.

However, by another aspects if we have different mapping between virtual and physical then we should treat properly the status of hypervisor MMU.

static int cortex_a_post_debug_entry(struct target *target)
{
        /* MRC p15,0,<Rt>,c1,c0,0 ; Read CP15 System Control Register */
        retval = armv7a->arm.mrc(target, 15,
                        0, 0,   /* op1, op2 */
                        1, 0,   /* CRn, CRm */
                        &cortex_a->cp15_control_reg);
               armv7a->armv7a_mmu.mmu_enabled =
                        (cortex_a->cp15_control_reg & 0x1U) ? 1 : 0;
        armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled =
                (cortex_a->cp15_control_reg & 0x4U) ? 1 : 0;
        armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled =
                (cortex_a->cp15_control_reg & 0x1000U) ? 1 : 0;
        cortex_a->curr_mode = armv7a->arm.core_mode;


src/target/cortex_a.c:1284:             retval = armv7a->post_debug_entry(target);

@tonosaman
Copy link
Author

Hypervisor MMU settings

  • stage 1 TLB is enabled
    • HSCTLR=0x30c5187d
      • Hypervisor System Control Register
      • (gdb) monitor rpi2.cpu0 arm mrc 15 4 1 0 0
      • M[0] controls Non-secure PL2 stage 1 MMU.
    • HTCR=0x80803500
      • Hypervisor Translation Control Register
      • (gdb) monitor rpi2.cpu0 arm mrc 15 4 2 0 2
    • HTTBR=0x10166000 (=def_ttbl)
      • Hyp Translation Table Base Register, Virtualization Extensions
  • stage 2 TLB is enabled in _reset()@cpu_entry.S
    • HCR=0x00000039

      • Hyp Configuration Register, Virtualization Extensions
      • (gdb) monitor rpi2.cpu0 arm mrc 15 4 1 1 0
      • VM[0] controls Non-secure PL1&0 stage 2 MMU.
      #define HCR_DEFAULT_BITS (HCR_AMO_MASK | HCR_IMO_MASK | HCR_FMO_MASK | HCR_VM_MASK)
    • VTTBR

    • VTCR=0x80003559

      • (gdb) monitor rpi2.cpu0 arm mrc 15 4 2 1 2

Need to map for periferal

This context is under the setting of Non-secure PL2 stage 1 MMU (HTTBR and HTCR) .

MRC p15, 4, <Rt>, c2, c0, 2 ; Read HTCR into Rt
MRRC p15, 4, <Rt>, <Rt2>, c2 ; Read 64-bit HTTBR into Rt (low word) and Rt2 (high word)
chip physical addresses(ARM side address) bus addresses (VideoCore/GPU address) spec.
BCM2836 0x0000_0000 .. 0x3EFF_FFFF 0xC0000000 .. 0xFEFF_FFFF SDRAM (16MB unseen from ARM side)
BCM2836 0x3F00_0000 .. 0x3FFF_FFFF 0x7E000000 .. 0x7EFF_FFFF peripherals @see BCM2835-ARM-Peripherals.pdf
#define BCM2708_PERI_BASE 0x3F000000
#define BCM2708_PAGE_SIZE 0x01000000    /* VC MMU Page Size is 16MB. */
  __setup_initial_ttbl(&lpae_entry, BCM2708_PERI_BASE, BCM2708_PERI_BASE
    + BCM2708_PAGE_SIZE, BCM2708_PERI_BASE, AINDEX_SO, TRUE);
/* 
 * 16MB is same size as Supersection memory block (24-bit offsets).
 * Thus, In Non-secure PL2 stage 1 TLB, Second-level table entries 
 * which associates (8 * 2)MB memory region will be allocated assigned.
 */

@tonosaman
Copy link
Author

Debug arch of RPi2 is v7.1

cpuid = 0x410fc075
ctypr = 0x84448003
ttypr = 0x00000000
didr = 0x3515f005

get_debug_arch()@linux

assert((cpuid >> 16) & 0xf == 0xf);
degug_arch = (didr >> 16) & 0xf;

define ARM_DEBUG_ARCH_V7_1 5

C6.4.1 Using CP14 to access debug registers (p.2123)

  • Register number[9:0]
10 9 8 7 6 5 4 3 2 1 0
0 CRn[3:0] opc2[2:0] Crm[3:0]
MRC p14, 0, <Rt>, <CRn>, <CRm>, <opc2> ; Read
MCR p14, 0, <Rt>, <CRn>, <CRm>, <opc2> ; Write

C6.7 Summary of the v7.1 Debug register interfaces (p.2139)

C11.11.29 DBGLSR, Lock Status Register (p.2267)

  • DBGLSR is only visible in the memory-mapped interface

  • DBGLSR offset = 0xFB4

  • DAP from openocd-rpi2.cfg: rpi2.cpu0 dap debugbase=0xc0010000

  • Thus DBGLSR busaddress is 0xC0010FB4

  • Read DBGLSR

    (gdb) monitor mdw 0xc0010fb4
    0xc0010fb4: 00000000
    

@tonosaman
Copy link
Author

diff --git a/Makefile b/Makefile
index 1098403..44e0faf 100644
--- a/Makefile
+++ b/Makefile
@@ -126,7 +126,7 @@ cppflags+=$(cpu-cppflags)
 cppflags+=$(board-cppflags)
 cppflags+=$(libs-cppflags-y)
 cc=$(CROSS_COMPILE)gcc
-cflags=-g -Wall -nostdlib --sysroot=$(drivers_dir)/include -fno-builtin -D__VMM__
+cflags=-g -O0 -Wall -nostdlib --sysroot=$(drivers_dir)/include -fno-builtin -D__VMM__
 cflags+=$(board-cflags) 
 cflags+=$(cpu-cflags) 
 cflags+=$(libs-cflags-y) 
diff --git a/arch/arm/cpu/common/include/mmu_lpae.h b/arch/arm/cpu/common/include/mmu_lpae.h
index 4b5a73e..adbdf22 100644
--- a/arch/arm/cpu/common/include/mmu_lpae.h
+++ b/arch/arm/cpu/common/include/mmu_lpae.h
@@ -133,6 +133,8 @@ int mmu_lpae_stage2_chttbl(u8 vmid, struct cpu_ttbl *ttbl);
 #define TTBL_L2_INDEX_SHIFT                21
 #define TTBL_L2_BLOCK_SIZE             0x0000000000200000ULL
 #define TTBL_L2_MAP_MASK               (~(TTBL_L2_BLOCK_SIZE - 1))
+#define TTBL_L2_OUTADDR_MASK           0x000000FFFFE00000ULL
+#define TTBL_L2_OUTADDR_SHIFT          21
 /* L3 index Bit[20:12] */
 #define TTBL_L3_INDEX_MASK             0x00000000001FF000ULL
 #define TTBL_L3_INDEX_SHIFT                12
diff --git a/arch/arm/cpu/common/mmu_lpae_entry_ttbl.c b/arch/arm/cpu/common/mmu_lpae_entry_ttbl.c
index d7a231f..366660f 100644
--- a/arch/arm/cpu/common/mmu_lpae_entry_ttbl.c
+++ b/arch/arm/cpu/common/mmu_lpae_entry_ttbl.c
@@ -92,7 +92,25 @@ void __attribute__ ((section(".entry")))
            ttbl =
                (u64 *) (unsigned long)(ttbl[index] &
                            TTBL_OUTADDR_MASK);
-       } else {
+       } else if (page_addr + TTBL_L2_BLOCK_SIZE < map_end) {
+               /* Update level2 block */
+               ttbl[index] =
+                   (((page_addr - map_start) + pa_start) &
+                    TTBL_OUTADDR_MASK);
+               ttbl[index] |= TTBL_STAGE1_LOWER_AF_MASK;
+               ttbl[index] |= (writeable) ?
+                   (TTBL_AP_SRW_U << TTBL_STAGE1_LOWER_AP_SHIFT) :
+                   (TTBL_AP_SR_U << TTBL_STAGE1_LOWER_AP_SHIFT);
+               ttbl[index] |=
+                   (aindex << TTBL_STAGE1_LOWER_AINDEX_SHIFT)
+                   & TTBL_STAGE1_LOWER_AINDEX_MASK;
+               ttbl[index] |= TTBL_STAGE1_LOWER_NS_MASK;
+               ttbl[index] |= (TTBL_SH_INNER_SHAREABLE
+                       << TTBL_STAGE1_LOWER_SH_SHIFT);
+        ttbl[index] |= TTBL_VALID_MASK;
+        page_addr += TTBL_L2_BLOCK_SIZE;
+        continue;
+    } else {
            /* Allocate new level3 table */
            if (lpae_entry->ttbl_count == TTBL_INITIAL_TABLE_COUNT) {
                while (1) ; /* No initial table available */
@@ -244,4 +262,10 @@ void __attribute__ ((section(".entry")))
     */
    __setup_initial_ttbl(&lpae_entry, exec_start, exec_end, load_start,
                 AINDEX_NORMAL_WB, TRUE);
+
+#define BCM2708_PERI_BASE 0x3F000000
+#define BCM2835_PERI_SIZE 0x01000000
+   __setup_initial_ttbl(&lpae_entry, BCM2708_PERI_BASE
+                      , BCM2708_PERI_BASE + BCM2835_PERI_SIZE
+                      , BCM2708_PERI_BASE, AINDEX_SO, TRUE);
 }

@tonosaman
Copy link
Author

@meriororen
Copy link

Hi.

Regarding this line :

umm... openocd-0.9 does not recognize Hypervisor mode of Cortex-A7 MPCore architecture correctly.

How did you solve this? It seems that I keep getting this when I run 'halt' :

Error: invalid mode value encountered 26
Info : ttbcr 0ttbr0 6fb52b5bttbr1 8b10bf69
Info : rp2.cpu.1 rev 5, partnum c07, arch f, variant 0, implementor 41
Info : number of cache level 2
Error: cache l2 present :not supported
Info : rp2.cpu.1 cluster f core 1 multi core
target state: halted
Error: unrecognized psr mode: 0x1a
target halted in ARM state due to debug-request, current mode: UNRECOGNIZED
cpsr: 0x600001da pc: 0x000000cc
MMU: disabled, D-Cache: disabled, I-Cache: disabled

Thank you

@AZO234
Copy link

AZO234 commented Sep 2, 2016

日本語で失礼します。

target halted in ARM state due to debug-request, current mode: Hypervisor

これはOpenOCDにHypervisor用の実装を加えたものでしょうか?
merioromen氏も書いている通り、par mode: 0x1a の解決方法をご教示下さいませ。
(軽い気持ちで src/target/armv4_5.c に実装を加えたらアボートしてしまいました・・・)
Raspberry Pi 3も同様にHYPモード関連でOpenOCDが使い物になりませんね。
SVCモードでもレジスタが触れないのは悲しいです。
更にAArch64・AArch32と、コンパイラやGDBも使い分けなきゃいけないのはしんどいですw

p.s. トノサマン最高です。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment