From: Anton Vorontsov <hidden> Date: 2012-08-20 14:47:14
Hi all,
In v4:
- Implemented kgdb_nmi serial driver, it provides 'nmi_console' KDB
command. With the driver we can use our debugger port as a normal
console, except that we can always get back to the debugger using the
magic sequence. Note that I still somewhat reluctant to introduce
software-raised interrupts, as they're arch-specific and not always
possible. So today the driver uses a tasklet, it should be pretty
cheap: we're checking for the input on timer interrupts, but we don't
cause needless wakeups. The pro of this is that it works everywhere
(but arches still have an option to optimize things, of course);
- Two new patches added to propagate init_poll() callbacks from tty
to uart drivers. As a side-effect, a long-standing bug fixed in
amba-pl1011 driver;
- Dropped patch 'Get rid of .LCcralign local label';
- Some more fixes in SVC return path. Now it seems rock-solid;
- The patches were rebased on the latest Linus' tree, and as usual can
be found in the following repo:
git://git.infradead.org/users/cbou/linux-nmi-kdb.git master
Boilerplate:
These patches introduce KGDB FIQ debugger support. The idea (and some
code, of course) comes from Google's FIQ debugger[2]. There are some
differences (mostly implementation details, feature-wise they're almost
equivalent, or can be made equivalent, if desired).
The FIQ debugger is a facility that can be used to debug situations when
the kernel stuck in uninterruptable sections, e.g. the kernel infinitely
loops or deadlocked in an interrupt or with interrupts disabled. On some
development boards there is even a special NMI button, which is very
useful for debugging weird kernel hangs.
And FIQ is basically an NMI, it has a higher priority than IRQs, and
upon IRQ exception FIQs are not disabled. It is still possible to
disable FIQs (as well as some "NMIs" on other architectures), but via
special means.
So, here FIQs and NMIs are synonyms, but in the code I use NMI term for
arch-independent code, and FIQs for ARM code.
A few years ago KDB wasn't yet ready for production, or even not
well-known, so originally Google implemented its own FIQ debugger that
included its own shell, ring-buffer, commands, dumping, backtracing
logic and whatnot. This is very much like PowerPC's xmon
(arch/powerpc/xmon), except that xmon was there for a decade, so it even
predates KDB.
Anyway, nowadays KGDB/KDB is the cross-platform debugger, and the only
feature that was missing is NMI handling. This is now fixed for ARM.
There are a few differences comparing to the original (Google's) FIQ
debugger:
- Doing stuff in FIQ context is dangerous, as there we are not allowed
to cause aborts or faults. In the original FIQ debugger there was a
"signal" software-induced interrupt, upon exit from FIQ it would fire,
and we would continue to execute "dangerous" commands from there.
In KGDB/KDB we don't use signal interrupts. We can do easier: set up a
breakpoint, continue, and you'll trap into KGDB again in a safe
context.
It works for most cases, but I can imagine cases when you can't set up
a breakpoint. For these cases we'd better introduce a KDB command
"exit_nmi", that will rise the SW IRQ, after which we're allowed to do
anything.
- KGDB/KDB FIQ debugger shell is synchronous. In Google's version you
could have a dedicated shell always running in the FIQ context, so
when you type something on a serial line, you won't actually cause any
debugging actions, FIQ would save the characters in its own buffer and
continue execution normally. But when you hit return key after the
command, then the command is executed.
In KGDB/KDB FIQ debugger it is different. Once you enter KGDB, the
kernel will stop until you instruct it to continue.
This might look as a drastic change, but it is not. There is actually
no difference whether you have sync or async shell, or at least I
couldn't find any use-case where this would matter at all. Anyways, it
is still possible to do async shell in KDB, just don't see any need
for this.
- Original FIQ debugger used a custom FIQ vector handling code, w/ a lot
of logic in it. In this approach I'm using the fact that FIQs are
basically IRQs, except that we there are a bit more registers banked,
and we can actually trap from the IRQ context.
But this all does not prevent us from using a simple jump-table based
approach as used in the generic ARM entry code. So, here I just reuse
the generic approach.
Note that I test the code on a modelled ARM machine (QEMU Versatile), so
there might be some issues on a real HW, but it works in QEMU tho. :-)
Assuming you have QEMU >= 1.1.0, you can easily play with the code using
ARM/versatile defconfig and command like this:
qemu-system-arm -nographic -machine versatilepb -kernel
linux/arch/arm/boot/zImage -append "console=ttyAMA0 kgdboc=ttyAMA0
kgdb_fiq.enable=1"
Thanks,
--
arch/arm/Kconfig | 19 ++
arch/arm/common/vic.c | 28 +++
arch/arm/include/asm/hardware/vic.h | 2 +
arch/arm/include/asm/kgdb.h | 8 +
arch/arm/kernel/Makefile | 1 +
arch/arm/kernel/entry-armv.S | 167 +----------------
arch/arm/kernel/entry-header.S | 170 ++++++++++++++++++
arch/arm/kernel/kgdb_fiq.c | 99 ++++++++++
arch/arm/kernel/kgdb_fiq_entry.S | 87 +++++++++
arch/arm/mach-versatile/Makefile | 1 +
arch/arm/mach-versatile/kgdb_fiq.c | 31 ++++
drivers/tty/serial/Kconfig | 19 ++
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/amba-pl011.c | 60 +++++--
drivers/tty/serial/kgdb_nmi.c | 348 ++++++++++++++++++++++++++++++++++++
drivers/tty/serial/kgdboc.c | 16 ++
drivers/tty/serial/serial_core.c | 30 ++++
include/linux/kdb.h | 29 +--
include/linux/kgdb.h | 34 ++++
include/linux/serial_core.h | 2 +
include/linux/tty_driver.h | 1 +
kernel/debug/debug_core.c | 36 +++-
kernel/debug/kdb/kdb_main.c | 29 +++
23 files changed, 1024 insertions(+), 194 deletions(-)
In v3:
- Per Colin Cross suggestion, added a way to release a debug console for
normal use. This is done via 'disable_nmi' command (in the original
FIQ debugger it was 'console' command). For this I added a new
callback in the tty ops, and serial drivers have to provide a way to
clear its interrupts. The patch 'tty/serial/kgdboc: Add and wire up
clear_irqs callback' explains the concept in details.
- Made the debug entry prompt more shell-like;
- A new knocking mode '-1'. It disables the feature altogether, and thus
makes it possible to hook KDB entry to a dedicated button.
- The code was rebased on 'v3.5 + kdb kiosk'[1] patches;
In v2:
- Per Colin Cross' suggestion, we should not enter the debugger on any
received byte (this might be a problem when there's a noise on the
serial line). So there is now an additional patch that implements
"knocking" to the KDB (either via $3#33 command or return key, this is
configurable);
- Reworked {enable,select}_fiq/is_fiq callbacks, now multi-mach kernels
should not be a problem;
- For versatile machines there are run-time checks for proper UART port
(kernel will scream aloud if out of range port is specified);
- Added some __init annotations;
- Since not every architecture defines FIQ_START, we can't just blindly
select CONFIG_FIQ symbol. So ARCH_MIGHT_HAVE_FIQ introduced;
- Add !THUMB2_KERNEL dependency for KGDB_FIQ, we don't support Thumb2
kernels;
- New patch that is used to get rid of LCcralign label in alignment_trap
macro.
[1] https://lkml.org/lkml/2012/7/26/260
[2]
Original Google's FIQ debugger, fiq_* files:
http://android.git.linaro.org/gitweb?p=kernel/common.git;a=tree;f=arch/arm/common;hb=refs/heads/android-3.4
And board support as an example of using it:
http://nv-tegra.nvidia.com/gitweb/?p=linux-2.6.git;a=commitdiff;h=461cb80c16e4e266ab6207a00767b59212148086
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:50:08
The new arch callback should manage NMIs that usually cause KGDB to
enter. That is, not all NMIs should be enabled/disabled, but only
those that issue kgdb_handle_exception().
We must mask it as serial-line interrupt can be used as an NMI, so
if the original KGDB-entry cause was say a breakpoint, then every
input to KDB console will cause KGDB to reenter, which we don't want.
Signed-off-by: Anton Vorontsov <redacted>
---
include/linux/kgdb.h | 23 +++++++++++++++++++++++
kernel/debug/debug_core.c | 36 +++++++++++++++++++++++++++++++++---
2 files changed, 56 insertions(+), 3 deletions(-)
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:50:13
This makes the stubs actually usable, since e.g. 'foo = kdb_register();'
leads to build errors in !KGDB_KDB case. Plus, with static inlines we
do type checking.
Signed-off-by: Anton Vorontsov <redacted>
---
include/linux/kdb.h | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
@@ -13,6 +13,14 @@*Copyright(C)2009JasonWessel<jason.wessel@windriver.com>*/+typedefenum{+KDB_REPEAT_NONE=0,/* Do not repeat this command */+KDB_REPEAT_NO_ARGS,/* Repeat the command without arguments */+KDB_REPEAT_WITH_ARGS,/* Repeat the command including its arguments */+}kdb_repeat_t;++typedefint(*kdb_func_t)(int,constchar**);+#ifdef CONFIG_KGDB_KDB#include<linux/init.h>#include<linux/sched.h>
@@ -32,14 +40,6 @@ extern atomic_t kdb_event;#define KDB_MAXARGS 16 /* Maximum number of arguments to a function */-typedefenum{-KDB_REPEAT_NONE=0,/* Do not repeat this command */-KDB_REPEAT_NO_ARGS,/* Repeat the command without arguments */-KDB_REPEAT_WITH_ARGS,/* Repeat the command including its arguments */-}kdb_repeat_t;--typedefint(*kdb_func_t)(int,constchar**);-/* KDB return codes from a command or internal kdb function */#define KDB_NOTFOUND (-1)#define KDB_ARGCOUNT (-2)
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:50:16
This command disables NMI-entry. If NMI source has been previously shared
with a serial console ("debug port"), this effectively releases the port
from KDB exclusive use, and makes the console available for normal use.
Of course, NMI can be reenabled, enable_nmi modparam is used for that:
echo 1 > /sys/module/kdb/parameters/enable_nmi
Signed-off-by: Anton Vorontsov <redacted>
---
kernel/debug/kdb/kdb_main.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
@@ -2107,6 +2108,32 @@ static int kdb_dmesg(int argc, const char **argv)return0;}#endif /* CONFIG_PRINTK */++/* Make sure we balance enable/disable calls, must disable first. */+staticatomic_tkdb_nmi_disabled;++staticintkdb_disable_nmi(intargc,constchar*argv[])+{+if(atomic_read(&kdb_nmi_disabled))+return0;+atomic_set(&kdb_nmi_disabled,1);+kgdb_enable_nmi(0);+return0;+}++staticintkdb_param_enable_nmi(constchar*val,conststructkernel_param*kp)+{+if(!atomic_add_unless(&kdb_nmi_disabled,-1,0))+return-EINVAL;+kgdb_enable_nmi(1);+return0;+}++staticconststructkernel_param_opskdb_param_ops_enable_nmi={+.set=kdb_param_enable_nmi,+};+module_param_cb(enable_nmi,&kdb_param_ops_enable_nmi,NULL,0600);+/**kdb_cpu-Thisfunctionimplementsthe'cpu'command.*cpu[<cpunum>]
@@ -2851,6 +2878,8 @@ static void __init kdb_inittab(void)kdb_register_repeat("dmesg",kdb_dmesg,"[lines]","Display syslog buffer",0,KDB_REPEAT_NONE);#endif+kdb_register_repeat("disable_nmi",kdb_disable_nmi,"",+"Disable NMI entry to KDB",0,KDB_REPEAT_NONE);kdb_register_repeat("defcmd",kdb_defcmd,"name \"usage\"\"help\"","Define a set of commands, down to endefcmd",0,KDB_REPEAT_NONE);kdb_register_repeat("kill",kdb_kill,"<-signal> <pid>",
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:50:20
It was noticed that polling drivers (like KGDB) are not able to use
serial ports if the ports were not previously initialized via console.
I.e. when booting with console=ttyAMA0 kgdboc=ttyAMA0, everything works
fine, but with console=ttyFOO kgdboc=ttyAMA0, the kgdboc doesn't work.
This is because we don't initialize the hardware. Calling ->startup() is
not an option, because drivers request interrupts there, and drivers
fail to handle situations when tty isn't opened with interrupts enabled.
So, we have to implement a new callback (actually, tty_ops already have
a similar callback), which does everything needed to initialize just the
hardware.
Signed-off-by: Anton Vorontsov <redacted>
---
drivers/tty/serial/serial_core.c | 15 +++++++++++++++
include/linux/serial_core.h | 1 +
2 files changed, 16 insertions(+)
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:50:27
Just a couple of calls to manage VIC FIQ routing. We'll use them for
KGDB FIQ support on ARM Versatile machines.
Signed-off-by: Anton Vorontsov <redacted>
---
arch/arm/common/vic.c | 28 ++++++++++++++++++++++++++++
arch/arm/include/asm/hardware/vic.h | 2 ++
2 files changed, 30 insertions(+)
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:50:43
If enabled, kernel will able to enter KGDB upon serial line activity on
UART ports.
Note that even with this patch and CONFIG_KGDB_FIQ is enabled, you still
need to pass kgdb_fiq.enable=1 kernel command line option, otherwise UART
will behave in a normal way.
By default UART0 is used, but this can be changed via kgdb_fiq.uart_num
kernel command line option.
Signed-off-by: Anton Vorontsov <redacted>
---
arch/arm/Kconfig | 1 +
arch/arm/mach-versatile/Makefile | 1 +
arch/arm/mach-versatile/kgdb_fiq.c | 31 +++++++++++++++++++++++++++++++
3 files changed, 33 insertions(+)
create mode 100644 arch/arm/mach-versatile/kgdb_fiq.c
@@ -0,0 +1,31 @@+/*+*KGDBFIQboardsupport+*+*Copyright2012LinaroLtd.+*AntonVorontsov<anton.vorontsov@linaro.org>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsoftheGNUGeneralPublicLicenseversion2aspublished+*bytheFreeSoftwareFoundation.+*/++#include<linux/module.h>+#include<linux/init.h>+#include<linux/kgdb.h>+#include<mach/hardware.h>+#include<mach/platform.h>+#include<asm/hardware/vic.h>++staticintkgdb_fiq;+module_param_named(uart_num,kgdb_fiq,int,0600);+MODULE_PARM_DESC(uart_num,"UART<number> port to use for KGDB FIQ");++staticint__initkgdb_fiq_init(void)+{+WARN_ON(kgdb_fiq>INT_UARTINT2-INT_UARTINT0);++returnkgdb_register_fiq(INT_UARTINT0+kgdb_fiq,+vic_fiq_select,+vic_is_fiq_rised);+}+console_initcall(kgdb_fiq_init);
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:51:34
The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.
By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.
Signed-off-by: Anton Vorontsov <redacted>
---
arch/arm/Kconfig | 18 ++++++++
arch/arm/include/asm/kgdb.h | 8 ++++
arch/arm/kernel/Makefile | 1 +
arch/arm/kernel/kgdb_fiq.c | 99 ++++++++++++++++++++++++++++++++++++++++
arch/arm/kernel/kgdb_fiq_entry.S | 87 +++++++++++++++++++++++++++++++++++
5 files changed, 213 insertions(+)
create mode 100644 arch/arm/kernel/kgdb_fiq.c
create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,99 @@+/*+*KGDBFIQ+*+*Copyright2010Google,Inc.+*ArveHj?nnev?g<arve@android.com>+*ColinCross<ccross@android.com>+*Copyright2012LinaroLtd.+*AntonVorontsov<anton.vorontsov@linaro.org>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsoftheGNUGeneralPublicLicenseversion2aspublished+*bytheFreeSoftwareFoundation.+*/++#include<linux/kernel.h>+#include<linux/module.h>+#include<linux/init.h>+#include<linux/slab.h>+#include<linux/errno.h>+#include<linux/hardirq.h>+#include<linux/kdb.h>+#include<linux/kgdb.h>+#include<asm/fiq.h>+#include<asm/exception.h>++staticintkgdb_fiq_enabled;+module_param_named(enable,kgdb_fiq_enabled,int,0600);+MODULE_PARM_DESC(enable,"set to 1 to enable FIQ KGDB");++staticunsignedintkgdb_fiq;+staticbool(*is_kgdb_fiq)(unsignedintirq);++asmlinkagevoid__exception_irq_entrykgdb_fiq_do_handle(structpt_regs*regs)+{+if(!is_kgdb_fiq(kgdb_fiq))+return;+if(!kgdb_nmi_poll_knock())+return;++nmi_enter();+kgdb_handle_exception(1,0,0,regs);+nmi_exit();+}++staticstructfiq_handlerkgdb_fiq_desc={+.name="kgdb",+};++staticlongkgdb_fiq_setup_stack(void*info)+{+structpt_regsregs;++regs.ARM_sp=__get_free_pages(GFP_KERNEL,THREAD_SIZE_ORDER)++THREAD_START_SP;+WARN_ON(!regs.ARM_sp);++set_fiq_regs(®s);+return0;+}++staticvoid(*kgdb_enable_fiq)(unsignedintirq,boolon);++voidkgdb_arch_enable_nmi(boolon)+{+if(!kgdb_enable_fiq)+return;+kgdb_enable_fiq(kgdb_fiq,on);+}++int__initkgdb_register_fiq(unsignedintmach_kgdb_fiq,+void(*mach_kgdb_enable_fiq)(unsignedintirq,boolon),+bool(*mach_is_kgdb_fiq)(unsignedintirq))+{+interr;+intcpu;++if(!kgdb_fiq_enabled)+return-ENODEV;+if(kgdb_fiq)+return-EBUSY;++kgdb_fiq=mach_kgdb_fiq;+kgdb_enable_fiq=mach_kgdb_enable_fiq;+is_kgdb_fiq=mach_is_kgdb_fiq;++err=claim_fiq(&kgdb_fiq_desc);+if(err){+pr_warn("%s: unable to claim fiq",__func__);+returnerr;+}++for_each_possible_cpu(cpu)+work_on_cpu(cpu,kgdb_fiq_setup_stack,NULL);++set_fiq_handler(&kgdb_fiq_handler,+&kgdb_fiq_handler_end-&kgdb_fiq_handler);++return0;+}
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:51:38
Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.
The following macros were moved:
- svc_entry
- usr_entry
- kuser_cmpxchg_check
- vector_stub
To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.
Signed-off-by: Anton Vorontsov <redacted>
---
arch/arm/kernel/entry-armv.S | 167 +---------------------------------------
arch/arm/kernel/entry-header.S | 170 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 171 insertions(+), 166 deletions(-)
@@ -136,57 +136,6 @@ common_invalid:bbad_modeENDPROC(__und_invalid)-/*-*SVCmodehandlers-*/--#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)-#define SPFIX(code...) code-#else-#define SPFIX(code...)-#endif--.macrosvc_entry,stack_hole=0-UNWIND(.fnstart)-UNWIND(.save{r0-pc})-subsp,sp,#(S_FRAME_SIZE + \stack_hole - 4)-#ifdef CONFIG_THUMB2_KERNEL-SPFIX(strr0,[sp])@temporarilysaved-SPFIX(movr0,sp)-SPFIX(tstr0,#4 ) @ test original stack alignment-SPFIX(ldrr0,[sp])@restored-#else-SPFIX(tstsp,#4 )-#endif-SPFIX(subeqsp,sp,#4 )-stmiasp,{r1-r12}--ldmiar0,{r3-r5}-addr7,sp,#S_SP - 4 @ here for interlock avoidance-movr6,#-1 @ "" "" "" ""-addr2,sp,#(S_FRAME_SIZE + \stack_hole - 4)-SPFIX(addeqr2,r2,#4 )-strr3,[sp,#-4]! @ save the "real" r0 copied-@fromtheexceptionstack--movr3,lr--@-@Wearenowreadytofillintheremainingblanksonthestack:-@-@r2-sp_svc-@r3-lr_svc-@r4-lr_<exception>,alreadyfixedupforcorrectreturn/restart-@r5-spsr_<exception>-@r6-orig_r0 (seept_regsdefinitioninptrace.h)-@-stmiar7,{r2-r6}--#ifdef CONFIG_TRACE_IRQFLAGS-bltrace_hardirqs_off-#endif-.endm-.align5 __dabt_svc:svc_entry
@@ -348,71 +297,8 @@ ENDPROC(__pabt_svc)/**Usermodehandlers-*-*EABInote:sp_svcisalways64-bitalignedhere,soshouldS_FRAME_SIZE*/-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)-#error "sizeof(struct pt_regs) must be a multiple of 8"-#endif--.macrousr_entry-UNWIND(.fnstart)-UNWIND(.cantunwind)@don't unwind the user space-subsp,sp,#S_FRAME_SIZE-ARM(stmibsp,{r1-r12})-THUMB(stmiasp,{r0-r12})--ldmiar0,{r3-r5}-addr0,sp,#S_PC @ here for interlock avoidance-movr6,#-1 @ "" "" "" ""--strr3,[sp]@savethe"real"r0copied-@fromtheexceptionstack--@-@Wearenowreadytofillintheremainingblanksonthestack:-@-@r4-lr_<exception>,alreadyfixedupforcorrectreturn/restart-@r5-spsr_<exception>-@r6-orig_r0 (seept_regsdefinitioninptrace.h)-@-@Also,separatelysavesp_usrandlr_usr-@-stmiar0,{r4-r6}-ARM(stmdbr0,{sp,lr}^)-THUMB(store_user_sp_lrr0,r1,S_SP-S_PC)--@-@Enablethealignmenttrapwhileinkernelmode-@-alignment_trapr0--@-@ClearFPtomarkthefirststackframe-@-zero_fp--#ifdef CONFIG_IRQSOFF_TRACER-bltrace_hardirqs_off-#endif-.endm--.macrokuser_cmpxchg_check-#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)-#ifndef CONFIG_MMU-#warning "NPTL on non MMU needs fixing"-#else-@Makesureouruserspaceatomichelperisrestarted-@ifitwasinterruptedinacriticalregion.Herewe-@performaquicktestinlinesinceitshouldbefalse-@99.9999%ofthetime.Therestisdoneoutofline.-cmpr4,#TASK_SIZE-blhskuser_cmpxchg64_fixup-#endif-#endif-.endm-.align5 __dabt_usr:usr_entry
@@ -73,6 +73,109 @@msrcpsr_c,\rtemp@switchbacktotheSVCmode.endm+/*+*Vectorstubs.+*+*Thiscodeiscopiedto0xffff0200sowecanusebranchesinthe+*vectors,ratherthanldr's. Note that this code must not+*exceed0x300bytes.+*+*Commonstubentrymacro:+*EnterinIRQmode,spsr=SVC/USRCPSR,lr=SVC/USRPC+*+*SPpointstoaminimalamountofprocessor-privatememory,theaddress+*ofwhichiscopiedintor0forthemodespecificaborthandler.+*/+.macrovector_stub,name,mode,correction=0+.align5++vector_\name:+.if\correction+sublr,lr,#\correction+.endif++@+@Saver0,lr_<exception>(parentPC)andspsr_<exception>+@(parentCPSR)+@+stmiasp,{r0,lr}@saver0,lr+mrslr,spsr+strlr,[sp,#8] @ save spsr++@+@PrepareforSVC32mode.IRQsremaindisabled.+@+mrsr0,cpsr+eorr0,r0,#(\mode ^ SVC_MODE | PSR_ISETSTATE)+msrspsr_cxsf,r0++@+@thebranchtablemustimmediatelyfollowthiscode+@+andlr,lr,#0x0f+THUMB(adrr0,1f)+THUMB(ldrlr,[r0,lr,lsl#2] )+movr0,sp+ARM(ldrlr,[pc,lr,lsl#2] )+movspc,lr@branchtohandlerinSVCmode+ENDPROC(vector_\name)++.align2+@handleraddressesfollowthislabel+1:+.endm++/*+*SVCmodehandlers+*/++#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)+#define SPFIX(code...) code+#else+#define SPFIX(code...)+#endif++.macrosvc_entry,stack_hole=0+UNWIND(.fnstart)+UNWIND(.save{r0-pc})+subsp,sp,#(S_FRAME_SIZE + \stack_hole - 4)+#ifdef CONFIG_THUMB2_KERNEL+SPFIX(strr0,[sp])@temporarilysaved+SPFIX(movr0,sp)+SPFIX(tstr0,#4 ) @ test original stack alignment+SPFIX(ldrr0,[sp])@restored+#else+SPFIX(tstsp,#4 )+#endif+SPFIX(subeqsp,sp,#4 )+stmiasp,{r1-r12}++ldmiar0,{r3-r5}+addr7,sp,#S_SP - 4 @ here for interlock avoidance+movr6,#-1 @ "" "" "" ""+addr2,sp,#(S_FRAME_SIZE + \stack_hole - 4)+SPFIX(addeqr2,r2,#4 )+strr3,[sp,#-4]! @ save the "real" r0 copied+@fromtheexceptionstack++movr3,lr++@+@Wearenowreadytofillintheremainingblanksonthestack:+@+@r2-sp_svc+@r3-lr_svc+@r4-lr_<exception>,alreadyfixedupforcorrectreturn/restart+@r5-spsr_<exception>+@r6-orig_r0 (seept_regsdefinitioninptrace.h)+@+stmiar7,{r2-r6}++#ifdef CONFIG_TRACE_IRQFLAGS+bltrace_hardirqs_off+#endif+.endm+#ifndef CONFIG_THUMB2_KERNEL.macrosvc_exit,rpsrmsrspsr_cxsf,\rpsr
@@ -164,6 +267,73 @@#endif /* !CONFIG_THUMB2_KERNEL *//*+*Usermodehandlers+*+*EABInote:sp_svcisalways64-bitalignedhere,soshouldS_FRAME_SIZE+*/++#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)+#error "sizeof(struct pt_regs) must be a multiple of 8"+#endif++.macrousr_entry+UNWIND(.fnstart)+UNWIND(.cantunwind)@don't unwind the user space+subsp,sp,#S_FRAME_SIZE+ARM(stmibsp,{r1-r12})+THUMB(stmiasp,{r0-r12})++ldmiar0,{r3-r5}+addr0,sp,#S_PC @ here for interlock avoidance+movr6,#-1 @ "" "" "" ""++strr3,[sp]@savethe"real"r0copied+@fromtheexceptionstack++@+@Wearenowreadytofillintheremainingblanksonthestack:+@+@r4-lr_<exception>,alreadyfixedupforcorrectreturn/restart+@r5-spsr_<exception>+@r6-orig_r0 (seept_regsdefinitioninptrace.h)+@+@Also,separatelysavesp_usrandlr_usr+@+stmiar0,{r4-r6}+ARM(stmdbr0,{sp,lr}^)+THUMB(store_user_sp_lrr0,r1,S_SP-S_PC)++@+@Enablethealignmenttrapwhileinkernelmode+@+alignment_trapr0++@+@ClearFPtomarkthefirststackframe+@+zero_fp++#ifdef CONFIG_IRQSOFF_TRACER+bltrace_hardirqs_off+#endif+.endm++.macrokuser_cmpxchg_check+#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)+#ifndef CONFIG_MMU+#warning "NPTL on non MMU needs fixing"+#else+@Makesureouruserspaceatomichelperisrestarted+@ifitwasinterruptedinacriticalregion.Herewe+@performaquicktestinlinesinceitshouldbefalse+@99.9999%ofthetime.Therestisdoneoutofline.+cmpr4,#TASK_SIZE+blhskuser_cmpxchg64_fixup+#endif+#endif+.endm++/**Thesearetheregistersusedinthesyscallhandler,andallowusto*haveintheoryupto7argumentstoafunction-r0tor6.*
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:53:04
This special driver makes it possible to temporary use NMI debugger port
as a normal console by issuing 'nmi_console' command (assuming that the
port is attached to KGDB).
Unlike KDB's disable_nmi command, with this driver you are always able
to go back to the debugger using KGDB escape sequence ($3#33). This is
because this console driver processes the input in NMI context, and thus
is able to intercept the magic sequence.
Note that since the console interprets input and uses polling
communication methods, for things like PPP it is still better to fully
detach debugger port from the KGDB NMI (i.e. disable_nmi), and use raw
console.
Usually, to enter the debugger one have to type the magic sequence, so
initially the kernel will print the following prompt on the NMI debugger
console:
Type $3#33 to enter the debugger>
For convenience, there is a kgdb_fiq.knock kernel command line option,
when set to 0, this turns the special command to just a return key
press, so the kernel will be printing this:
Hit <return> to enter the debugger>
This is more convenient for long debugging sessions, although it makes
nmi_console feature somewhat useless.
And for the cases when NMI connected to a dedicated button, the knocking
can be disabled altogether by setting kgdb_fiq.knock to -1.
Suggested-by: Colin Cross <redacted>
Signed-off-by: Anton Vorontsov <redacted>
---
drivers/tty/serial/Kconfig | 19 +++
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/kgdb_nmi.c | 348 ++++++++++++++++++++++++++++++++++++++++++
drivers/tty/serial/kgdboc.c | 6 +
include/linux/kgdb.h | 10 ++
5 files changed, 384 insertions(+)
create mode 100644 drivers/tty/serial/kgdb_nmi.c
@@ -0,0 +1,348 @@+/*+*KGDBNMIserialconsole+*+*Copyright2010Google,Inc.+*ArveHj?nnev?g<arve@android.com>+*ColinCross<ccross@android.com>+*Copyright2012LinaroLtd.+*AntonVorontsov<anton.vorontsov@linaro.org>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsoftheGNUGeneralPublicLicenseversion2aspublished+*bytheFreeSoftwareFoundation.+*/++#include<linux/kernel.h>+#include<linux/module.h>+#include<linux/compiler.h>+#include<linux/init.h>+#include<linux/slab.h>+#include<linux/errno.h>+#include<linux/mutex.h>+#include<linux/atomic.h>+#include<linux/console.h>+#include<linux/tty.h>+#include<linux/tty_driver.h>+#include<linux/tty_flip.h>+#include<linux/interrupt.h>+#include<linux/hrtimer.h>+#include<linux/tick.h>+#include<linux/kfifo.h>+#include<linux/kgdb.h>+#include<linux/kdb.h>++staticintkgdb_nmi_knock=1;+module_param_named(knock,kgdb_nmi_knock,int,0600);+MODULE_PARM_DESC(knock,"if set to 1 (default), the special '$3#33' command "+"must be used to enter the debugger; when set to 0, "+"hitting return key is enough to enter the debugger; "+"when set to -1, the debugger is entered immediately "+"upon NMI");++staticboolkgdb_nmi_tty_enabled;++staticvoidkgdb_nmi_console_write(structconsole*co,constchar*s,uintc)+{+inti;++if(!kgdb_nmi_tty_enabled||atomic_read(&kgdb_active)>=0)+return;++for(i=0;i<c;i++)+dbg_io_ops->write_char(s[i]);+}++staticstructtty_driver*kgdb_nmi_tty_driver;++staticstructtty_driver*kgdb_nmi_console_device(structconsole*co,int*idx)+{+*idx=co->index;+returnkgdb_nmi_tty_driver;+}++staticstructconsolekgdb_nmi_console={+.name="ttyNMI",+.write=kgdb_nmi_console_write,+.device=kgdb_nmi_console_device,+.flags=CON_PRINTBUFFER|CON_ANYTIME|CON_ENABLED,+.index=-1,+};++/*+*Thisisusuallythemaximumrateondebugports.Wemakefifolargeenough+*tomakecopy-pastingtotheterminalusable.+*/+#define KGDB_NMI_BAUD 115200+#define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)++structkgdb_nmi_tty_priv{+intopened;+structtty_struct*tty;+structtasklet_structtlet;+STRUCT_KFIFO(char,KGDB_NMI_FIFO_SIZE)fifo;+};++/*+*Ourdebuggingconsoleispolledinatasklet,sowe'llcheckforinput+*everytick.InHZ-lessmode,weshouldprogramthenexttick.Wehave+*tousethelowlevelstuffasnolocksshouldbegrabbed.+*/+#ifdef CONFIG_HIGH_RES_TIMERS+staticvoidkgdb_tty_poke(void)+{+tick_program_event(ktime_get(),0);+}+#else+staticinlinevoidkgdb_tty_poke(void){}+#endif++staticstructtty_struct*kgdb_nmi_tty;++staticvoidkgdb_tty_recv(intch)+{+structkgdb_nmi_tty_priv*priv;+charc=ch;++if(!kgdb_nmi_tty||ch<0)+return;++priv=kgdb_nmi_tty->driver_data;+kfifo_in(&priv->fifo,&c,1);+kgdb_tty_poke();+}++staticintkgdb_nmi_poll_one_knock(void)+{+staticintn;+intc=-1;+charmagic[]="$3#33";+size_tm=strlen(magic);+boolprintch=0;++c=dbg_io_ops->read_char();+if(c==NO_POLL_CHAR)+returnc;++if(!kgdb_nmi_knock&&(c=='\r'||c=='\n')){+return1;+}elseif(c==magic[n]){+n=(n+1)%m;+if(!n)+return1;+printch=1;+}else{+n=0;+}++if(kgdb_nmi_tty_enabled){+kgdb_tty_recv(c);+return0;+}++if(printch){+kdb_printf("%c",c);+return0;+}++kdb_printf("\r%s %s to enter the debugger> %*s",+kgdb_nmi_knock?"Type":"Hit",+kgdb_nmi_knock?magic:"<return>",m,"");+memset(magic,'\b',m);+kdb_printf("%s",magic);+return0;+}++/**+*kgdb_nmi_poll_knock-Checkifitistimetoenterthedebugger+*+*"Serial ports are often noisy, especially when muxed over another port (we+*oftenuseserialovertheheadsetconnector).Noiseontheasynccommand+*linejustcausescharactersthatareignored,onacommandlinethatblocked+*executionnoisewouldbecatastrophic." -- Colin Cross+*+*So,thisfunctionimplementsKGDB/KDBknockingontheserialline:wewon't+*enterthedebuggeruntilwereceiveaknownmagicphrase(whichisactually+*"$3#33",knownas"escape to KDB"command.Thereisalsoarelaxedvariant+*ofknocking,i.e.justpressingthereturnkeyisenoughtoenterthe+*debugger.Andifknockingisdisabled,thefunctionalwaysreturns1.+*/+boolkgdb_nmi_poll_knock(void)+{+if(kgdb_nmi_knock<0)+return1;++dbg_io_ops->clear_irqs();++while(1){+intret;++ret=kgdb_nmi_poll_one_knock();+if(ret==NO_POLL_CHAR)+return0;+elseif(ret==1)+break;+}+return1;+}++staticvoidkgdb_nmi_tty_receiver(unsignedlongdata)+{+structkgdb_nmi_tty_priv*priv=(void*)data;+charch;++tasklet_schedule(&priv->tlet);++if(likely(!kgdb_nmi_tty_enabled||!kfifo_len(&priv->fifo)))+return;++while(kfifo_out(&priv->fifo,&ch,1))+tty_insert_flip_char(priv->tty,ch,TTY_NORMAL);+tty_flip_buffer_push(priv->tty);+}++staticDEFINE_MUTEX(kgdb_nmi_tty_mutex);++staticintkgdb_nmi_tty_open(structtty_struct*tty,structfile*file)+{+structkgdb_nmi_tty_priv*priv;+intret=0;++mutex_lock(&kgdb_nmi_tty_mutex);++priv=tty->driver_data;+if(priv)+gotoout;++priv=kzalloc(sizeof(*priv),GFP_KERNEL);+if(!priv){+ret=-ENOMEM;+gotoerr;+}++kgdb_nmi_tty=tty;+priv->tty=tty;+INIT_KFIFO(priv->fifo);+tty->driver_data=priv;++/*+*Thetaskletischeap,itdoesnotcausewakeupswhenreschedules+*itself,insteaditwaitsforthenexttick.+*/+tasklet_init(&priv->tlet,kgdb_nmi_tty_receiver,(unsignedlong)priv);+tasklet_schedule(&priv->tlet);+out:+priv->opened++;+err:+mutex_unlock(&kgdb_nmi_tty_mutex);+returnret;+}++staticvoidkgdb_nmi_tty_close(structtty_struct*tty,structfile*file)+{+structkgdb_nmi_tty_priv*priv;++mutex_lock(&kgdb_nmi_tty_mutex);++priv=tty->driver_data;+if(--priv->opened)+gotoout;++tasklet_kill(&priv->tlet);+kgdb_nmi_tty=NULL;+kfree(priv);+out:+mutex_unlock(&kgdb_nmi_tty_mutex);+}++staticintkgdb_nmi_tty_write_room(structtty_struct*tty)+{+/* Actually, we can handle any amount as we use polled writes. */+return2048;+}++staticintkgdb_nmi_tty_write(structtty_struct*tty,constunchar*buf,intc)+{+inti;++for(i=0;i<c;i++)+dbg_io_ops->write_char(buf[i]);+returnc;+}++staticconststructtty_operationskgdb_nmi_tty_ops={+.open=kgdb_nmi_tty_open,+.close=kgdb_nmi_tty_close,+.write_room=kgdb_nmi_tty_write_room,+.write=kgdb_nmi_tty_write,+};++staticintkgdb_nmi_enable_console(intargc,constchar*argv[])+{+kgdb_nmi_tty_enabled=!(argc==1&&!strcmp(argv[1],"off"));+return0;+}++intkgdb_register_nmi_console(void)+{+intret;++kgdb_nmi_tty_driver=alloc_tty_driver(1);+if(!kgdb_nmi_tty_driver){+pr_err("%s: cannot allocate tty\n",__func__);+return-ENOMEM;+}+kgdb_nmi_tty_driver->driver_name="ttyNMI";+kgdb_nmi_tty_driver->name="ttyNMI";+kgdb_nmi_tty_driver->type=TTY_DRIVER_TYPE_SERIAL;+kgdb_nmi_tty_driver->subtype=SERIAL_TYPE_NORMAL;+kgdb_nmi_tty_driver->flags=TTY_DRIVER_REAL_RAW|+TTY_DRIVER_DYNAMIC_DEV;+kgdb_nmi_tty_driver->init_termios=tty_std_termios;+tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,+KGDB_NMI_BAUD,KGDB_NMI_BAUD);+tty_set_operations(kgdb_nmi_tty_driver,&kgdb_nmi_tty_ops);++ret=tty_register_driver(kgdb_nmi_tty_driver);+if(ret){+pr_err("%s: unable to register tty: %d\n",__func__,ret);+gotoerr_tty_reg;+}++ret=kdb_register("nmi_console",kgdb_nmi_enable_console,"[off]",+"switch to Linux NMI console",0);+if(ret){+pr_err("%s: unable to register kdb command: %d\n",+__func__,ret);+gotoerr_kdb_reg;+}++register_console(&kgdb_nmi_console);+kgdb_enable_nmi(1);++return0;+err_kdb_reg:+tty_unregister_driver(kgdb_nmi_tty_driver);+err_tty_reg:+put_tty_driver(kgdb_nmi_tty_driver);+returnret;+}+EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);++intkgdb_unregister_nmi_console(void)+{+intret;++kgdb_enable_nmi(0);++ret=tty_unregister_driver(kgdb_nmi_tty_driver);+if(ret)+returnret;+put_tty_driver(kgdb_nmi_tty_driver);++ret=unregister_console(&kgdb_nmi_console);+if(ret)+returnret;++return0;+}+EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:53:09
It's all pretty straightforward, except for TXIM interrupt. The interrupt
has meaning "ready to transmit", so it's almost always raised, and the
only way to silence it is to mask it. But that's OK, ops->start_tx will
unmask it.
Signed-off-by: Anton Vorontsov <redacted>
---
drivers/tty/serial/amba-pl011.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:53:42
This patch implements a new callback: clear_irqs. It is used for the
cases when KDB-entry (e.g. NMI) and KDB IO (e.g. serial port) shares
the same interrupt. To get the idea, let's take some real example (ARM
machine): we have a serial port which interrupt is routed to an NMI,
and the interrupt is used to enter KDB. Once there is some activity on
the serial port, the CPU receives NMI exception, and we fall into KDB
shell. So, it is our "debug console", and it is able to interrupt (and
thus debug) even IRQ handlers themselves.
When used that way, the interrupt never reaches serial driver's IRQ
handler routine, which means that serial driver will not silence the
interrupt. NMIs behaviour are quite arch-specific, and we can't assume
that we can use them as ordinary IRQs, e.g. on some arches (like ARM)
we can't handle data aborts, the behaviour is undefined then. So we
can't just handle execution to serial driver's IRQ handler from the
NMI context once we're done with KDB (plus this would defeat the
debugger's purpose: we want the NMI handler be as simple as possible,
so it will have less chances to hang).
So, given that have to deal with it somehow, we have two options:
1. Implement something that clears the interrupt;
2. Implement a whole new concept of grabbing tty for exclusive KDB use,
plus implement mask/unmask callbacks, i.e.:
- Since consoles might use ttys w/o opending them, we would have
to make kdb respect CON_ENABLED flag (maybe a good idea to do it
anyway);
- Add 'bool exclusive' argument to tty_find_polling_driver(), if set
to 1, the function will refuse to return an already tty; and will
use the flag in tty_reopen() to not allow multiple users (there are
already checks for pty masters, which are "open once" ttys);
- Once we got the tty exclusively, we would need to call some new
uart->mask_all_but_rx_interrupts call before we want to use the
port for NMI/KDB, and unmask_all_but_rx_interrupts after we're
done with it.
The second option is obviously more complex, needlessly so, and less
generic. So I went with the first one: we just consume all the interrupts.
The tty becomes silently unusable for the rest of the world when we use
it with KDB; but once we reroute the serial IRQ source back from NMI to
an ordinary IRQ (in KDB this can be done with 'disable_nmi' command), it
will behave as normal.
p.s. Since the callback is so far used only by polling user, we place
it under the appropriate #ifdef.
Signed-off-by: Anton Vorontsov <redacted>
---
drivers/tty/serial/kgdboc.c | 10 ++++++++++
drivers/tty/serial/serial_core.c | 15 +++++++++++++++
include/linux/kgdb.h | 1 +
include/linux/serial_core.h | 1 +
include/linux/tty_driver.h | 1 +
5 files changed, 28 insertions(+)
From: Anton Vorontsov <hidden> Date: 2012-08-20 14:53:58
The callback is used to initialize the hardware, nothing else should be
done, i.e. we should not request interrupts (but we can and do unmask
some of them, as they might be useful for NMI entry).
As a side-effect, the patch also fixes a division by zero[1] when booting
with kgdboc options specified (e.g. kgdboc=ttyAMA0,115200n8). The issue
happens because serial core calls set_termios callback, but the driver
doesn't know clock frequency, and thus cannot calculate proper baud rate
values.
[1]
WARNING: at drivers/tty/serial/serial_core.c:400 uart_get_baud_rate+0xe8/0x14c()
Modules linked in:
[<c0018e50>] (unwind_backtrace+0x0/0xf0) from [<c0020ae8>] (warn_slowpath_common+0x4c/0x64)
[<c0020ae8>] (warn_slowpath_common+0x4c/0x64) from [<c0020b1c>] (warn_slowpath_null+0x1c/0x24)
[<c0020b1c>] (warn_slowpath_null+0x1c/0x24) from [<c0185ed8>] (uart_get_baud_rate+0xe8/0x14c)
[<c0185ed8>] (uart_get_baud_rate+0xe8/0x14c) from [<c0187078>] (pl011_set_termios+0x48/0x278)
[<c0187078>] (pl011_set_termios+0x48/0x278) from [<c01850b0>] (uart_set_options+0xe8/0x114)
[<c01850b0>] (uart_set_options+0xe8/0x114) from [<c0185de4>] (uart_poll_init+0xd4/0xe0)
[<c0185de4>] (uart_poll_init+0xd4/0xe0) from [<c016da8c>] (tty_find_polling_driver+0x100/0x17c)
[<c016da8c>] (tty_find_polling_driver+0x100/0x17c) from [<c0188538>] (configure_kgdboc+0xc8/0x1b8)
[<c0188538>] (configure_kgdboc+0xc8/0x1b8) from [<c00088a4>] (do_one_initcall+0x30/0x168)
[<c00088a4>] (do_one_initcall+0x30/0x168) from [<c033784c>] (do_basic_setup+0x94/0xc8)
[<c033784c>] (do_basic_setup+0x94/0xc8) from [<c03378e0>] (kernel_init+0x60/0xf4)
[<c03378e0>] (kernel_init+0x60/0xf4) from [<c00144a0>] (kernel_thread_exit+0x0/0x8)
---[ end trace 7d41c9186f342c40 ]---
Division by zero in kernel.
[<c0018e50>] (unwind_backtrace+0x0/0xf0) from [<c014546c>] (Ldiv0+0x8/0x10)
[<c014546c>] (Ldiv0+0x8/0x10) from [<c0187098>] (pl011_set_termios+0x68/0x278)
[<c0187098>] (pl011_set_termios+0x68/0x278) from [<c01850b0>] (uart_set_options+0xe8/0x114)
[<c01850b0>] (uart_set_options+0xe8/0x114) from [<c0185de4>] (uart_poll_init+0xd4/0xe0)
[<c0185de4>] (uart_poll_init+0xd4/0xe0) from [<c016da8c>] (tty_find_polling_driver+0x100/0x17c)
[<c016da8c>] (tty_find_polling_driver+0x100/0x17c) from [<c0188538>] (configure_kgdboc+0xc8/0x1b8)
[<c0188538>] (configure_kgdboc+0xc8/0x1b8) from [<c00088a4>] (do_one_initcall+0x30/0x168)
[<c00088a4>] (do_one_initcall+0x30/0x168) from [<c033784c>] (do_basic_setup+0x94/0xc8)
[<c033784c>] (do_basic_setup+0x94/0xc8) from [<c03378e0>] (kernel_init+0x60/0xf4)
[<c03378e0>] (kernel_init+0x60/0xf4) from [<c00144a0>] (kernel_thread_exit+0x0/0x8)
Division by zero in kernel.
[<c0018e50>] (unwind_backtrace+0x0/0xf0) from [<c014546c>] (Ldiv0+0x8/0x10)
[<c014546c>] (Ldiv0+0x8/0x10) from [<c0183a98>] (uart_update_timeout+0x4c/0x5c)
[<c0183a98>] (uart_update_timeout+0x4c/0x5c) from [<c01870f8>] (pl011_set_termios+0xc8/0x278)
[<c01870f8>] (pl011_set_termios+0xc8/0x278) from [<c01850b0>] (uart_set_options+0xe8/0x114)
[<c01850b0>] (uart_set_options+0xe8/0x114) from [<c0185de4>] (uart_poll_init+0xd4/0xe0)
[<c0185de4>] (uart_poll_init+0xd4/0xe0) from [<c016da8c>] (tty_find_polling_driver+0x100/0x17c)
[<c016da8c>] (tty_find_polling_driver+0x100/0x17c) from [<c0188538>] (configure_kgdboc+0xc8/0x1b8)
[<c0188538>] (configure_kgdboc+0xc8/0x1b8) from [<c00088a4>] (do_one_initcall+0x30/0x168)
[<c00088a4>] (do_one_initcall+0x30/0x168) from [<c033784c>] (do_basic_setup+0x94/0xc8)
[<c033784c>] (do_basic_setup+0x94/0xc8) from [<c03378e0>] (kernel_init+0x60/0xf4)
[<c03378e0>] (kernel_init+0x60/0xf4) from [<c00144a0>] (kernel_thread_exit+0x0/0x8)
Signed-off-by: Anton Vorontsov <redacted>
---
drivers/tty/serial/amba-pl011.c | 47 ++++++++++++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 12 deletions(-)
From: Brian Swetland <hidden> Date: 2012-08-20 20:51:38
On Mon, Aug 20, 2012 at 7:44 AM, Anton Vorontsov
[off-list ref] wrote:
- KGDB/KDB FIQ debugger shell is synchronous. In Google's version you
could have a dedicated shell always running in the FIQ context, so
when you type something on a serial line, you won't actually cause any
debugging actions, FIQ would save the characters in its own buffer and
continue execution normally. But when you hit return key after the
command, then the command is executed.
In KGDB/KDB FIQ debugger it is different. Once you enter KGDB, the
kernel will stop until you instruct it to continue.
This might look as a drastic change, but it is not. There is actually
no difference whether you have sync or async shell, or at least I
couldn't find any use-case where this would matter at all. Anyways, it
is still possible to do async shell in KDB, just don't see any need
for this.
The main reason we did this asynchronously was that it's entirely possible
to get the occasional random character on the debug serial port (which is
often multiplexed with the audio path on the headphone jack), and having
the device freeze mysteriously when this happens is problematic.
Since the FIQ debugger is incredibly useful for diagnosing "my device is
stuck" type problems, we tend to leave it enabled on large numbers of
devices during internal testing, so that if somebody runs into a problem
an engineer can plug in a serial debug cable and take a look. It's
important that the presence of the debug feature doesn't lead to instability,
and thus we don't want a single random character to stop the normal
operation ofthe device.
Brian
From: Anton Vorontsov <hidden> Date: 2012-08-20 21:27:31
Hi Brian,
On Mon, Aug 20, 2012 at 01:51:33PM -0700, Brian Swetland wrote:
quoted
- KGDB/KDB FIQ debugger shell is synchronous. In Google's version you
could have a dedicated shell always running in the FIQ context,
[...]
The main reason we did this asynchronously was that it's entirely possible
to get the occasional random character on the debug serial port (which is
often multiplexed with the audio path on the headphone jack), and having
the device freeze mysteriously when this happens is problematic.
Since the FIQ debugger is incredibly useful for diagnosing "my device is
stuck" type problems, we tend to leave it enabled on large numbers of
devices during internal testing, so that if somebody runs into a problem
an engineer can plug in a serial debug cable and take a look. It's
important that the presence of the debug feature doesn't lead to instability,
and thus we don't want a single random character to stop the normal
operation ofthe device.
Yup, and that's why in my approach I implemented a tiny async "shell" on
to of KDB, the shell accepts just one command "$3#33" -- GDB-protocol
escape sequence:
/**
* kgdb_nmi_poll_knock - Check if it is time to enter the debugger
*
* "Serial ports are often noisy, especially when muxed over another port (we
* often use serial over the headset connector). Noise on the async command
* line just causes characters that are ignored, on a command line that blocked
* execution noise would be catastrophic." -- Colin Cross
*
* So, this function implements KGDB/KDB knocking on the serial line: we won't
* enter the debugger until we receive a known magic phrase (which is actually
* "$3#33", known as "escape to KDB" command.
...
I.e. the kernel will print this prompt on the NMI debugger console:
Type $3#33 to enter the debugger>
And this command will be processed asynchronously.
Thanks!
Anton.