ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

9 messages, 3 authors, 2012-10-16 · open the first message on its own page

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Valentin Pistol <hidden>
Date: 2012-09-13 18:42:09

Hi everyone,

This is my first list post, thanks for bearing with me.

Summary:
Kernel is compiled with CONFIG_HAVE_HW_BREAKPOINT but after boot the DSCR
register does not have monitor mode enabled which is required for debug
register use.
Kernel fails to set monitor mode in the initialization for hw
breakpoints/watchpoints.
It appears to be an EPERM which is silently discarded. I think this should
be logged as pr_warning and I would also be interested to see why it's
failing and fix this.
Any thoughts or suggestions would be greatly appreciated!

Details:
I am interested in using the ptrace interface for hw
breakpoints/watchpoints on a Cortex A9. I found out that watchpoints are
not triggering and tracked down an issue to the hw_breakpoint.c. The flow
is as follows:
arch_hw_breakpoint_init > on_each_cpu(reset_ctrl_regs, &cpumask, 1);  >
reset_ctrl_regs > enable_monitor_mode

enable_monitor_mode performs ARM_DBG_WRITE(c2, 2, (dscr |
ARM_DSCR_MDBGEN));
Another read on dscr is performed to check if the bit was set and if not it
returns -EPERM. In my case the write is not successful so it returns.

Since the reset_ctrl_regs code just returns on failure setting the monitor
mode, there is no reporting of this.
if (enable_monitor_mode)
 return ret;

Hardware: OMAP4460 CPU inside a Galaxy Nexus phone.
Software: Android 4.1.1 and Linux Kernel 3.0.31.
DSCR reads 0x01030002 before/after enable_monitor_mode showing
ARM_DSCR_MDBGEN (bit 15) is not set.
DIDR reads 0x3513702a ( 6 watchpoints and 2 breakpoints )
PTRACE_GETGBPREGS result = 0x3513702a (debug_arch 0x3, max_wp_length = 4,
wp_count = 1, bp_count = 5)

I am aware that the ptrace in my kernel version reports 1 wp as hardcoded
due to an issue with identifying which wp triggered.

dmesg shows the following happening at boot. the hw-wp lines are my own
extra pr_info lines to help debug.

<6>[    0.515777] hw-breakpoint: found 6 breakpoint and 1 watchpoint
registers.
<6>[    0.515777] hw-breakpoint: 1 breakpoint(s) reserved for watchpoint
single-step.
// core 1
<6>[    0.516265] hw-breakpoint: hw-wp: reset_ctrl_regs DBGOSLSR = 0x0
<6>[    0.516265] hw-breakpoint: hw-wp: reset_ctrl_regs DBGAUTHSTATUS = 0xaa
<6>[    0.516723] hw-breakpoint: hw-wp: enable_monitor_mode entering dscr =
0x1030002...
<6>[    0.516723] hw-breakpoint: hw-wp: enable_monitor_mode setting
ARM_DSCR_MDBGEN for ARM_DEBUG_ARCH_V7_ECP14
<6>[    0.516998] hw-breakpoint: hw-wp: enable_monitor_mode dscr write
failed with EPERM
<6>[    0.517181] hw-breakpoint: hw-wp: enable_monitor_mode leaving dscr =
0x1030002 ret = -1...
// core 2: same as above, removed for brevity
<6>[    0.517913] hw-breakpoint: maximum watchpoint size is 4 bytes.

After boot, my ptrace test example with PTRACE_GETHBPREGS works fine
but PTRACE_SETHBPREGS fails silently inside arch_install_hw_breakpoint due
to the same enable_monitor_mode issue.

Thanks for your time,
Valentin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120913/e095fae0/attachment-0001.html>

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Will Deacon <hidden>
Date: 2012-09-13 21:41:02

On Thu, Sep 13, 2012 at 07:42:09PM +0100, Valentin Pistol wrote:
Hi everyone,
Hi Valentin,
This is my first list post, thanks for bearing with me.
You might want to configure your mail client to wrap lines at 76-80 columns
in order to make your mails more readable.
Summary:
Kernel is compiled with CONFIG_HAVE_HW_BREAKPOINT but after boot the DSCR register does not have monitor mode enabled which is required for debug register use.
That means that hardware breakpoints are unusable on your platform, likely
because it has been locked down in the hardware (there is a signal that
can be tied off to prevent monitor mode debug).
I am interested in using the ptrace interface for hw breakpoints/watchpoints on a Cortex A9. I found out that watchpoints are not triggering and tracked down an issue to the hw_breakpoint.c. The flow is as follows:
arch_hw_breakpoint_init > on_each_cpu(reset_ctrl_regs, &cpumask, 1);  > reset_ctrl_regs > enable_monitor_mode

