Jonah Petri

Debugging Linux Kernel over JTAG with J-Link

Discussion created by Jonah Petri on Sep 30, 2015
Latest reply on Dec 9, 2017 by Jonah Petri

We've been working through getting a working setup for debugging the linux kernel via JTAG, using Segger's J-Link.  There's a few hints on this forum and elsewhere, but not a complete guide, so here's what works for us:


First: if you just go and try debugging the kernel, you'll probably find that you either:

  • can't connect at all once linux has booted, or
  • if you connect at u-boot, and then let linux load, you get disconnected around the time that init runs, or
  • if you get lucky and manage to connect when linux is running, you get disconnected shortly afterwards.


This issue is caused by linux going into a low power idle state.  In this state, linux will gate the ARM clock domain, causing the JTAG to lose connection whenever the OS is executing the idle task. There are two ways around this. The first is less invasive, but slightly more limited.


Method 1 (easy method): Disable 'clock off' wait state in the cpuidle driver


On the IMX6 you can disable the clock off wait state through sysfs. Navigate to the cpuidle driver for the cpu (cpu0 in this case as we are on the solo lite).


cd /sys/devices/system/cpu/cpu0/cpuidle/state1


cat desc

The output of 'cat desc' should be 'Clock off'. If this is not the case, go up a folder and check the other states until you find the one with the 'Clock off' desc. Now, you simply need to disable this wait state


echo 1 > disable


Now you should be able to attach with JTAG and debug to your heart's content.


Method 2 (harder method): Disable gating of the ARM clock domain in the source


The above method is good for most cases of debugging, unless something needs to be debugged during startup. In this case you will need to modify the source to stop the IMX from ever gating the ARM clock domain. You can apply the following patch to disable the clock gating.


diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c


index e1a45e2..feadccb 100644

--- a/arch/arm/mach-imx/pm-imx6.c

+++ b/arch/arm/mach-imx/pm-imx6.c

@@ -552,8 +552,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)

        case WAIT_CLOCKED:


        case WAIT_UNCLOCKED:

-               val |= 0x1 << BP_CLPCR_LPM;

-               val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM;


        case STOP_POWER_ON:

                val |= 0x2 << BP_CLPCR_LPM;

J-Link setup


We have been using the Segger J-Link to debug ARM platforms from a linux host. Download the Segger J-Link tools for Linux from the Segger website. After you have done one of the two above methods you can now attach the J-Link GDB server. Note that by default your user wont have permissions to access the J-Link USB device. You can either setup a udev rule to set the permissions properly, or simply run the gdb server as root. We will do the latter as we are lazy. Note the noir and noreset options. noir will not init the working register and noreset won't reset the cpu core. See the J-Link documentation included with the download for more info.


sudo ./JLinkGDBServer -if JTAG -endian little -device MCIMX6L8 -select USB -noir -noreset


Helpful kernel configuration options for debugging


Before diving right into debugging, note there are some useful kernel configuration options that will make your life a lot easier. Below is a list of kernel configuration options you should set:


CONFIG_DEBUG_INFO=y # this will compile in debugging symbols and info


GDB client connection and debugging!


Finally, with a GDB server running that is connected to your target, you can connect with a GDB client. Note that you can point GDB to your linux binary for the debugging information. Also, you should use your cross compile GDB for this target. If you are using the Yocto Poky SDK (as we are), you can simply source the SDK and use '$GDB' in place of gdb-[CROSS-COMPILE] below. Note that [CROSS-COMPILE] should be replaced with your proper cross compile tuple (e.g. gdb-arm-linux-eabi).


$ gdb-[CROSS-COMPILE] /path/to/linux/build/vmlinux


(gdb) target remote localhost:2331


Enjoy your debugging session!  Any questions or comments, please post them below.