NOTICE: The Processors Wiki will End-of-Life in December of 2020. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
Debugging on DaVinci using BDI2000
Content is no longer maintained and is being kept for reference only!
Debugging the Linux kernel using the BDI2000 JTAG emulator on DM6446
This topic discusses how to debug the Linux kernel on Davinci using a BDI2000 JTAG emulator from Abatron (http://www.abatron.ch). It uses the command line client gdb as a front end, on top of which you can put a GUI like DDD if you like (http://www.gnu.org/software/ddd). This topic assumes a Linux host. You may or may not be successful on Windows using these instructions, but you will likely have to modify them slightly. This topic also assumes you are using TFTP to load your Linux kernel image and that you are mounting your Linux target root filesystem off of NFS.
BDI2000 can only be used to debug the Linux kernel and kernel modules as it doesn't know of different MMU contexts (much in the same way as CCS).
Note! Do not configure KGDB support into the kernel. Using KGDB and the BDI2000 are mutually exclusive.
Setting up the BDI2000 JTAG emulator for DM6446
First make sure you have purchased a BDI2000 emulator for the ARM7/9/9e cores and with software for bdiGdb.
To connect the BDI2000 to the EVM board use the ARM/XScale cable that comes with the emulator. Connect the ARM/XScale end of the cable to the 20 pin ARM converter that came with the DVEVM (if you have a alpha, beta, gamma or delta board -- if you have a production board you have to build your own adapter using these schematics). Plug the ARM converter into the JTAG connector on the DVEVM board.
Follow the instructions that come with the BDI2000 for setting up the emulator to receive commands from ethernet. When it becomes time to give the BDI2000 a configuration file type the following into a text file named davinci.cnf and put it in your tftp root directory (along with the reg926e.def file):
[INIT] [TARGET] CPUTYPE ARM926E CLOCK 4 ; JTAG clock : without adaptive clocking cable, 1 MHz ;CLOCK 7 ; JTAG clock value required for BDI3000, 1MHz TRST PUSHPULL ; TRST driver type (OPENDRAIN | PUSHPULL) RESET HARD 500 ; NONE | HARD <n> (ms) ENDIAN LITTLE ; memory model (LITTLE | BIG) WAKEUP 100 SCANPRED 1 6 ; count for ICEPick TAP SCANSUCC 0 0 ; no device after ARM926e BREAKMODE SOFT ; HARD = hardware, SOFT = software, go figure VECTOR CATCH 0x02 ; catch undefined instructions ; Configure ICEPick module to make ARM926 TAP visible SCANINIT r1:w400000:r0 ; toggle reset for 0.4 seconds SCANINIT t1:w1000:t0:w1000: ; toggle TRST SCANINIT i6=07:d8=89:i6=02: ; connect and select router SCANINIT d32=81000082: ; set IP control SCANINIT d32=a018206f: ; configure TAP0 SCANINIT d32=a018216f:cl5: ; enable TAP0, clock 5 times in RTI SCANINIT d32=a018616f:cl5: ; enable TAP0, clock 5 times in RTI SCANINIT i10=ffff ; scan bypass ;STARTUP RUN [HOST] IP 192.168.1.104 PROMPT DaVinci> [FLASH] CHIPTYPE MIRRORX16 CHIPSIZE 0x02000000 BUSWIDTH 16 WORKSPACE 0x1000 [REGS] FILE $reg926e.def
- NOTICE: Note that you should replace the [HOST]:IP parameter (192.168.1.104) with your host ip (where gdb is running). If you don't want the target to halt immediately (to be explicitly released by gdb) then you can uncomment the STARTUP RUN line.
- NOTICE: The BDI3000 is providing a higher maximum clock rate and thus requires a different CLOCK value. the parameter 'CLOCK 4' has te beset to 'CLOCK 7' for the new BDI3000 to get the thje same JTag clock.
- NOTICE: This example also works for the DM6467
Preparing the Linux kernel for debugging
On your host machine, cd into the Linux kernel source top level directory and edit the Makefile. Find the place where C_FLAGS are assigned and add a -g at the end. This adds debugging information to the kernel image we are about to create.
Now make sure your montavista/pro/bin directory is in your path (where mkimage resides) as well as your montavista/pro/devkit/arm/v5t_le/bin directory (where arm_v5t_le-gcc resides).
To configure the DM6446 Linux kernel with the default options execute:
make ARCH=arm CROSS_COMPILE=arm_v5t_le- davinci_dm644x_defconfig
make ARCH=arm CROSS_COMPILE=arm_v5t_le- checksetconfig
To create the kernel image (with verbose output) execute:
KBUILD_VERBOSE=1 make ARCH=arm CROSS_COMPILE=arm_v5t_le- uImage
Enabling the verbose mode of the build system allows you to verify that the -g you added above actually does get fed to the compiler. This will create a kernel image in arch/arm/boot/uImage. Copy this image to your tftp repository ( typically /tftpboot).
Also you might want to build your kernel modules using:
KBUILD_VERBOSE=1 make ARCH=arm CROSS_COMPILE=arm_v5t_le- modules
Assuming your NFS target file system is located at /targetfs on your host file system, you can install the modules (with debugging information!) using:
INSTALL_MOD_PATH=/targetfs make ARCH=arm CROSS_COMPILE=arm_v5t_le- modules_install
Debugging the Linux kernel using BDI2000
First you of course need to make sure you are booting from the uImage you just created. I would suggest using TFTP to boot your uImage. This way you can pick up modifications quickly while developing. The DVEVM Getting Started Guide has information on how to boot a Linux kernel image from TFTP.
Telnet to your (configured as above) BDI2000 using telnet and execute the reset command at the prompt. You should see something like:
- TARGET: processing reset request - TARGET: BDI executes scan chain init string - TARGET: Bypass check 0x00000001 => 0x00000002 - TARGET: JTAG exists check passed - Core#0: ID code is 0x07926001 - TARGET: All ICEBreaker access checks passed - TARGET: BDI removes RESET - TARGET: BDI waits for RESET inactive - TARGET: resetting target passed - TARGET: processing target startup .... - TARGET: processing target startup passed - TARGET: core #0 has entered debug mode DaVinci>
Note that the BDI2000 configuration will keep the ARM halted until you release it. At this DaVinci> prompt you can access the BDI2000 directly. You normally don't want to do this as gdb provides a much more flexible and powerful interface, but the reset command does come in handy sometimes.
Now start the gdb debugger from the Montavista tool chain using arm_v5t_le-gdb (provided it's in your path) and execute the following commands from the gdb prompt:
symbol-file /path/to/linux/kernel/source/vmlinux target remote [bdi2000 ipaddress]:2001 hbreak start_kernel cont
The first command will load the symbols of the Linux kernel from a non-stripped version of the uImage file. The second command will connect to your BDI2000 emulator over TCP/IP and the third command will set a hardware breakpoint at the first kernel C function. The reason why we use a hardware breakpoint is that if we use a software breakpoint, the ESTOP instruction is likely to be overwritten when the Linux kernel decompresses. The fourth command will continue execution until a breakpoint is hit.
If you want to debug the Linux kernel after it has booted you can put a software breakpoint on the sys_sync() function using b sys_sync (note that this has to be done after the kernel decompresses as it's a software breakpoint) and then execute the sync command at the target Linux bash prompt. This is also a good method of entering the debugger to add breakpoints, for instance when debugging kernel modules (see below).
Executing one or more of these commands every time can be tedious. Instead, put the commands you execute every time (one per line) in a file somewhere on your host file system and name it something like gdbstart.txt. To execute the commands when gdb is started execute arm_v5t_le-gdb -x gdbstart.txt. Alternatively if you are always working on one project you can put the commands in your .gdbinit file in your home directory (this way they will always be executed when you start gdb).
Debugging Linux kernel modules using BDI2000
Many device drivers, especially those in development (for easy testing without rebooting the system), will be kept as runtime loadable kernel modules. This section describes how to debug them using gdb and the BDI2000 JTAG emulator. I will use the DSP Link kernel module as an example.
On the target, first insert the modules as you normally do when running the DVEVM demos using ./loadmodules in the /opt/dvevm directory. Then execute cat /proc/modules and you will see a line containing something like this:
dsplinkk 68632 0 - Live 0xbf005000
The last number is the address to which the dynamic kernel module was loaded. Assuming you have added the breakpoint at
sys_sync() as described above (in fact you might want to edit your startup script to set your hardware breakpoint on
sys_sync() instead of
start_kernel() if you are debugging kernel modules), now execute sync on the target command line. This will trigger a breakpoint and allow you to give commands to gdb (and after you are done giving gdb commands you can resume execution using the cont command).
Now we want to add the symbols of the dsplinkk.ko kernel module to gdb, and you have to use the debug version of dsplinkk.ko to be able to debug it, so execute the following in gdb (example path for DVEVM 1.10 and the example address from above):
add-symbol-file /path/to/DVEVM/dsplink_1_30_08_02/packages/dsplink/gpp/export/BIN/Linux/Davinci/DEBUG/dsplinkk.ko 0xbf005000
Let's say we want to single step through the function
DRV_Ioctl() in the DSP Link kernel module. This function is implemented in the file drv_pmgr.c in the gpp/src/pmgr/Linux/2.6 directory. To add this source directory to gdb so that the debugger can find the source file execute the following in gdb:
Note that this step is not needed for kernel modules built inside the Linux kernel build system as the full source path is available in the debugging information.
Now set a breakpoint in GDB on the
DRV_Ioctl() function using b DRV_Ioctl and resume execution using cont.
At the target prompt now execute one of the DM6446 DVEVM demos (which uses Codec Engine, which in turn uses DSP Link), for instance using ./decode -v data/videos/davincieffect_ntsc.m2v. Voila, the breakpoint will be hit inside DSP Link and you can now single step through the DSP Link kernel module.
If you want to find out at which address a certain symbol (like DRV_Ioctl) is loaded at in the kernel you can execute grep DRV_Ioctl /proc/kallsyms on the target (as /proc/kallsyms contain all symbols currently loaded in kernel space).
Note! The location in memory of the kernel module is dynamically assigned by the kernel. However, while I've been debugging the modules they have always been in the same place (assuming you load them in the same order) so in practice most of this process can be automated.