enable_monitor_mode performs ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN));
Another read on dscr is performed to check if the bit was set and if not it returns -EPERM. In my case the write is not successful so it returns.

Since the reset_ctrl_regs code just returns on failure setting the monitor mode, there is no reporting of this.
if (enable_monitor_mode)
 return ret;
I'll fix this, we should print something here. Thanks.
After boot, my ptrace test example with PTRACE_GETHBPREGS works fine but PTRACE_SETHBPREGS fails silently inside arch_install_hw_breakpoint due to the same enable_monitor_mode issue.
That's probably because the monitor mode check is at *install* time, which
is asynchronous wrt the ptrace system call (i.e. when the child is next
scheduled). How about we move the check to validation time instead? We
should never try to install an unvalidated breakpoint and trying to support
hardware debuggers and software debuggers simultaneously isn't actually
support by the architecture, requiring some discipline from the guy with the
JTAG cable.

Completely untested patch below, please let me know how you get on...

Will

--->8
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index ba386bd..f513b0e 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -322,14 +322,9 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
 {
 	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
 	struct perf_event **slot, **slots;
-	int i, max_slots, ctrl_base, val_base, ret = 0;
+	int i, max_slots, ctrl_base, val_base;
 	u32 addr, ctrl;
 
-	/* Ensure that we are in monitor mode and halting mode is disabled. */
-	ret = enable_monitor_mode();
-	if (ret)
-		goto out;
-
 	addr = info->address;
 	ctrl = encode_ctrl_reg(info->ctrl) | 0x1;
 
@@ -356,10 +351,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
 		}
 	}
 
-	if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) {
-		ret = -EBUSY;
-		goto out;
-	}
+	if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n"))
+		return -EBUSY;
 
 	/* Override the breakpoint data with the step data. */
 	if (info->step_ctrl.enabled) {
@@ -378,8 +371,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
 	/* Setup the control register. */
 	write_wb_reg(ctrl_base + i, ctrl);
 
-out:
-	return ret;
+	return 0;
 }
 
 void arch_uninstall_hw_breakpoint(struct perf_event *bp)
@@ -590,6 +582,10 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
 	int ret = 0;
 	u32 offset, alignment_mask = 0x3;
 
+	/* Ensure that we are in monitor mode and halting mode is disabled. */
+	if (enable_monitor_mode())
+		return -ENODEV;
+
 	/* Build the arch_hw_breakpoint. */
 	ret = arch_build_bp_info(bp);
 	if (ret)
@@ -935,8 +931,10 @@ static void reset_ctrl_regs(void *unused)
 	isb();
 
 reset_regs:
-	if (enable_monitor_mode())
+	if (enable_monitor_mode()) {
+		pr_warning("CPU %d failed to enable monitor mode\n", cpu);
 		return;
+	}
 
 	/* We must also reset any reserved registers. */
 	raw_num_brps = get_num_brp_resources();

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Valentin Pistol <hidden>
Date: 2012-09-14 08:08:24

Hi Valentin,
Hi Will,
You might want to configure your mail client to wrap lines at 76-80 columns
in order to make your mails more readable.
Thanks for the good suggestion.
quoted
Summary:
Kernel is compiled with CONFIG_HAVE_HW_BREAKPOINT but after boot the DSCR register does not have monitor mode enabled which is required for debug register use.
That means that hardware breakpoints are unusable on your platform, likely
because it has been locked down in the hardware (there is a signal that
can be tied off to prevent monitor mode debug).
Is there a reliable way to determine that they are locked down?
Any particular register/bit I can check to confirm?
If they're really locked down I think getting a development board is
likely the only way to have full support (considering a PandaBoard).
Completely untested patch below, please let me know how you get on...
Looks good, I'll give it a try.

Thanks a lot for your help!
Valentin

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Will Deacon <hidden>
Date: 2012-09-18 10:04:39

On Fri, Sep 14, 2012 at 09:08:24AM +0100, Valentin Pistol wrote:
Is there a reliable way to determine that they are locked down?
Any particular register/bit I can check to confirm?
You can take a look at the DBGAUTHSTATUS register and try to determine the
signal values for SPNIDEN, DBGEN and NIDEN.
quoted
Completely untested patch below, please let me know how you get on...
Looks good, I'll give it a try.
Great. Let me know if it helps and, if so, I'll merge it.

Will

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Valentin Pistol <hidden>
Date: 2012-10-09 17:05:53

Will,

On Tue, Sep 18, 2012 at 3:04 AM, Will Deacon [off-list ref] wrote:
On Fri, Sep 14, 2012 at 09:08:24AM +0100, Valentin Pistol wrote:
quoted
Is there a reliable way to determine that they are locked down?
Any particular register/bit I can check to confirm?
You can take a look at the DBGAUTHSTATUS register and try to determine the
signal values for SPNIDEN, DBGEN and NIDEN.
DBGAUTHSTATUS=0xaa confirming DBGEN is LOW. Since then I found out
that there are two types of OMAP devices:
GP (General Purpose) and HS (High Security) and supposedly Debug
Capabilities are only available on GP devices.
Thus, I ordered a Pandaboard ES with OMAP4460 and tested it with a
prebuilt Ubuntu 12.04 image.
After boot monitor mode is still not set, the DSCR reads the same
0x01030002 just as with the previous Galaxy Nexus.

I contacted TI and they seem to say hw breakpoints/watchpoints are
available on Pandaboard but they are confused about monitor mode,
saying it's not available on Pandaboard GP.
See http://e2e.ti.com/support/omap/f/849/p/216276/770995.aspx for the
discussion.
Isn't monitor mode and DBGEN on HIGH required for access to
breakpoints/watchpoints?
Maybe they are thinking about Secure Monitor Mode and TrustZone which
is not related?

Have you used a Pandaboard and can comment on how to enable the
breakpoints/watchpoints?
Could you also mention a specific development board that you are using
and recommend for access to these features?
quoted
quoted
Completely untested patch below, please let me know how you get on...
Looks good, I'll give it a try.
Great. Let me know if it helps and, if so, I'll merge it.
Sorry I wasn't able to directly apply your patch to the specific
Android kernel version I was using.
Manually merging the code seems to perform as expected.

Thanks a lot for your help,
Valentin

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Will Deacon <hidden>
Date: 2012-10-09 21:08:02

On Tue, Oct 09, 2012 at 06:05:53PM +0100, Valentin Pistol wrote:
Will,
Hi Valentin,
On Tue, Sep 18, 2012 at 3:04 AM, Will Deacon [off-list ref] wrote:
quoted
On Fri, Sep 14, 2012 at 09:08:24AM +0100, Valentin Pistol wrote:
quoted
Is there a reliable way to determine that they are locked down?
Any particular register/bit I can check to confirm?
You can take a look at the DBGAUTHSTATUS register and try to determine the
signal values for SPNIDEN, DBGEN and NIDEN.
DBGAUTHSTATUS=0xaa confirming DBGEN is LOW. Since then I found out
that there are two types of OMAP devices:
GP (General Purpose) and HS (High Security) and supposedly Debug
Capabilities are only available on GP devices.
Thus, I ordered a Pandaboard ES with OMAP4460 and tested it with a
prebuilt Ubuntu 12.04 image.
After boot monitor mode is still not set, the DSCR reads the same
0x01030002 just as with the previous Galaxy Nexus.
Can you try this with my hw-breakpoint branch please? I've reworked a fair
amount of code there, so it might at least be more verbose if it fails.
I contacted TI and they seem to say hw breakpoints/watchpoints are
available on Pandaboard but they are confused about monitor mode,
saying it's not available on Pandaboard GP.
See http://e2e.ti.com/support/omap/f/849/p/216276/770995.aspx for the
discussion.
In that discussion, the TI folks are confusing `Monitor-mode Debug' with
`Secure Monitor Mode'. They are two completely different things and (for the
purposes of this discussion), unrelated. You should press them further on
this!
Have you used a Pandaboard and can comment on how to enable the
breakpoints/watchpoints?
I haven't tried it, but I do have a Panda now so I could give it a go when I
get a chance. I suspect there's something related to power-management at
play... for JTAG, you need to hack MLO as described here:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15314.html

maybe something similar is required for self-hosted (monitor mode) debug?
Could you also mention a specific development board that you are using
and recommend for access to these features?
I use the ARM Versatile Express platform, but I think it's probably quite
expensive to get hold of if you don't work for ARM.

Will

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: dietmar.eggemann@arm.com (Dietmar Eggemann)
Date: 2012-10-12 11:26:12

On 09/10/12 18:05, Valentin Pistol wrote:
Will,

On Tue, Sep 18, 2012 at 3:04 AM, Will Deacon [off-list ref] wrote:
quoted
On Fri, Sep 14, 2012 at 09:08:24AM +0100, Valentin Pistol wrote:
quoted
Is there a reliable way to determine that they are locked down?
Any particular register/bit I can check to confirm?
You can take a look at the DBGAUTHSTATUS register and try to determine the
signal values for SPNIDEN, DBGEN and NIDEN.
DBGAUTHSTATUS=0xaa confirming DBGEN is LOW. Since then I found out
that there are two types of OMAP devices:
GP (General Purpose) and HS (High Security) and supposedly Debug
Capabilities are only available on GP devices.
Thus, I ordered a Pandaboard ES with OMAP4460 and tested it with a
prebuilt Ubuntu 12.04 image.
After boot monitor mode is still not set, the DSCR reads the same
0x01030002 just as with the previous Galaxy Nexus.

I contacted TI and they seem to say hw breakpoints/watchpoints are
available on Pandaboard but they are confused about monitor mode,
saying it's not available on Pandaboard GP.
See http://e2e.ti.com/support/omap/f/849/p/216276/770995.aspx for the
discussion.
Isn't monitor mode and DBGEN on HIGH required for access to
breakpoints/watchpoints?
Maybe they are thinking about Secure Monitor Mode and TrustZone which
is not related?

Have you used a Pandaboard and can comment on how to enable the
breakpoints/watchpoints?
Could you also mention a specific development board that you are using
and recommend for access to these features?
I'm running Linaro 12.08 on Pandaboard (Rev A1) and on this board 
DBGAUTHSTATUS.NSNE and DBGAUTHSTATUS.NSE are set.

With additional logs in enable_monitor_mode() 
[arch/arm/kernel/hw_breakpoint.c]:

root at linaro-nano:~# dmesg | grep hw-break
[    0.321380] hw-breakpoint: arch_hw_breakpoint_init cpu0 debug_arch=3
[    0.321441] hw-breakpoint: enable_monitor_mode cpu1 
DBGDSCR=03070002
[    0.321441] hw-breakpoint: enable_monitor_mode cpu1 
DBGAUTHSTATUS=000000af
[    0.321502] hw-breakpoint: enable_monitor_mode cpu0 
DBGDSCR=03070002
[    0.321533] hw-breakpoint: enable_monitor_mode cpu0 
DBGAUTHSTATUS=000000af
[    0.321533] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 
watchpoint registers.
[    0.321563] hw-breakpoint: maximum watchpoint size is 4 bytes.

-- Dietmar
quoted
quoted
quoted
Completely untested patch below, please let me know how you get on...
Looks good, I'll give it a try.
Great. Let me know if it helps and, if so, I'll merge it.
Sorry I wasn't able to directly apply your patch to the specific
Android kernel version I was using.
Manually merging the code seems to perform as expected.

Thanks a lot for your help,
Valentin

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Valentin Pistol <hidden>
Date: 2012-10-15 20:48:40

Can you try this with my hw-breakpoint branch please? I've reworked a fair
amount of code there, so it might at least be more verbose if it fails.
I am trying the Linaro 12.08 images from
http://releases.linaro.org/12.08/android/leb-panda/
After testing it boots fine on my board, I replaced the uImage with
one built from your code at
git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git and
hw-breakpoint branch.

Unfortunately it gets stuck on "Uncompressing Linux... done, booting
the kernel." on the serial port.
What kernel config are you using? I'm using omap2plus_defconfig
resulting in a Linux-3.7.0-rc1-00015-gd633d80b kernel:
$ make mrproper
$ make ARCH=arm CROSS_COMPILE=arm-eabi- omap2plus_defconfig uImage

I also tried using the Linaro 12.08 kernel config from the above page:
$ make mrproper
$ cp linaro_kernel_config .config
$ make ARCH=arm CROSS_COMPILE=arm-eabi- uImage
[ accept a lot of default values due to kernel version changes ]

Then I mount the SD card and replace the uImage file yet neither uImages boot.
Here is the full serial log: http://pastebin.com/raw.php?i=YQ4vk634
In that discussion, the TI folks are confusing `Monitor-mode Debug' with
`Secure Monitor Mode'. They are two completely different things and (for the
purposes of this discussion), unrelated. You should press them further on
this!
Thanks for the clarification, I contacted them again and will see how
it turns out.
quoted
Have you used a Pandaboard and can comment on how to enable the
breakpoints/watchpoints?
I haven't tried it, but I do have a Panda now so I could give it a go when I
get a chance. I suspect there's something related to power-management at
play... for JTAG, you need to hack MLO as described here:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15314.html

maybe something similar is required for self-hosted (monitor mode) debug?
If you could give it a try on your Panda that would be great!

On Fri, Oct 12, 2012 at 7:26 AM, Dietmar Eggemann
[off-list ref] wrote:
I'm running Linaro 12.08 on Pandaboard (Rev A1) and on this board
DBGAUTHSTATUS.NSNE and DBGAUTHSTATUS.NSE are set.

With additional logs in enable_monitor_mode()
[arch/arm/kernel/hw_breakpoint.c]:

root at linaro-nano:~# dmesg | grep hw-break
[    0.321380] hw-breakpoint: arch_hw_breakpoint_init cpu0 debug_arch=3
[    0.321441] hw-breakpoint: enable_monitor_mode cpu1 DBGDSCR=03070002
[    0.321441] hw-breakpoint: enable_monitor_mode cpu1
DBGAUTHSTATUS=000000af
[    0.321502] hw-breakpoint: enable_monitor_mode cpu0 DBGDSCR=03070002
[    0.321533] hw-breakpoint: enable_monitor_mode cpu0
DBGAUTHSTATUS=000000af
[    0.321533] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1
watchpoint registers.
[    0.321563] hw-breakpoint: maximum watchpoint size is 4 bytes.
Dietmar,

That looks great! Did you flash the prebuilt images from Linaro 12.08
and replaced the kernel with those extra debug messages on top of
kernel at git://android.git.linaro.org/kernel/panda? Or are you using
Will's branch?
I am using a newer Pandaboard ES (Rev B1) and hope this is not the problem.
Could you please provide a few instructions to reproduce your setup?

Thanks!
Valentin

ARM: hw_breakpoint: silent EPERM when setting ARM_DSCR_MDBGEN on ARM_DEBUG_ARCH_V7_ECP14

From: Valentin Pistol <hidden>
Date: 2012-10-16 04:26:29

On Fri, Oct 12, 2012 at 7:26 AM, Dietmar Eggemann
[off-list ref] wrote:
quoted
I'm running Linaro 12.08 on Pandaboard (Rev A1) and on this board
DBGAUTHSTATUS.NSNE and DBGAUTHSTATUS.NSE are set.

With additional logs in enable_monitor_mode()
[arch/arm/kernel/hw_breakpoint.c]:

root at linaro-nano:~# dmesg | grep hw-break
[    0.321380] hw-breakpoint: arch_hw_breakpoint_init cpu0 debug_arch=3
[    0.321441] hw-breakpoint: enable_monitor_mode cpu1 DBGDSCR=03070002
[    0.321441] hw-breakpoint: enable_monitor_mode cpu1
DBGAUTHSTATUS=000000af
[    0.321502] hw-breakpoint: enable_monitor_mode cpu0 DBGDSCR=03070002
[    0.321533] hw-breakpoint: enable_monitor_mode cpu0
DBGAUTHSTATUS=000000af
[    0.321533] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1
watchpoint registers.
[    0.321563] hw-breakpoint: maximum watchpoint size is 4 bytes.
Dietmar,

That looks great! Did you flash the prebuilt images from Linaro 12.08
and replaced the kernel with those extra debug messages on top of
kernel at git://android.git.linaro.org/kernel/panda? Or are you using
Will's branch?
I am using a newer Pandaboard ES (Rev B1) and hope this is not the problem.
Could you please provide a few instructions to reproduce your setup?
I just tried the kernel over at
git://android.git.linaro.org/kernel/panda and used the same branch in
the prebuilt Linaro 12.08:
linaro-tilt-android-tracking e78449e OMAPFB: Asynchronous vsync notification
I used android_omap4_defconfig but CONFIG_HW_HAVE_BREAKPOINT were not
persistent in the .config so I had to manually add HW_HAVE_BREAKPOINT
to arch/arm/Kconfig under ARCH_OMAP and also add PERF_EVENTS
dependency.
Similar to Dietmar I added additional info to
arch/arm/kernel/hw_breakpoint.c and now I can confirm I see the proper
value of DSCR = 0x3078002 and DBGAUTHSTATUS = 0xaf !
Flashing this 3.2 Kernel works without a problem but I am still
interested in getting Will's branch and 3.7 Kernel working.
I tried the above on Will's branch (copy over the
android_omap4_defconfig and edit Kconfig) but the kernel is still
stuck at trying to boot.

I am wondering if I can use all 4 watchpoints available in OMAP4460.
Normally the kernel just reports 1 watchpoint available due to what I
believe is a lack of information on what watchpoint triggered. Would
it be possible to enable all 4 and have a workaround to determine
which WP triggers?

Valentin
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help