From 5bcc457a96f078cfe0dcd42a7f7143338c23f45b Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 2 Apr 2014 18:30:04 -0700 Subject: [PATCH 01/21] fiq_debugger: move into drivers/staging/android/fiq_debugger/ Move fiq_debugger into drivers/staging/android/fiq_debugger/ to allow for sharing between ARM and ARM64. Change-Id: I6ca5e8b7e3d000f57da3234260261c5592cef2a8 Signed-off-by: Colin Cross --- arch/arm/common/Kconfig | 46 ------------------- arch/arm/common/Makefile | 1 - drivers/staging/android/Kconfig | 2 + drivers/staging/android/Makefile | 1 + drivers/staging/android/fiq_debugger/Kconfig | 43 +++++++++++++++++ drivers/staging/android/fiq_debugger/Makefile | 1 + .../android/fiq_debugger}/fiq_debugger.c | 4 +- .../android/fiq_debugger}/fiq_debugger.h | 2 +- .../fiq_debugger}/fiq_debugger_ringbuf.h | 2 +- 9 files changed, 51 insertions(+), 51 deletions(-) create mode 100644 drivers/staging/android/fiq_debugger/Kconfig create mode 100644 drivers/staging/android/fiq_debugger/Makefile rename {arch/arm/common => drivers/staging/android/fiq_debugger}/fiq_debugger.c (99%) rename {arch/arm/include/asm => drivers/staging/android/fiq_debugger}/fiq_debugger.h (97%) rename {arch/arm/common => drivers/staging/android/fiq_debugger}/fiq_debugger_ringbuf.h (96%) diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 992d4046bb8a..ce01364a96e3 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -21,49 +21,3 @@ config SHARP_SCOOP config FIQ_GLUE bool select FIQ - -config FIQ_DEBUGGER - bool "FIQ Mode Serial Debugger" - select FIQ - select FIQ_GLUE - default n - help - The FIQ serial debugger can accept commands even when the - kernel is unresponsive due to being stuck with interrupts - disabled. - - -config FIQ_DEBUGGER_NO_SLEEP - bool "Keep serial debugger active" - depends on FIQ_DEBUGGER - default n - help - Enables the serial debugger at boot. Passing - fiq_debugger.no_sleep on the kernel commandline will - override this config option. - -config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON - bool "Don't disable wakeup IRQ when debugger is active" - depends on FIQ_DEBUGGER - default n - help - Don't disable the wakeup irq when enabling the uart clock. This will - cause extra interrupts, but it makes the serial debugger usable with - on some MSM radio builds that ignore the uart clock request in power - collapse. - -config FIQ_DEBUGGER_CONSOLE - bool "Console on FIQ Serial Debugger port" - depends on FIQ_DEBUGGER - default n - help - Enables a console so that printk messages are displayed on - the debugger serial port as the occur. - -config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE - bool "Put the FIQ debugger into console mode by default" - depends on FIQ_DEBUGGER_CONSOLE - default n - help - If enabled, this puts the fiq debugger into console mode by default. - Otherwise, the fiq debugger will start out in debug mode. diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 384abdc09b62..0a0821fa9a90 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -4,7 +4,6 @@ obj-y += firmware.o -obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o obj-$(CONFIG_ICST) += icst.o obj-$(CONFIG_SA1111) += sa1111.o diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index a802bc0bf4a4..c5539001f444 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -118,6 +118,8 @@ config SW_SYNC_USER source "drivers/staging/android/ion/Kconfig" +source "drivers/staging/android/fiq_debugger/Kconfig" + endif # if ANDROID endmenu diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 0a01e1914905..907b62f56203 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -1,6 +1,7 @@ ccflags-y += -I$(src) # needed for trace events obj-y += ion/ +obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/ obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o obj-$(CONFIG_ASHMEM) += ashmem.o diff --git a/drivers/staging/android/fiq_debugger/Kconfig b/drivers/staging/android/fiq_debugger/Kconfig new file mode 100644 index 000000000000..803fb59cc82f --- /dev/null +++ b/drivers/staging/android/fiq_debugger/Kconfig @@ -0,0 +1,43 @@ +config FIQ_DEBUGGER + bool "FIQ Mode Serial Debugger" + default n + depends on ARM + help + The FIQ serial debugger can accept commands even when the + kernel is unresponsive due to being stuck with interrupts + disabled. + +config FIQ_DEBUGGER_NO_SLEEP + bool "Keep serial debugger active" + depends on FIQ_DEBUGGER + default n + help + Enables the serial debugger at boot. Passing + fiq_debugger.no_sleep on the kernel commandline will + override this config option. + +config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON + bool "Don't disable wakeup IRQ when debugger is active" + depends on FIQ_DEBUGGER + default n + help + Don't disable the wakeup irq when enabling the uart clock. This will + cause extra interrupts, but it makes the serial debugger usable with + on some MSM radio builds that ignore the uart clock request in power + collapse. + +config FIQ_DEBUGGER_CONSOLE + bool "Console on FIQ Serial Debugger port" + depends on FIQ_DEBUGGER + default n + help + Enables a console so that printk messages are displayed on + the debugger serial port as the occur. + +config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE + bool "Put the FIQ debugger into console mode by default" + depends on FIQ_DEBUGGER_CONSOLE + default n + help + If enabled, this puts the fiq debugger into console mode by default. + Otherwise, the fiq debugger will start out in debug mode. diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile new file mode 100644 index 000000000000..437037852963 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/Makefile @@ -0,0 +1 @@ +obj-y += fiq_debugger.o diff --git a/arch/arm/common/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c similarity index 99% rename from arch/arm/common/fiq_debugger.c rename to drivers/staging/android/fiq_debugger/fiq_debugger.c index 65b943c76300..f93d7526b87a 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -1,5 +1,5 @@ /* - * arch/arm/common/fiq_debugger.c + * drivers/staging/android/fiq_debugger.c * * Serial Debugger Interface accessed through an FIQ interrupt. * @@ -35,12 +35,12 @@ #include #include -#include #include #include #include +#include "fiq_debugger.h" #include "fiq_debugger_ringbuf.h" #define DEBUG_MAX 64 diff --git a/arch/arm/include/asm/fiq_debugger.h b/drivers/staging/android/fiq_debugger/fiq_debugger.h similarity index 97% rename from arch/arm/include/asm/fiq_debugger.h rename to drivers/staging/android/fiq_debugger/fiq_debugger.h index 4d274883ba6a..c9ec4f8db086 100644 --- a/arch/arm/include/asm/fiq_debugger.h +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.h @@ -1,5 +1,5 @@ /* - * arch/arm/include/asm/fiq_debugger.h + * drivers/staging/android/fiq_debugger/fiq_debugger.h * * Copyright (C) 2010 Google, Inc. * Author: Colin Cross diff --git a/arch/arm/common/fiq_debugger_ringbuf.h b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h similarity index 96% rename from arch/arm/common/fiq_debugger_ringbuf.h rename to drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h index 2649b5581088..10c3c5d09098 100644 --- a/arch/arm/common/fiq_debugger_ringbuf.h +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h @@ -1,5 +1,5 @@ /* - * arch/arm/common/fiq_debugger_ringbuf.c + * drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h * * simple lockless ringbuffer * From a6273046d9cfdcff141250fda616b3b80cadc492 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 4 Apr 2014 22:58:23 -0700 Subject: [PATCH 02/21] fiq_debugger: rename debug->fiq_debugger Rename variables and functions in the global namespace to avoid future collisions. Change-Id: Ic23a304b0f794efc94cc6d086fddd63231d99c98 Signed-off-by: Colin Cross --- .../android/fiq_debugger/fiq_debugger.c | 405 ++++++++++-------- 1 file changed, 220 insertions(+), 185 deletions(-) diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index f93d7526b87a..c3a862790239 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -124,10 +124,13 @@ module_param_named(console_enable, initial_console_enable, bool, 0644); module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644); #ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON -static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {} -static inline void disable_wakeup_irq(struct fiq_debugger_state *state) {} +static inline +void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) {} +static inline +void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) {} #else -static inline void enable_wakeup_irq(struct fiq_debugger_state *state) +static inline +void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) { if (state->wakeup_irq < 0) return; @@ -135,7 +138,8 @@ static inline void enable_wakeup_irq(struct fiq_debugger_state *state) if (!state->wakeup_irq_no_set_wake) enable_irq_wake(state->wakeup_irq); } -static inline void disable_wakeup_irq(struct fiq_debugger_state *state) +static inline +void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) { if (state->wakeup_irq < 0) return; @@ -145,16 +149,16 @@ static inline void disable_wakeup_irq(struct fiq_debugger_state *state) } #endif -static bool inline debug_have_fiq(struct fiq_debugger_state *state) +static inline bool fiq_debugger_have_fiq(struct fiq_debugger_state *state) { return (state->fiq >= 0); } -static void debug_force_irq(struct fiq_debugger_state *state) +static void fiq_debugger_force_irq(struct fiq_debugger_state *state) { unsigned int irq = state->signal_irq; - if (WARN_ON(!debug_have_fiq(state))) + if (WARN_ON(!fiq_debugger_have_fiq(state))) return; if (state->pdata->force_irq) { state->pdata->force_irq(state->pdev, irq); @@ -165,7 +169,7 @@ static void debug_force_irq(struct fiq_debugger_state *state) } } -static void debug_uart_enable(struct fiq_debugger_state *state) +static void fiq_debugger_uart_enable(struct fiq_debugger_state *state) { if (state->clk) clk_enable(state->clk); @@ -173,7 +177,7 @@ static void debug_uart_enable(struct fiq_debugger_state *state) state->pdata->uart_enable(state->pdev); } -static void debug_uart_disable(struct fiq_debugger_state *state) +static void fiq_debugger_uart_disable(struct fiq_debugger_state *state) { if (state->pdata->uart_disable) state->pdata->uart_disable(state->pdev); @@ -181,33 +185,33 @@ static void debug_uart_disable(struct fiq_debugger_state *state) clk_disable(state->clk); } -static void debug_uart_flush(struct fiq_debugger_state *state) +static void fiq_debugger_uart_flush(struct fiq_debugger_state *state) { if (state->pdata->uart_flush) state->pdata->uart_flush(state->pdev); } -static void debug_putc(struct fiq_debugger_state *state, char c) +static void fiq_debugger_putc(struct fiq_debugger_state *state, char c) { state->pdata->uart_putc(state->pdev, c); } -static void debug_puts(struct fiq_debugger_state *state, char *s) +static void fiq_debugger_puts(struct fiq_debugger_state *state, char *s) { unsigned c; while ((c = *s++)) { if (c == '\n') - debug_putc(state, '\r'); - debug_putc(state, c); + fiq_debugger_putc(state, '\r'); + fiq_debugger_putc(state, c); } } -static void debug_prompt(struct fiq_debugger_state *state) +static void fiq_debugger_prompt(struct fiq_debugger_state *state) { - debug_puts(state, "debug> "); + fiq_debugger_puts(state, "debug> "); } -static void dump_kernel_log(struct fiq_debugger_state *state) +static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state) { char buf[512]; size_t len; @@ -218,7 +222,7 @@ static void dump_kernel_log(struct fiq_debugger_state *state) while (kmsg_dump_get_line_nolock(&dumper, true, buf, sizeof(buf) - 1, &len)) { buf[len] = 0; - debug_puts(state, buf); + fiq_debugger_puts(state, buf); } } @@ -236,7 +240,7 @@ static char *mode_name(unsigned cpsr) } } -static int debug_printf(void *cookie, const char *fmt, ...) +static int fiq_debugger_printf(void *cookie, const char *fmt, ...) { struct fiq_debugger_state *state = cookie; char buf[256]; @@ -246,12 +250,12 @@ static int debug_printf(void *cookie, const char *fmt, ...) vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - debug_puts(state, buf); + fiq_debugger_puts(state, buf); return state->debug_abort; } /* Safe outside fiq context */ -static int debug_printf_nfiq(void *cookie, const char *fmt, ...) +static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...) { struct fiq_debugger_state *state = cookie; char buf[256]; @@ -263,29 +267,35 @@ static int debug_printf_nfiq(void *cookie, const char *fmt, ...) va_end(ap); local_irq_save(irq_flags); - debug_puts(state, buf); - debug_uart_flush(state); + fiq_debugger_puts(state, buf); + fiq_debugger_uart_flush(state); local_irq_restore(irq_flags); return state->debug_abort; } -static void dump_regs(struct fiq_debugger_state *state, unsigned *regs) +static void fiq_debugger_dump_regs(struct fiq_debugger_state *state, + unsigned *regs) { - debug_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + fiq_debugger_printf(state, + " r0 %08x r1 %08x r2 %08x r3 %08x\n", regs[0], regs[1], regs[2], regs[3]); - debug_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + fiq_debugger_printf(state, + " r4 %08x r5 %08x r6 %08x r7 %08x\n", regs[4], regs[5], regs[6], regs[7]); - debug_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", + fiq_debugger_printf(state, + " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", regs[8], regs[9], regs[10], regs[11], mode_name(regs[16])); if ((regs[16] & MODE_MASK) == USR_MODE) - debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " - "cpsr %08x\n", regs[12], regs[13], regs[14], - regs[15], regs[16]); + fiq_debugger_printf(state, + " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + regs[12], regs[13], regs[14], regs[15], + regs[16]); else - debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " - "cpsr %08x spsr %08x\n", regs[12], regs[13], - regs[14], regs[15], regs[16], regs[17]); + fiq_debugger_printf(state, + " ip %08x sp %08x lr %08x pc %08x cpsr %08x spsr %08x\n", + regs[12], regs[13], regs[14], regs[15], + regs[16], regs[17]); } struct mode_regs { @@ -340,38 +350,45 @@ void __naked get_mode_regs(struct mode_regs *regs) } -static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs) +static void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, + unsigned *regs) { struct mode_regs mode_regs; - dump_regs(state, regs); + fiq_debugger_dump_regs(state, regs); get_mode_regs(&mode_regs); - debug_printf(state, " svc: sp %08x lr %08x spsr %08x\n", + fiq_debugger_printf(state, + " svc: sp %08x lr %08x spsr %08x\n", mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); - debug_printf(state, " abt: sp %08x lr %08x spsr %08x\n", + fiq_debugger_printf(state, + " abt: sp %08x lr %08x spsr %08x\n", mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); - debug_printf(state, " und: sp %08x lr %08x spsr %08x\n", + fiq_debugger_printf(state, + " und: sp %08x lr %08x spsr %08x\n", mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); - debug_printf(state, " irq: sp %08x lr %08x spsr %08x\n", + fiq_debugger_printf(state, + " irq: sp %08x lr %08x spsr %08x\n", mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); - debug_printf(state, " fiq: r8 %08x r9 %08x r10 %08x r11 %08x " - "r12 %08x\n", + fiq_debugger_printf(state, + " fiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, mode_regs.r11_fiq, mode_regs.r12_fiq); - debug_printf(state, " fiq: sp %08x lr %08x spsr %08x\n", + fiq_debugger_printf(state, + " fiq: sp %08x lr %08x spsr %08x\n", mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); } -static void dump_irqs(struct fiq_debugger_state *state) +static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) { int n; struct irq_desc *desc; - debug_printf(state, "irqnr total since-last status name\n"); + fiq_debugger_printf(state, + "irqnr total since-last status name\n"); for_each_irq_desc(n, desc) { struct irqaction *act = desc->action; if (!act && !kstat_irqs(n)) continue; - debug_printf(state, "%5d: %10u %11u %8x %s\n", n, + fiq_debugger_printf(state, "%5d: %10u %11u %8x %s\n", n, kstat_irqs(n), kstat_irqs(n) - state->last_irqs[n], desc->status_use_accessors, @@ -390,14 +407,14 @@ static int report_trace(struct stackframe *frame, void *d) struct stacktrace_state *sts = d; if (sts->depth) { - debug_printf(sts->state, + fiq_debugger_printf(sts->state, " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", frame->pc, frame->pc, frame->lr, frame->lr, frame->sp, frame->fp); sts->depth--; return 0; } - debug_printf(sts->state, " ...\n"); + fiq_debugger_printf(sts->state, " ...\n"); return sts->depth == 0; } @@ -415,16 +432,17 @@ static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, /* Also check accessibility of one struct frame_tail beyond */ if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { - debug_printf(state, " invalid frame pointer %p\n", tail); + fiq_debugger_printf(state, " invalid frame pointer %p\n", + tail); return NULL; } if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { - debug_printf(state, + fiq_debugger_printf(state, " failed to copy frame pointer %p\n", tail); return NULL; } - debug_printf(state, " %p\n", buftail[0].lr); + fiq_debugger_printf(state, " %p\n", buftail[0].lr); /* frame pointers should strictly progress back up the stack * (towards higher addresses) */ @@ -434,7 +452,7 @@ static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, return buftail[0].fp-1; } -void dump_stacktrace(struct fiq_debugger_state *state, +void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, struct pt_regs * const regs, unsigned int depth, void *ssp) { struct frame_tail *tail; @@ -446,11 +464,11 @@ void dump_stacktrace(struct fiq_debugger_state *state, *current_thread_info() = *real_thread_info; if (!current) - debug_printf(state, "current NULL\n"); + fiq_debugger_printf(state, "current NULL\n"); else - debug_printf(state, "pid: %d comm: %s\n", + fiq_debugger_printf(state, "pid: %d comm: %s\n", current->pid, current->comm); - dump_regs(state, (unsigned *)regs); + fiq_debugger_dump_regs(state, (unsigned *)regs); if (!user_mode(regs)) { struct stackframe frame; @@ -458,7 +476,7 @@ void dump_stacktrace(struct fiq_debugger_state *state, frame.sp = regs->ARM_sp; frame.lr = regs->ARM_lr; frame.pc = regs->ARM_pc; - debug_printf(state, + fiq_debugger_printf(state, " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, regs->ARM_sp, regs->ARM_fp); @@ -471,84 +489,86 @@ void dump_stacktrace(struct fiq_debugger_state *state, tail = user_backtrace(state, tail); } -static void do_ps(struct fiq_debugger_state *state) +static void fiq_debugger_do_ps(struct fiq_debugger_state *state) { struct task_struct *g; struct task_struct *p; unsigned task_state; static const char stat_nam[] = "RSDTtZX"; - debug_printf(state, "pid ppid prio task pc\n"); + fiq_debugger_printf(state, "pid ppid prio task pc\n"); read_lock(&tasklist_lock); do_each_thread(g, p) { task_state = p->state ? __ffs(p->state) + 1 : 0; - debug_printf(state, + fiq_debugger_printf(state, "%5d %5d %4d ", p->pid, p->parent->pid, p->prio); - debug_printf(state, "%-13.13s %c", p->comm, + fiq_debugger_printf(state, "%-13.13s %c", p->comm, task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]); if (task_state == TASK_RUNNING) - debug_printf(state, " running\n"); + fiq_debugger_printf(state, " running\n"); else - debug_printf(state, " %08lx\n", thread_saved_pc(p)); + fiq_debugger_printf(state, " %08lx\n", + thread_saved_pc(p)); } while_each_thread(g, p); read_unlock(&tasklist_lock); } #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -static void begin_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state) { state->syslog_dumping = true; } -static void end_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state) { state->syslog_dumping = false; } #else extern int do_syslog(int type, char __user *bug, int count); -static void begin_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state) { do_syslog(5 /* clear */, NULL, 0); } -static void end_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state) { - dump_kernel_log(state); + fiq_debugger_dump_kernel_log(state); } #endif -static void do_sysrq(struct fiq_debugger_state *state, char rq) +static void fiq_debugger_do_sysrq(struct fiq_debugger_state *state, char rq) { if ((rq == 'g' || rq == 'G') && !fiq_kgdb_enable) { - debug_printf(state, "sysrq-g blocked\n"); + fiq_debugger_printf(state, "sysrq-g blocked\n"); return; } - begin_syslog_dump(state); + fiq_debugger_begin_syslog_dump(state); handle_sysrq(rq); - end_syslog_dump(state); + fiq_debugger_end_syslog_dump(state); } #ifdef CONFIG_KGDB -static void do_kgdb(struct fiq_debugger_state *state) +static void fiq_debugger_do_kgdb(struct fiq_debugger_state *state) { if (!fiq_kgdb_enable) { - debug_printf(state, "kgdb through fiq debugger not enabled\n"); + fiq_debugger_printf(state, "kgdb through fiq debugger not enabled\n"); return; } - debug_printf(state, "enabling console and triggering kgdb\n"); + fiq_debugger_printf(state, "enabling console and triggering kgdb\n"); state->console_enable = true; handle_sysrq('g'); } #endif -static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd) +static void fiq_debugger_schedule_work(struct fiq_debugger_state *state, + char *cmd) { unsigned long flags; spin_lock_irqsave(&state->work_lock, flags); if (state->work_cmd[0] != '\0') { - debug_printf(state, "work command processor busy\n"); + fiq_debugger_printf(state, "work command processor busy\n"); spin_unlock_irqrestore(&state->work_lock, flags); return; } @@ -559,7 +579,7 @@ static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd) schedule_work(&state->work); } -static void debug_work(struct work_struct *work) +static void fiq_debugger_work(struct work_struct *work) { struct fiq_debugger_state *state; char work_cmd[DEBUG_MAX]; @@ -585,30 +605,32 @@ static void debug_work(struct work_struct *work) else kernel_restart(NULL); } else { - debug_printf(state, "unknown work command '%s'\n", work_cmd); + fiq_debugger_printf(state, "unknown work command '%s'\n", + work_cmd); } } /* This function CANNOT be called in FIQ context */ -static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd) +static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd) { if (!strcmp(cmd, "ps")) - do_ps(state); + fiq_debugger_do_ps(state); if (!strcmp(cmd, "sysrq")) - do_sysrq(state, 'h'); + fiq_debugger_do_sysrq(state, 'h'); if (!strncmp(cmd, "sysrq ", 6)) - do_sysrq(state, cmd[6]); + fiq_debugger_do_sysrq(state, cmd[6]); #ifdef CONFIG_KGDB if (!strcmp(cmd, "kgdb")) - do_kgdb(state); + fiq_debugger_do_kgdb(state); #endif if (!strncmp(cmd, "reboot", 6)) - debug_schedule_work(state, cmd); + fiq_debugger_schedule_work(state, cmd); } -static void debug_help(struct fiq_debugger_state *state) +static void fiq_debugger_help(struct fiq_debugger_state *state) { - debug_printf(state, "FIQ Debugger commands:\n" + fiq_debugger_printf(state, + "FIQ Debugger commands:\n" " pc PC status\n" " regs Register dump\n" " allregs Extended Register dump\n" @@ -618,20 +640,23 @@ static void debug_help(struct fiq_debugger_state *state) " irqs Interupt status\n" " kmsg Kernel log\n" " version Kernel version\n"); - debug_printf(state, " sleep Allow sleep while in FIQ\n" + fiq_debugger_printf(state, + " sleep Allow sleep while in FIQ\n" " nosleep Disable sleep while in FIQ\n" " console Switch terminal to console\n" " cpu Current CPU\n" " cpu Switch to CPU\n"); - debug_printf(state, " ps Process list\n" + fiq_debugger_printf(state, + " ps Process list\n" " sysrq sysrq options\n" " sysrq Execute sysrq with \n"); #ifdef CONFIG_KGDB - debug_printf(state, " kgdb Enter kernel debugger\n"); + fiq_debugger_printf(state, + " kgdb Enter kernel debugger\n"); #endif } -static void take_affinity(void *info) +static void fiq_debugger_take_affinity(void *info) { struct fiq_debugger_state *state = info; struct cpumask cpumask; @@ -642,29 +667,31 @@ static void take_affinity(void *info) irq_set_affinity(state->uart_irq, &cpumask); } -static void switch_cpu(struct fiq_debugger_state *state, int cpu) +static void fiq_debugger_switch_cpu(struct fiq_debugger_state *state, int cpu) { - if (!debug_have_fiq(state)) - smp_call_function_single(cpu, take_affinity, state, false); + if (!fiq_debugger_have_fiq(state)) + smp_call_function_single(cpu, fiq_debugger_take_affinity, state, + false); state->current_cpu = cpu; } -static bool debug_fiq_exec(struct fiq_debugger_state *state, +static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, const char *cmd, unsigned *regs, void *svc_sp) { bool signal_helper = false; if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { - debug_help(state); + fiq_debugger_help(state); } else if (!strcmp(cmd, "pc")) { - debug_printf(state, " pc %08x cpsr %08x mode %s\n", + fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n", regs[15], regs[16], mode_name(regs[16])); } else if (!strcmp(cmd, "regs")) { - dump_regs(state, regs); + fiq_debugger_dump_regs(state, regs); } else if (!strcmp(cmd, "allregs")) { - dump_allregs(state, regs); + fiq_debugger_dump_allregs(state, regs); } else if (!strcmp(cmd, "bt")) { - dump_stacktrace(state, (struct pt_regs *)regs, 100, svc_sp); + fiq_debugger_dump_stacktrace(state, (struct pt_regs *)regs, 100, + svc_sp); } else if (!strncmp(cmd, "reset", 5)) { cmd += 5; while (*cmd == ' ') @@ -677,33 +704,33 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state, machine_restart(NULL); } } else if (!strcmp(cmd, "irqs")) { - dump_irqs(state); + fiq_debugger_dump_irqs(state); } else if (!strcmp(cmd, "kmsg")) { - dump_kernel_log(state); + fiq_debugger_dump_kernel_log(state); } else if (!strcmp(cmd, "version")) { - debug_printf(state, "%s\n", linux_banner); + fiq_debugger_printf(state, "%s\n", linux_banner); } else if (!strcmp(cmd, "sleep")) { state->no_sleep = false; - debug_printf(state, "enabling sleep\n"); + fiq_debugger_printf(state, "enabling sleep\n"); } else if (!strcmp(cmd, "nosleep")) { state->no_sleep = true; - debug_printf(state, "disabling sleep\n"); + fiq_debugger_printf(state, "disabling sleep\n"); } else if (!strcmp(cmd, "console")) { - debug_printf(state, "console mode\n"); - debug_uart_flush(state); + fiq_debugger_printf(state, "console mode\n"); + fiq_debugger_uart_flush(state); state->console_enable = true; } else if (!strcmp(cmd, "cpu")) { - debug_printf(state, "cpu %d\n", state->current_cpu); + fiq_debugger_printf(state, "cpu %d\n", state->current_cpu); } else if (!strncmp(cmd, "cpu ", 4)) { unsigned long cpu = 0; if (strict_strtoul(cmd + 4, 10, &cpu) == 0) - switch_cpu(state, cpu); + fiq_debugger_switch_cpu(state, cpu); else - debug_printf(state, "invalid cpu\n"); - debug_printf(state, "cpu %d\n", state->current_cpu); + fiq_debugger_printf(state, "invalid cpu\n"); + fiq_debugger_printf(state, "cpu %d\n", state->current_cpu); } else { if (state->debug_busy) { - debug_printf(state, + fiq_debugger_printf(state, "command processor busy. trying to abort.\n"); state->debug_abort = -1; } else { @@ -714,12 +741,12 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state, return true; } if (!state->console_enable) - debug_prompt(state); + fiq_debugger_prompt(state); return signal_helper; } -static void sleep_timer_expired(unsigned long data) +static void fiq_debugger_sleep_timer_expired(unsigned long data) { struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; unsigned long flags; @@ -728,18 +755,19 @@ static void sleep_timer_expired(unsigned long data) if (state->uart_enabled && !state->no_sleep) { if (state->debug_enable && !state->console_enable) { state->debug_enable = false; - debug_printf_nfiq(state, "suspending fiq debugger\n"); + fiq_debugger_printf_nfiq(state, + "suspending fiq debugger\n"); } state->ignore_next_wakeup_irq = true; - debug_uart_disable(state); + fiq_debugger_uart_disable(state); state->uart_enabled = false; - enable_wakeup_irq(state); + fiq_debugger_enable_wakeup_irq(state); } wake_unlock(&state->debugger_wake_lock); spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } -static void handle_wakeup(struct fiq_debugger_state *state) +static void fiq_debugger_handle_wakeup(struct fiq_debugger_state *state) { unsigned long flags; @@ -748,26 +776,27 @@ static void handle_wakeup(struct fiq_debugger_state *state) state->ignore_next_wakeup_irq = false; } else if (!state->uart_enabled) { wake_lock(&state->debugger_wake_lock); - debug_uart_enable(state); + fiq_debugger_uart_enable(state); state->uart_enabled = true; - disable_wakeup_irq(state); + fiq_debugger_disable_wakeup_irq(state); mod_timer(&state->sleep_timer, jiffies + HZ / 2); } spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } -static irqreturn_t wakeup_irq_handler(int irq, void *dev) +static irqreturn_t fiq_debugger_wakeup_irq_handler(int irq, void *dev) { struct fiq_debugger_state *state = dev; if (!state->no_sleep) - debug_puts(state, "WAKEUP\n"); - handle_wakeup(state); + fiq_debugger_puts(state, "WAKEUP\n"); + fiq_debugger_handle_wakeup(state); return IRQ_HANDLED; } -static void debug_handle_console_irq_context(struct fiq_debugger_state *state) +static +void fiq_debugger_handle_console_irq_context(struct fiq_debugger_state *state) { #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) if (state->tty_port.ops) { @@ -784,7 +813,7 @@ static void debug_handle_console_irq_context(struct fiq_debugger_state *state) #endif } -static void debug_handle_irq_context(struct fiq_debugger_state *state) +static void fiq_debugger_handle_irq_context(struct fiq_debugger_state *state) { if (!state->no_sleep) { unsigned long flags; @@ -794,22 +823,22 @@ static void debug_handle_irq_context(struct fiq_debugger_state *state) mod_timer(&state->sleep_timer, jiffies + HZ * 5); spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } - debug_handle_console_irq_context(state); + fiq_debugger_handle_console_irq_context(state); if (state->debug_busy) { - debug_irq_exec(state, state->debug_cmd); + fiq_debugger_irq_exec(state, state->debug_cmd); if (!state->console_enable) - debug_prompt(state); + fiq_debugger_prompt(state); state->debug_busy = 0; } } -static int debug_getc(struct fiq_debugger_state *state) +static int fiq_debugger_getc(struct fiq_debugger_state *state) { return state->pdata->uart_getc(state->pdev); } -static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, - int this_cpu, void *regs, void *svc_sp) +static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state, + int this_cpu, struct pt_regs *regs, void *svc_sp) { int c; static int last_c; @@ -824,30 +853,31 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, MAX_UNHANDLED_FIQ_COUNT) return false; - debug_printf(state, "fiq_debugger: cpu %d not responding, " + fiq_debugger_printf(state, + "fiq_debugger: cpu %d not responding, " "reverting to cpu %d\n", state->current_cpu, this_cpu); atomic_set(&state->unhandled_fiq_count, 0); - switch_cpu(state, this_cpu); + fiq_debugger_switch_cpu(state, this_cpu); return false; } state->in_fiq = true; - while ((c = debug_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { + while ((c = fiq_debugger_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { count++; if (!state->debug_enable) { if ((c == 13) || (c == 10)) { state->debug_enable = true; state->debug_count = 0; - debug_prompt(state); + fiq_debugger_prompt(state); } } else if (c == FIQ_DEBUGGER_BREAK) { state->console_enable = false; - debug_puts(state, "fiq debugger mode\n"); + fiq_debugger_puts(state, "fiq debugger mode\n"); state->debug_count = 0; - debug_prompt(state); + fiq_debugger_prompt(state); #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE } else if (state->console_enable && state->tty_rbuf) { fiq_debugger_ringbuf_push(state->tty_rbuf, c); @@ -856,34 +886,35 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, } else if ((c >= ' ') && (c < 127)) { if (state->debug_count < (DEBUG_MAX - 1)) { state->debug_buf[state->debug_count++] = c; - debug_putc(state, c); + fiq_debugger_putc(state, c); } } else if ((c == 8) || (c == 127)) { if (state->debug_count > 0) { state->debug_count--; - debug_putc(state, 8); - debug_putc(state, ' '); - debug_putc(state, 8); + fiq_debugger_putc(state, 8); + fiq_debugger_putc(state, ' '); + fiq_debugger_putc(state, 8); } } else if ((c == 13) || (c == 10)) { if (c == '\r' || (c == '\n' && last_c != '\r')) { - debug_putc(state, '\r'); - debug_putc(state, '\n'); + fiq_debugger_putc(state, '\r'); + fiq_debugger_putc(state, '\n'); } if (state->debug_count) { state->debug_buf[state->debug_count] = 0; state->debug_count = 0; signal_helper |= - debug_fiq_exec(state, state->debug_buf, - regs, svc_sp); + fiq_debugger_fiq_exec(state, + state->debug_buf, + regs, svc_sp); } else { - debug_prompt(state); + fiq_debugger_prompt(state); } } last_c = c; } if (!state->console_enable) - debug_uart_flush(state); + fiq_debugger_uart_flush(state); if (state->pdata->fiq_ack) state->pdata->fiq_ack(state->pdev, state->fiq); @@ -897,16 +928,18 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, return signal_helper; } -static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) +static void fiq_debugger_fiq(struct fiq_glue_handler *h, void *regs, + void *svc_sp) { struct fiq_debugger_state *state = container_of(h, struct fiq_debugger_state, handler); unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; bool need_irq; - need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp); + need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs, + svc_sp); if (need_irq) - debug_force_irq(state); + fiq_debugger_force_irq(state); } /* @@ -914,19 +947,19 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) * This just effectively takes over the UART interrupt and does all the work * in this context. */ -static irqreturn_t debug_uart_irq(int irq, void *dev) +static irqreturn_t fiq_debugger_uart_irq(int irq, void *dev) { struct fiq_debugger_state *state = dev; bool not_done; - handle_wakeup(state); + fiq_debugger_handle_wakeup(state); /* handle the debugger irq in regular context */ - not_done = debug_handle_uart_interrupt(state, smp_processor_id(), + not_done = fiq_debugger_handle_uart_interrupt(state, smp_processor_id(), get_irq_regs(), current_thread_info()); if (not_done) - debug_handle_irq_context(state); + fiq_debugger_handle_irq_context(state); return IRQ_HANDLED; } @@ -936,19 +969,19 @@ static irqreturn_t debug_uart_irq(int irq, void *dev) * FIQ handler does what it can and then signals this interrupt to finish the * job in irq context. */ -static irqreturn_t debug_signal_irq(int irq, void *dev) +static irqreturn_t fiq_debugger_signal_irq(int irq, void *dev) { struct fiq_debugger_state *state = dev; if (state->pdata->force_irq_ack) state->pdata->force_irq_ack(state->pdev, state->signal_irq); - debug_handle_irq_context(state); + fiq_debugger_handle_irq_context(state); return IRQ_HANDLED; } -static void debug_resume(struct fiq_glue_handler *h) +static void fiq_debugger_resume(struct fiq_glue_handler *h) { struct fiq_debugger_state *state = container_of(h, struct fiq_debugger_state, handler); @@ -957,13 +990,13 @@ static void debug_resume(struct fiq_glue_handler *h) } #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) -struct tty_driver *debug_console_device(struct console *co, int *index) +struct tty_driver *fiq_debugger_console_device(struct console *co, int *index) { *index = co->index; return fiq_tty_driver; } -static void debug_console_write(struct console *co, +static void fiq_debugger_console_write(struct console *co, const char *s, unsigned int count) { struct fiq_debugger_state *state; @@ -974,22 +1007,22 @@ static void debug_console_write(struct console *co, if (!state->console_enable && !state->syslog_dumping) return; - debug_uart_enable(state); + fiq_debugger_uart_enable(state); spin_lock_irqsave(&state->console_lock, flags); while (count--) { if (*s == '\n') - debug_putc(state, '\r'); - debug_putc(state, *s++); + fiq_debugger_putc(state, '\r'); + fiq_debugger_putc(state, *s++); } - debug_uart_flush(state); + fiq_debugger_uart_flush(state); spin_unlock_irqrestore(&state->console_lock, flags); - debug_uart_disable(state); + fiq_debugger_uart_disable(state); } static struct console fiq_debugger_console = { .name = "ttyFIQ", - .device = debug_console_device, - .write = debug_console_write, + .device = fiq_debugger_console_device, + .write = fiq_debugger_console_write, .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, }; @@ -1017,12 +1050,12 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) if (!state->console_enable) return count; - debug_uart_enable(state); + fiq_debugger_uart_enable(state); spin_lock_irq(&state->console_lock); for (i = 0; i < count; i++) - debug_putc(state, *buf++); + fiq_debugger_putc(state, *buf++); spin_unlock_irq(&state->console_lock); - debug_uart_disable(state); + fiq_debugger_uart_disable(state); return count; } @@ -1044,19 +1077,19 @@ static int fiq_tty_poll_get_char(struct tty_driver *driver, int line) struct fiq_debugger_state *state = states[line]; int c = NO_POLL_CHAR; - debug_uart_enable(state); - if (debug_have_fiq(state)) { + fiq_debugger_uart_enable(state); + if (fiq_debugger_have_fiq(state)) { int count = fiq_debugger_ringbuf_level(state->tty_rbuf); if (count > 0) { c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0); fiq_debugger_ringbuf_consume(state->tty_rbuf, 1); } } else { - c = debug_getc(state); + c = fiq_debugger_getc(state); if (c == FIQ_DEBUGGER_NO_CHAR) c = NO_POLL_CHAR; } - debug_uart_disable(state); + fiq_debugger_uart_disable(state); return c; } @@ -1065,9 +1098,9 @@ static void fiq_tty_poll_put_char(struct tty_driver *driver, int line, char ch) { struct fiq_debugger_state **states = driver->driver_state; struct fiq_debugger_state *state = states[line]; - debug_uart_enable(state); - debug_putc(state, ch); - debug_uart_disable(state); + fiq_debugger_uart_enable(state); + fiq_debugger_putc(state, ch); + fiq_debugger_uart_disable(state); } #endif @@ -1224,7 +1257,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) return -EINVAL; state = kzalloc(sizeof(*state), GFP_KERNEL); - setup_timer(&state->sleep_timer, sleep_timer_expired, + setup_timer(&state->sleep_timer, fiq_debugger_sleep_timer_expired, (unsigned long)state); state->pdata = pdata; state->pdev = pdev; @@ -1237,14 +1270,14 @@ static int fiq_debugger_probe(struct platform_device *pdev) state->signal_irq = platform_get_irq_byname(pdev, "signal"); state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); - INIT_WORK(&state->work, debug_work); + INIT_WORK(&state->work, fiq_debugger_work); spin_lock_init(&state->work_lock); platform_set_drvdata(pdev, state); spin_lock_init(&state->sleep_timer_lock); - if (state->wakeup_irq < 0 && debug_have_fiq(state)) + if (state->wakeup_irq < 0 && fiq_debugger_have_fiq(state)) state->no_sleep = true; state->ignore_next_wakeup_irq = !state->no_sleep; @@ -1268,12 +1301,13 @@ static int fiq_debugger_probe(struct platform_device *pdev) goto err_uart_init; } - debug_printf_nfiq(state, "\n", + fiq_debugger_printf_nfiq(state, + "\n", state->no_sleep ? "" : "twice "); - if (debug_have_fiq(state)) { - state->handler.fiq = debug_fiq; - state->handler.resume = debug_resume; + if (fiq_debugger_have_fiq(state)) { + state->handler.fiq = fiq_debugger_fiq; + state->handler.resume = fiq_debugger_resume; ret = fiq_glue_register_handler(&state->handler); if (ret) { pr_err("%s: could not install fiq handler\n", __func__); @@ -1282,7 +1316,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) pdata->fiq_enable(pdev, state->fiq, 1); } else { - ret = request_irq(state->uart_irq, debug_uart_irq, + ret = request_irq(state->uart_irq, fiq_debugger_uart_irq, IRQF_NO_SUSPEND, "debug", state); if (ret) { pr_err("%s: could not install irq handler\n", __func__); @@ -1299,14 +1333,15 @@ static int fiq_debugger_probe(struct platform_device *pdev) clk_disable(state->clk); if (state->signal_irq >= 0) { - ret = request_irq(state->signal_irq, debug_signal_irq, + ret = request_irq(state->signal_irq, fiq_debugger_signal_irq, IRQF_TRIGGER_RISING, "debug-signal", state); if (ret) pr_err("serial_debugger: could not install signal_irq"); } if (state->wakeup_irq >= 0) { - ret = request_irq(state->wakeup_irq, wakeup_irq_handler, + ret = request_irq(state->wakeup_irq, + fiq_debugger_wakeup_irq_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, "debug-wakeup", state); if (ret) { @@ -1323,7 +1358,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) } } if (state->no_sleep) - handle_wakeup(state); + fiq_debugger_handle_wakeup(state); #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) spin_lock_init(&state->console_lock); From ab71250a48be67b7445a864408fd99f0410d610e Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 2 Apr 2014 18:37:29 -0700 Subject: [PATCH 03/21] fiq_debugger: allow compiling without CONFIG_FIQ_GLUE Allow compiling fiq_debugger.c without CONFIG_FIQ_GLUE for platforms that don't support FIQs. Change-Id: Iabdfd790d24fa9d47b29d2f850c567af2dcad78f Signed-off-by: Colin Cross --- .../android/fiq_debugger/fiq_debugger.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index c3a862790239..4c392729fc68 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -35,7 +35,9 @@ #include #include +#ifdef CONFIG_FIQ_GLUE #include +#endif #include #include @@ -52,7 +54,9 @@ ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) struct fiq_debugger_state { +#ifdef CONFIG_FIQ_GLUE struct fiq_glue_handler handler; +#endif int fiq; int uart_irq; @@ -154,6 +158,7 @@ static inline bool fiq_debugger_have_fiq(struct fiq_debugger_state *state) return (state->fiq >= 0); } +#ifdef CONFIG_FIQ_GLUE static void fiq_debugger_force_irq(struct fiq_debugger_state *state) { unsigned int irq = state->signal_irq; @@ -168,6 +173,7 @@ static void fiq_debugger_force_irq(struct fiq_debugger_state *state) chip->irq_retrigger(irq_get_irq_data(irq)); } } +#endif static void fiq_debugger_uart_enable(struct fiq_debugger_state *state) { @@ -928,6 +934,7 @@ static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state, return signal_helper; } +#ifdef CONFIG_FIQ_GLUE static void fiq_debugger_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) { @@ -941,6 +948,7 @@ static void fiq_debugger_fiq(struct fiq_glue_handler *h, void *regs, if (need_irq) fiq_debugger_force_irq(state); } +#endif /* * When not using FIQs, we only use this single interrupt as an entry point. @@ -981,6 +989,7 @@ static irqreturn_t fiq_debugger_signal_irq(int irq, void *dev) return IRQ_HANDLED; } +#ifdef CONFIG_FIQ_GLUE static void fiq_debugger_resume(struct fiq_glue_handler *h) { struct fiq_debugger_state *state = @@ -988,6 +997,7 @@ static void fiq_debugger_resume(struct fiq_glue_handler *h) if (state->pdata->uart_resume) state->pdata->uart_resume(state->pdev); } +#endif #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) struct tty_driver *fiq_debugger_console_device(struct console *co, int *index) @@ -1305,17 +1315,20 @@ static int fiq_debugger_probe(struct platform_device *pdev) "\n", state->no_sleep ? "" : "twice "); +#ifdef CONFIG_FIQ_GLUE if (fiq_debugger_have_fiq(state)) { state->handler.fiq = fiq_debugger_fiq; state->handler.resume = fiq_debugger_resume; ret = fiq_glue_register_handler(&state->handler); if (ret) { pr_err("%s: could not install fiq handler\n", __func__); - goto err_register_fiq; + goto err_register_irq; } pdata->fiq_enable(pdev, state->fiq, 1); - } else { + } else +#endif + { ret = request_irq(state->uart_irq, fiq_debugger_uart_irq, IRQF_NO_SUSPEND, "debug", state); if (ret) { @@ -1373,7 +1386,6 @@ static int fiq_debugger_probe(struct platform_device *pdev) return 0; err_register_irq: -err_register_fiq: if (pdata->uart_free) pdata->uart_free(pdev); err_uart_init: From c000c88d0769604ffa2c18d9670dcceb777f7b16 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 4 Apr 2014 17:05:19 -0700 Subject: [PATCH 04/21] fiq_debugger: use pt_regs for registers IRQ mode already passes in a struct pt_regs from get_irq_regs(). FIQ mode passes in something similar but not identical to a struct pt_regs - FIQ mode stores the spsr of the interrupted mode in slot 17, while pt_regs expects orig_r0. Replace the existing mixture of void *regs, unsigned *regs, and struct pt_regs * const with const struct pt_regs *. Modify dump_regs not to print the spsr since it won't be there in a struct pt_regs anyways. Modify dump_allregs to highlight the mode that was interrupted, making spsr easy to find there. Change-Id: Ibfe1723d702306c7605fd071737d7be9ee9d8c12 Signed-off-by: Colin Cross --- .../android/fiq_debugger/fiq_debugger.c | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index 4c392729fc68..d660a46e7893 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -280,28 +280,22 @@ static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...) } static void fiq_debugger_dump_regs(struct fiq_debugger_state *state, - unsigned *regs) + const struct pt_regs *regs) { fiq_debugger_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", - regs[0], regs[1], regs[2], regs[3]); + regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); fiq_debugger_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", - regs[4], regs[5], regs[6], regs[7]); + regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); fiq_debugger_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", - regs[8], regs[9], regs[10], regs[11], - mode_name(regs[16])); - if ((regs[16] & MODE_MASK) == USR_MODE) - fiq_debugger_printf(state, - " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", - regs[12], regs[13], regs[14], regs[15], - regs[16]); - else - fiq_debugger_printf(state, - " ip %08x sp %08x lr %08x pc %08x cpsr %08x spsr %08x\n", - regs[12], regs[13], regs[14], regs[15], - regs[16], regs[17]); + regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, + mode_name(regs->ARM_cpsr)); + fiq_debugger_printf(state, + " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, + regs->ARM_cpsr); } struct mode_regs { @@ -357,25 +351,33 @@ void __naked get_mode_regs(struct mode_regs *regs) static void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, - unsigned *regs) + const struct pt_regs *regs) { struct mode_regs mode_regs; + unsigned long mode = regs->ARM_cpsr & MODE_MASK; + fiq_debugger_dump_regs(state, regs); get_mode_regs(&mode_regs); + fiq_debugger_printf(state, - " svc: sp %08x lr %08x spsr %08x\n", + "%csvc: sp %08x lr %08x spsr %08x\n", + mode == SVC_MODE ? '*' : ' ', mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); fiq_debugger_printf(state, - " abt: sp %08x lr %08x spsr %08x\n", + "%cabt: sp %08x lr %08x spsr %08x\n", + mode == ABT_MODE ? '*' : ' ', mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); fiq_debugger_printf(state, - " und: sp %08x lr %08x spsr %08x\n", + "%cund: sp %08x lr %08x spsr %08x\n", + mode == UND_MODE ? '*' : ' ', mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); fiq_debugger_printf(state, - " irq: sp %08x lr %08x spsr %08x\n", + "%cirq: sp %08x lr %08x spsr %08x\n", + mode == IRQ_MODE ? '*' : ' ', mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); fiq_debugger_printf(state, - " fiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", + "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", + mode == FIQ_MODE ? '*' : ' ', mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, mode_regs.r11_fiq, mode_regs.r12_fiq); fiq_debugger_printf(state, @@ -459,7 +461,7 @@ static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, } void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, - struct pt_regs * const regs, unsigned int depth, void *ssp) + const struct pt_regs *regs, unsigned int depth, void *ssp) { struct frame_tail *tail; struct thread_info *real_thread_info = THREAD_INFO(ssp); @@ -474,7 +476,7 @@ void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, else fiq_debugger_printf(state, "pid: %d comm: %s\n", current->pid, current->comm); - fiq_debugger_dump_regs(state, (unsigned *)regs); + fiq_debugger_dump_regs(state, regs); if (!user_mode(regs)) { struct stackframe frame; @@ -682,7 +684,8 @@ static void fiq_debugger_switch_cpu(struct fiq_debugger_state *state, int cpu) } static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, - const char *cmd, unsigned *regs, void *svc_sp) + const char *cmd, const struct pt_regs *regs, + void *svc_sp) { bool signal_helper = false; @@ -690,14 +693,14 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, fiq_debugger_help(state); } else if (!strcmp(cmd, "pc")) { fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n", - regs[15], regs[16], mode_name(regs[16])); + regs->ARM_pc, regs->ARM_cpsr, + mode_name(regs->ARM_cpsr)); } else if (!strcmp(cmd, "regs")) { fiq_debugger_dump_regs(state, regs); } else if (!strcmp(cmd, "allregs")) { fiq_debugger_dump_allregs(state, regs); } else if (!strcmp(cmd, "bt")) { - fiq_debugger_dump_stacktrace(state, (struct pt_regs *)regs, 100, - svc_sp); + fiq_debugger_dump_stacktrace(state, regs, 100, svc_sp); } else if (!strncmp(cmd, "reset", 5)) { cmd += 5; while (*cmd == ' ') @@ -844,7 +847,7 @@ static int fiq_debugger_getc(struct fiq_debugger_state *state) } static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state, - int this_cpu, struct pt_regs *regs, void *svc_sp) + int this_cpu, const struct pt_regs *regs, void *svc_sp) { int c; static int last_c; @@ -935,8 +938,8 @@ static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state, } #ifdef CONFIG_FIQ_GLUE -static void fiq_debugger_fiq(struct fiq_glue_handler *h, void *regs, - void *svc_sp) +static void fiq_debugger_fiq(struct fiq_glue_handler *h, + const struct pt_regs *regs, void *svc_sp) { struct fiq_debugger_state *state = container_of(h, struct fiq_debugger_state, handler); From 86098e6f33f71d31374dc01f452dcb0ed919145d Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 2 Apr 2014 18:42:13 -0700 Subject: [PATCH 05/21] fiq_debugger: split arm support into fiq_debugger_arm.c Split arm support into a separate .c file that is only built for CONFIG_ARM. Change-Id: Iba16f4d51608bf9c3e5c8acefefcd38fead9797c Signed-off-by: Colin Cross --- drivers/staging/android/fiq_debugger/Makefile | 1 + .../android/fiq_debugger/fiq_debugger.c | 223 +--------------- .../android/fiq_debugger/fiq_debugger_arm.c | 240 ++++++++++++++++++ .../android/fiq_debugger/fiq_debugger_priv.h | 36 +++ 4 files changed, 280 insertions(+), 220 deletions(-) create mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_arm.c create mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_priv.h diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile index 437037852963..1e203aed8c62 100644 --- a/drivers/staging/android/fiq_debugger/Makefile +++ b/drivers/staging/android/fiq_debugger/Makefile @@ -1 +1,2 @@ obj-y += fiq_debugger.o +obj-$(CONFIG_ARM) += fiq_debugger_arm.o diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index d660a46e7893..5516d3113b94 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -38,11 +38,11 @@ #ifdef CONFIG_FIQ_GLUE #include #endif -#include #include #include "fiq_debugger.h" +#include "fiq_debugger_priv.h" #include "fiq_debugger_ringbuf.h" #define DEBUG_MAX 64 @@ -50,9 +50,6 @@ #define MAX_FIQ_DEBUGGER_PORTS 4 -#define THREAD_INFO(sp) ((struct thread_info *) \ - ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) - struct fiq_debugger_state { #ifdef CONFIG_FIQ_GLUE struct fiq_glue_handler handler; @@ -232,21 +229,7 @@ static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state) } } -static char *mode_name(unsigned cpsr) -{ - switch (cpsr & MODE_MASK) { - case USR_MODE: return "USR"; - case FIQ_MODE: return "FIQ"; - case IRQ_MODE: return "IRQ"; - case SVC_MODE: return "SVC"; - case ABT_MODE: return "ABT"; - case UND_MODE: return "UND"; - case SYSTEM_MODE: return "SYS"; - default: return "???"; - } -} - -static int fiq_debugger_printf(void *cookie, const char *fmt, ...) +int fiq_debugger_printf(void *cookie, const char *fmt, ...) { struct fiq_debugger_state *state = cookie; char buf[256]; @@ -279,112 +262,6 @@ static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...) return state->debug_abort; } -static void fiq_debugger_dump_regs(struct fiq_debugger_state *state, - const struct pt_regs *regs) -{ - fiq_debugger_printf(state, - " r0 %08x r1 %08x r2 %08x r3 %08x\n", - regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); - fiq_debugger_printf(state, - " r4 %08x r5 %08x r6 %08x r7 %08x\n", - regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); - fiq_debugger_printf(state, - " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", - regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, - mode_name(regs->ARM_cpsr)); - fiq_debugger_printf(state, - " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", - regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, - regs->ARM_cpsr); -} - -struct mode_regs { - unsigned long sp_svc; - unsigned long lr_svc; - unsigned long spsr_svc; - - unsigned long sp_abt; - unsigned long lr_abt; - unsigned long spsr_abt; - - unsigned long sp_und; - unsigned long lr_und; - unsigned long spsr_und; - - unsigned long sp_irq; - unsigned long lr_irq; - unsigned long spsr_irq; - - unsigned long r8_fiq; - unsigned long r9_fiq; - unsigned long r10_fiq; - unsigned long r11_fiq; - unsigned long r12_fiq; - unsigned long sp_fiq; - unsigned long lr_fiq; - unsigned long spsr_fiq; -}; - -void __naked get_mode_regs(struct mode_regs *regs) -{ - asm volatile ( - "mrs r1, cpsr\n" - "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r8 - r14}\n" - "mrs r2, spsr\n" - "stmia r0!, {r2}\n" - "msr cpsr_c, r1\n" - "bx lr\n"); -} - - -static void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, - const struct pt_regs *regs) -{ - struct mode_regs mode_regs; - unsigned long mode = regs->ARM_cpsr & MODE_MASK; - - fiq_debugger_dump_regs(state, regs); - get_mode_regs(&mode_regs); - - fiq_debugger_printf(state, - "%csvc: sp %08x lr %08x spsr %08x\n", - mode == SVC_MODE ? '*' : ' ', - mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); - fiq_debugger_printf(state, - "%cabt: sp %08x lr %08x spsr %08x\n", - mode == ABT_MODE ? '*' : ' ', - mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); - fiq_debugger_printf(state, - "%cund: sp %08x lr %08x spsr %08x\n", - mode == UND_MODE ? '*' : ' ', - mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); - fiq_debugger_printf(state, - "%cirq: sp %08x lr %08x spsr %08x\n", - mode == IRQ_MODE ? '*' : ' ', - mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); - fiq_debugger_printf(state, - "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", - mode == FIQ_MODE ? '*' : ' ', - mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, - mode_regs.r11_fiq, mode_regs.r12_fiq); - fiq_debugger_printf(state, - " fiq: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); -} - static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) { int n; @@ -405,98 +282,6 @@ static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) } } -struct stacktrace_state { - struct fiq_debugger_state *state; - unsigned int depth; -}; - -static int report_trace(struct stackframe *frame, void *d) -{ - struct stacktrace_state *sts = d; - - if (sts->depth) { - fiq_debugger_printf(sts->state, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - frame->pc, frame->pc, frame->lr, frame->lr, - frame->sp, frame->fp); - sts->depth--; - return 0; - } - fiq_debugger_printf(sts->state, " ...\n"); - - return sts->depth == 0; -} - -struct frame_tail { - struct frame_tail *fp; - unsigned long sp; - unsigned long lr; -} __attribute__((packed)); - -static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, - struct frame_tail *tail) -{ - struct frame_tail buftail[2]; - - /* Also check accessibility of one struct frame_tail beyond */ - if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { - fiq_debugger_printf(state, " invalid frame pointer %p\n", - tail); - return NULL; - } - if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { - fiq_debugger_printf(state, - " failed to copy frame pointer %p\n", tail); - return NULL; - } - - fiq_debugger_printf(state, " %p\n", buftail[0].lr); - - /* frame pointers should strictly progress back up the stack - * (towards higher addresses) */ - if (tail >= buftail[0].fp) - return NULL; - - return buftail[0].fp-1; -} - -void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, - const struct pt_regs *regs, unsigned int depth, void *ssp) -{ - struct frame_tail *tail; - struct thread_info *real_thread_info = THREAD_INFO(ssp); - struct stacktrace_state sts; - - sts.depth = depth; - sts.state = state; - *current_thread_info() = *real_thread_info; - - if (!current) - fiq_debugger_printf(state, "current NULL\n"); - else - fiq_debugger_printf(state, "pid: %d comm: %s\n", - current->pid, current->comm); - fiq_debugger_dump_regs(state, regs); - - if (!user_mode(regs)) { - struct stackframe frame; - frame.fp = regs->ARM_fp; - frame.sp = regs->ARM_sp; - frame.lr = regs->ARM_lr; - frame.pc = regs->ARM_pc; - fiq_debugger_printf(state, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, - regs->ARM_sp, regs->ARM_fp); - walk_stackframe(&frame, report_trace, &sts); - return; - } - - tail = ((struct frame_tail *) regs->ARM_fp) - 1; - while (depth-- && tail && !((unsigned long) tail & 3)) - tail = user_backtrace(state, tail); -} - static void fiq_debugger_do_ps(struct fiq_debugger_state *state) { struct task_struct *g; @@ -692,9 +477,7 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { fiq_debugger_help(state); } else if (!strcmp(cmd, "pc")) { - fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n", - regs->ARM_pc, regs->ARM_cpsr, - mode_name(regs->ARM_cpsr)); + fiq_debugger_dump_pc(state, regs); } else if (!strcmp(cmd, "regs")) { fiq_debugger_dump_regs(state, regs); } else if (!strcmp(cmd, "allregs")) { diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c new file mode 100644 index 000000000000..fca12737d224 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include + +#include "fiq_debugger_priv.h" + +static char *mode_name(unsigned cpsr) +{ + switch (cpsr & MODE_MASK) { + case USR_MODE: return "USR"; + case FIQ_MODE: return "FIQ"; + case IRQ_MODE: return "IRQ"; + case SVC_MODE: return "SVC"; + case ABT_MODE: return "ABT"; + case UND_MODE: return "UND"; + case SYSTEM_MODE: return "SYS"; + default: return "???"; + } +} + +void fiq_debugger_dump_pc(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n", + regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr)); +} + +void fiq_debugger_dump_regs(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + fiq_debugger_printf(state, + " r0 %08x r1 %08x r2 %08x r3 %08x\n", + regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); + fiq_debugger_printf(state, + " r4 %08x r5 %08x r6 %08x r7 %08x\n", + regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); + fiq_debugger_printf(state, + " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", + regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, + mode_name(regs->ARM_cpsr)); + fiq_debugger_printf(state, + " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, + regs->ARM_cpsr); +} + +struct mode_regs { + unsigned long sp_svc; + unsigned long lr_svc; + unsigned long spsr_svc; + + unsigned long sp_abt; + unsigned long lr_abt; + unsigned long spsr_abt; + + unsigned long sp_und; + unsigned long lr_und; + unsigned long spsr_und; + + unsigned long sp_irq; + unsigned long lr_irq; + unsigned long spsr_irq; + + unsigned long r8_fiq; + unsigned long r9_fiq; + unsigned long r10_fiq; + unsigned long r11_fiq; + unsigned long r12_fiq; + unsigned long sp_fiq; + unsigned long lr_fiq; + unsigned long spsr_fiq; +}; + +static void __naked get_mode_regs(struct mode_regs *regs) +{ + asm volatile ( + "mrs r1, cpsr\n" + "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r8 - r14}\n" + "mrs r2, spsr\n" + "stmia r0!, {r2}\n" + "msr cpsr_c, r1\n" + "bx lr\n"); +} + + +void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + struct mode_regs mode_regs; + unsigned long mode = regs->ARM_cpsr & MODE_MASK; + + fiq_debugger_dump_regs(state, regs); + get_mode_regs(&mode_regs); + + fiq_debugger_printf(state, + "%csvc: sp %08x lr %08x spsr %08x\n", + mode == SVC_MODE ? '*' : ' ', + mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); + fiq_debugger_printf(state, + "%cabt: sp %08x lr %08x spsr %08x\n", + mode == ABT_MODE ? '*' : ' ', + mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); + fiq_debugger_printf(state, + "%cund: sp %08x lr %08x spsr %08x\n", + mode == UND_MODE ? '*' : ' ', + mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); + fiq_debugger_printf(state, + "%cirq: sp %08x lr %08x spsr %08x\n", + mode == IRQ_MODE ? '*' : ' ', + mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); + fiq_debugger_printf(state, + "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", + mode == FIQ_MODE ? '*' : ' ', + mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, + mode_regs.r11_fiq, mode_regs.r12_fiq); + fiq_debugger_printf(state, + " fiq: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); +} + +struct stacktrace_state { + struct fiq_debugger_state *state; + unsigned int depth; +}; + +static int report_trace(struct stackframe *frame, void *d) +{ + struct stacktrace_state *sts = d; + + if (sts->depth) { + fiq_debugger_printf(sts->state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + frame->pc, frame->pc, frame->lr, frame->lr, + frame->sp, frame->fp); + sts->depth--; + return 0; + } + fiq_debugger_printf(sts->state, " ...\n"); + + return sts->depth == 0; +} + +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + +static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, + struct frame_tail *tail) +{ + struct frame_tail buftail[2]; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { + fiq_debugger_printf(state, " invalid frame pointer %p\n", + tail); + return NULL; + } + if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { + fiq_debugger_printf(state, + " failed to copy frame pointer %p\n", tail); + return NULL; + } + + fiq_debugger_printf(state, " %p\n", buftail[0].lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= buftail[0].fp) + return NULL; + + return buftail[0].fp-1; +} + +void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, + const struct pt_regs *regs, unsigned int depth, void *ssp) +{ + struct frame_tail *tail; + struct thread_info *real_thread_info = THREAD_INFO(ssp); + struct stacktrace_state sts; + + sts.depth = depth; + sts.state = state; + *current_thread_info() = *real_thread_info; + + if (!current) + fiq_debugger_printf(state, "current NULL\n"); + else + fiq_debugger_printf(state, "pid: %d comm: %s\n", + current->pid, current->comm); + fiq_debugger_dump_regs(state, regs); + + if (!user_mode(regs)) { + struct stackframe frame; + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + frame.pc = regs->ARM_pc; + fiq_debugger_printf(state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, + regs->ARM_sp, regs->ARM_fp); + walk_stackframe(&frame, report_trace, &sts); + return; + } + + tail = ((struct frame_tail *) regs->ARM_fp) - 1; + while (depth-- && tail && !((unsigned long) tail & 3)) + tail = user_backtrace(state, tail); +} diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h new file mode 100644 index 000000000000..746cf1b5d55b --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _FIQ_DEBUGGER_PRIV_H_ +#define _FIQ_DEBUGGER_PRIV_H_ + +#define THREAD_INFO(sp) ((struct thread_info *) \ + ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) + +struct fiq_debugger_state; +struct pt_regs; + +int fiq_debugger_printf(void *cookie, const char *fmt, ...); + +void fiq_debugger_dump_pc(struct fiq_debugger_state *state, + const struct pt_regs *regs); +void fiq_debugger_dump_regs(struct fiq_debugger_state *state, + const struct pt_regs *regs); +void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, + const struct pt_regs *regs); +void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, + const struct pt_regs *regs, unsigned int depth, void *ssp); + +#endif From a0f3f0f28e1636405b4c736eb7b9bd557cf11ad7 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 2 Apr 2014 18:49:39 -0700 Subject: [PATCH 06/21] fiq_debugger: add ARM64 support Add fiq_debugger_arm64.c that implements the platform-specific functions. Change-Id: I4d8b96777bb8503a93d4eb47bbde8e018740a5bf Signed-off-by: Colin Cross --- drivers/staging/android/fiq_debugger/Kconfig | 2 +- drivers/staging/android/fiq_debugger/Makefile | 1 + .../android/fiq_debugger/fiq_debugger_arm64.c | 202 ++++++++++++++++++ 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c diff --git a/drivers/staging/android/fiq_debugger/Kconfig b/drivers/staging/android/fiq_debugger/Kconfig index 803fb59cc82f..d87978cc7dee 100644 --- a/drivers/staging/android/fiq_debugger/Kconfig +++ b/drivers/staging/android/fiq_debugger/Kconfig @@ -1,7 +1,7 @@ config FIQ_DEBUGGER bool "FIQ Mode Serial Debugger" default n - depends on ARM + depends on ARM || ARM64 help The FIQ serial debugger can accept commands even when the kernel is unresponsive due to being stuck with interrupts diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile index 1e203aed8c62..c95da7eb1b33 100644 --- a/drivers/staging/android/fiq_debugger/Makefile +++ b/drivers/staging/android/fiq_debugger/Makefile @@ -1,2 +1,3 @@ obj-y += fiq_debugger.o obj-$(CONFIG_ARM) += fiq_debugger_arm.o +obj-$(CONFIG_ARM64) += fiq_debugger_arm64.o \ No newline at end of file diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c new file mode 100644 index 000000000000..cbca82b70533 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include "fiq_debugger_priv.h" + +static char *mode_name(const struct pt_regs *regs) +{ + if (compat_user_mode(regs)) { + return "USR"; + } else { + switch (processor_mode(regs)) { + case PSR_MODE_EL0t: return "EL0t"; + case PSR_MODE_EL1t: return "EL1t"; + case PSR_MODE_EL1h: return "EL1h"; + case PSR_MODE_EL2t: return "EL2t"; + case PSR_MODE_EL2h: return "EL2h"; + default: return "???"; + } + } +} + +void fiq_debugger_dump_pc(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + fiq_debugger_printf(state, " pc %016lx cpsr %08lx mode %s\n", + regs->pc, regs->pstate, mode_name(regs)); +} + +void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + fiq_debugger_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + regs->compat_usr(0), regs->compat_usr(1), + regs->compat_usr(2), regs->compat_usr(3)); + fiq_debugger_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + regs->compat_usr(4), regs->compat_usr(5), + regs->compat_usr(6), regs->compat_usr(7)); + fiq_debugger_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x\n", + regs->compat_usr(8), regs->compat_usr(9), + regs->compat_usr(10), regs->compat_usr(11)); + fiq_debugger_printf(state, " ip %08x sp %08x lr %08x pc %08x\n", + regs->compat_usr(12), regs->compat_sp, + regs->compat_lr, regs->pc); + fiq_debugger_printf(state, " cpsr %08x (%s)\n", + regs->pstate, mode_name(regs)); +} + +void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + + fiq_debugger_printf(state, " x0 %016lx x1 %016lx\n", + regs->regs[0], regs->regs[1]); + fiq_debugger_printf(state, " x2 %016lx x3 %016lx\n", + regs->regs[2], regs->regs[3]); + fiq_debugger_printf(state, " x4 %016lx x5 %016lx\n", + regs->regs[4], regs->regs[5]); + fiq_debugger_printf(state, " x6 %016lx x7 %016lx\n", + regs->regs[6], regs->regs[7]); + fiq_debugger_printf(state, " x8 %016lx x9 %016lx\n", + regs->regs[8], regs->regs[9]); + fiq_debugger_printf(state, " x10 %016lx x11 %016lx\n", + regs->regs[10], regs->regs[11]); + fiq_debugger_printf(state, " x12 %016lx x13 %016lx\n", + regs->regs[12], regs->regs[13]); + fiq_debugger_printf(state, " x14 %016lx x15 %016lx\n", + regs->regs[14], regs->regs[15]); + fiq_debugger_printf(state, " x16 %016lx x17 %016lx\n", + regs->regs[16], regs->regs[17]); + fiq_debugger_printf(state, " x18 %016lx x19 %016lx\n", + regs->regs[18], regs->regs[19]); + fiq_debugger_printf(state, " x20 %016lx x21 %016lx\n", + regs->regs[20], regs->regs[21]); + fiq_debugger_printf(state, " x22 %016lx x23 %016lx\n", + regs->regs[22], regs->regs[23]); + fiq_debugger_printf(state, " x24 %016lx x25 %016lx\n", + regs->regs[24], regs->regs[25]); + fiq_debugger_printf(state, " x26 %016lx x27 %016lx\n", + regs->regs[26], regs->regs[27]); + fiq_debugger_printf(state, " x28 %016lx x29 %016lx\n", + regs->regs[28], regs->regs[29]); + fiq_debugger_printf(state, " x30 %016lx sp %016lx\n", + regs->regs[30], regs->sp); + fiq_debugger_printf(state, " pc %016lx cpsr %08x (%s)\n", + regs->pc, regs->pstate, mode_name(regs)); +} + +void fiq_debugger_dump_regs(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + if (compat_user_mode(regs)) + fiq_debugger_dump_regs_aarch32(state, regs); + else + fiq_debugger_dump_regs_aarch64(state, regs); +} + +#define READ_SPECIAL_REG(x) ({ \ + u64 val; \ + asm volatile ("mrs %0, " # x : "=r"(val)); \ + val; \ +}) + +void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + u32 pstate = READ_SPECIAL_REG(CurrentEl); + bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t; + + fiq_debugger_dump_regs(state, regs); + + fiq_debugger_printf(state, " sp_el0 %016lx\n", + READ_SPECIAL_REG(sp_el0)); + + if (in_el2) + fiq_debugger_printf(state, " sp_el1 %016lx\n", + READ_SPECIAL_REG(sp_el1)); + + fiq_debugger_printf(state, " elr_el1 %016lx\n", + READ_SPECIAL_REG(elr_el1)); + + fiq_debugger_printf(state, " spsr_el1 %08lx\n", + READ_SPECIAL_REG(spsr_el1)); + + if (in_el2) { + fiq_debugger_printf(state, " spsr_irq %08lx\n", + READ_SPECIAL_REG(spsr_irq)); + fiq_debugger_printf(state, " spsr_abt %08lx\n", + READ_SPECIAL_REG(spsr_abt)); + fiq_debugger_printf(state, " spsr_und %08lx\n", + READ_SPECIAL_REG(spsr_und)); + fiq_debugger_printf(state, " spsr_fiq %08lx\n", + READ_SPECIAL_REG(spsr_fiq)); + fiq_debugger_printf(state, " spsr_el2 %08lx\n", + READ_SPECIAL_REG(elr_el2)); + fiq_debugger_printf(state, " spsr_el2 %08lx\n", + READ_SPECIAL_REG(spsr_el2)); + } +} + +struct stacktrace_state { + struct fiq_debugger_state *state; + unsigned int depth; +}; + +static int report_trace(struct stackframe *frame, void *d) +{ + struct stacktrace_state *sts = d; + + if (sts->depth) { + fiq_debugger_printf(sts->state, "%pF:\n", frame->pc); + fiq_debugger_printf(sts->state, + " pc %016lx sp %016lx fp %016lx\n", + frame->pc, frame->sp, frame->fp); + sts->depth--; + return 0; + } + fiq_debugger_printf(sts->state, " ...\n"); + + return sts->depth == 0; +} + +void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, + const struct pt_regs *regs, unsigned int depth, void *ssp) +{ + struct thread_info *real_thread_info = THREAD_INFO(ssp); + struct stacktrace_state sts; + + sts.depth = depth; + sts.state = state; + *current_thread_info() = *real_thread_info; + + if (!current) + fiq_debugger_printf(state, "current NULL\n"); + else + fiq_debugger_printf(state, "pid: %d comm: %s\n", + current->pid, current->comm); + fiq_debugger_dump_regs(state, regs); + + if (!user_mode(regs)) { + struct stackframe frame; + frame.fp = regs->regs[29]; + frame.sp = regs->sp; + frame.pc = regs->pc; + fiq_debugger_printf(state, "\n"); + walk_stackframe(&frame, report_trace, &sts); + } +} From a2acc58bc7460a03627f20842a7169d7a1328299 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 6 Mar 2013 19:10:29 -0800 Subject: [PATCH 07/21] of: fix CONFIG_CMDLINE_EXTEND strlcat takes the size of the buffer, not the number of characters to concatenate. If the size of the device tree command line p is larger than the CONFIG_CMDLINE string data, then strcat(data, p, l) will hit a BUG_ON because strlen(data) > l. Replace the second strlcat with a strncpy plus a manual null termination. Also rearrange the code to reduce indent depth to make it more readable, and replace data with a char *cmdline to avoid extra casts. Signed-off-by: Colin Cross --- drivers/of/fdt.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index ffe1dbc141a4..99a2f7860255 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -685,32 +685,38 @@ static const char *config_cmdline = ""; int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { - unsigned long l; - char *p; + unsigned long l = 0; + char *p = NULL; + char *cmdline = data; pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - if (depth != 1 || !data || + if (depth != 1 || !cmdline || (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) return 0; early_init_dt_check_for_initrd(node); /* Put CONFIG_CMDLINE in if forced or if data had nothing in it to start */ - if (overwrite_incoming_cmdline || !((char *)data)[0]) - strlcpy(data, config_cmdline, COMMAND_LINE_SIZE); + if (overwrite_incoming_cmdline || !cmdline[0]) + strlcpy(cmdline, config_cmdline, COMMAND_LINE_SIZE); /* Retrieve command line unless forcing */ - if (read_dt_cmdline) { + if (read_dt_cmdline) p = of_get_flat_dt_prop(node, "bootargs", &l); - if (p != NULL && l > 0) { - if (concat_cmdline) { - strlcat(data, " ", COMMAND_LINE_SIZE); - strlcat(data, p, min_t(int, (int)l, - COMMAND_LINE_SIZE)); - } else - strlcpy(data, p, min_t(int, (int)l, - COMMAND_LINE_SIZE)); + + if (p != NULL && l > 0) { + if (concat_cmdline) { + int cmdline_len; + int copy_len; + strlcat(cmdline, " ", COMMAND_LINE_SIZE); + cmdline_len = strlen(cmdline); + copy_len = COMMAND_LINE_SIZE - cmdline_len - 1; + copy_len = min((int)l, copy_len); + strncpy(cmdline + cmdline_len, p, copy_len); + cmdline[cmdline_len + copy_len] = '\0'; + } else { + strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE)); } } From 37a591d407084b967bb49acc3fe21c446b075d55 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Fri, 18 Apr 2014 14:07:28 -0700 Subject: [PATCH 08/21] prctl: adds PR_SET_TIMERSLACK_PID for setting timer slack of an arbitrary thread. Second argument is similar to PR_SET_TIMERSLACK, if non-zero then the slack is set to that value otherwise sets it to the default for the thread. Takes PID of the thread as the third argument. This allows power/performance management software to set timer slack for other threads according to its policy for the thread (such as when the thread is designated foreground vs. background activity) Change-Id: I744d451ff4e60dae69f38f53948ff36c51c14a3f Signed-off-by: Ruchi Kandoi --- include/uapi/linux/prctl.h | 6 ++++++ kernel/sys.c | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 253856a2a8ad..28bb0b3a08bf 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -149,6 +149,12 @@ #define PR_GET_TID_ADDRESS 40 +/* Sets the timerslack for arbitrary threads + * arg2 slack value, 0 means "use default" + * arg3 pid of the thread whose timer slack needs to be set + */ +#define PR_SET_TIMERSLACK_PID 41 + #define PR_SET_VMA 0x53564d41 # define PR_SET_VMA_ANON_NAME 0 diff --git a/kernel/sys.c b/kernel/sys.c index 126b7c939d1f..875529e936ab 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -2252,6 +2253,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5) { struct task_struct *me = current; + struct task_struct *tsk; unsigned char comm[sizeof(me->comm)]; long error; @@ -2375,6 +2377,23 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else return -EINVAL; break; + case PR_SET_TIMERSLACK_PID: + rcu_read_lock(); + tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns); + if (tsk == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + get_task_struct(tsk); + rcu_read_unlock(); + if (arg2 <= 0) + tsk->timer_slack_ns = + tsk->default_timer_slack_ns; + else + tsk->timer_slack_ns = arg2; + put_task_struct(tsk); + error = 0; + break; default: return -EINVAL; } From e8430cbed3ef15fdb1ac26cfd020e010aa5f1c35 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Tue, 25 Mar 2014 16:43:28 -0700 Subject: [PATCH 09/21] nf: IDLETIMER: time-stamp and suspend/resume handling. Message notifications contains an additional timestamp field in nano seconds. The expiry time for the timers are modified during suspend/resume. If timer was supposed to expire while the system is suspended then a notification is sent when it resumes with the timestamp of the scheduled expiry. Removes the race condition for multiple work scheduled. Bug: 13247811 Change-Id: I752c5b00225fe7085482819f975cc0eb5af89bff Signed-off-by: Ruchi Kandoi --- net/netfilter/xt_IDLETIMER.c | 169 +++++++++++++++++++++++++++++++---- 1 file changed, 152 insertions(+), 17 deletions(-) diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index df91e26f55f2..43ced837a6c2 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -42,6 +42,11 @@ #include #include #include +#include +#include +#include +#include +#include #include struct idletimer_tg_attr { @@ -58,22 +63,65 @@ struct idletimer_tg { struct kobject *kobj; struct idletimer_tg_attr attr; + struct timespec delayed_timer_trigger; + struct timespec last_modified_timer; + struct timespec last_suspend_time; + struct notifier_block pm_nb; + + int timeout; unsigned int refcnt; + bool work_pending; bool send_nl_msg; bool active; }; static LIST_HEAD(idletimer_tg_list); static DEFINE_MUTEX(list_mutex); +static DEFINE_SPINLOCK(timestamp_lock); static struct kobject *idletimer_tg_kobj; +static bool check_for_delayed_trigger(struct idletimer_tg *timer, + struct timespec *ts) +{ + bool state; + struct timespec temp; + spin_lock_bh(×tamp_lock); + timer->work_pending = false; + if ((ts->tv_sec - timer->last_modified_timer.tv_sec) > timer->timeout || + timer->delayed_timer_trigger.tv_sec != 0) { + state = false; + temp.tv_sec = timer->timeout; + temp.tv_nsec = 0; + if (timer->delayed_timer_trigger.tv_sec != 0) { + temp = timespec_add(timer->delayed_timer_trigger, temp); + ts->tv_sec = temp.tv_sec; + ts->tv_nsec = temp.tv_nsec; + timer->delayed_timer_trigger.tv_sec = 0; + timer->work_pending = true; + schedule_work(&timer->work); + } else { + temp = timespec_add(timer->last_modified_timer, temp); + ts->tv_sec = temp.tv_sec; + ts->tv_nsec = temp.tv_nsec; + } + } else { + state = timer->active; + } + spin_unlock_bh(×tamp_lock); + return state; +} + static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer) { char iface_msg[NLMSG_MAX_SIZE]; char state_msg[NLMSG_MAX_SIZE]; - char *envp[] = { iface_msg, state_msg, NULL }; + char timestamp_msg[NLMSG_MAX_SIZE]; + char *envp[] = { iface_msg, state_msg, timestamp_msg, NULL }; int res; + struct timespec ts; + uint64_t time_ns; + bool state; res = snprintf(iface_msg, NLMSG_MAX_SIZE, "INTERFACE=%s", iface); @@ -81,12 +129,24 @@ static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer) pr_err("message too long (%d)", res); return; } + + get_monotonic_boottime(&ts); + state = check_for_delayed_trigger(timer, &ts); res = snprintf(state_msg, NLMSG_MAX_SIZE, "STATE=%s", - timer->active ? "active" : "inactive"); + state ? "active" : "inactive"); + if (NLMSG_MAX_SIZE <= res) { pr_err("message too long (%d)", res); return; } + + time_ns = timespec_to_ns(&ts); + res = snprintf(timestamp_msg, NLMSG_MAX_SIZE, "TIME_NS=%llu", time_ns); + if (NLMSG_MAX_SIZE <= res) { + timestamp_msg[0] = '\0'; + pr_err("message too long (%d)", res); + } + pr_debug("putting nlmsg: <%s> <%s>\n", iface_msg, state_msg); kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp); return; @@ -151,9 +211,55 @@ static void idletimer_tg_expired(unsigned long data) struct idletimer_tg *timer = (struct idletimer_tg *) data; pr_debug("timer %s expired\n", timer->attr.attr.name); - + spin_lock_bh(×tamp_lock); timer->active = false; + timer->work_pending = true; schedule_work(&timer->work); + spin_unlock_bh(×tamp_lock); +} + +static int idletimer_resume(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + struct timespec ts; + unsigned long time_diff, now = jiffies; + struct idletimer_tg *timer = container_of(notifier, + struct idletimer_tg, pm_nb); + if (!timer) + return NOTIFY_DONE; + switch (pm_event) { + case PM_SUSPEND_PREPARE: + get_monotonic_boottime(&timer->last_suspend_time); + break; + case PM_POST_SUSPEND: + spin_lock_bh(×tamp_lock); + if (!timer->active) { + spin_unlock_bh(×tamp_lock); + break; + } + /* since jiffies are not updated when suspended now represents + * the time it would have suspended */ + if (time_after(timer->timer.expires, now)) { + get_monotonic_boottime(&ts); + ts = timespec_sub(ts, timer->last_suspend_time); + time_diff = timespec_to_jiffies(&ts); + if (timer->timer.expires > (time_diff + now)) { + mod_timer_pending(&timer->timer, + (timer->timer.expires - time_diff)); + } else { + del_timer(&timer->timer); + timer->timer.expires = 0; + timer->active = false; + timer->work_pending = true; + schedule_work(&timer->work); + } + } + spin_unlock_bh(×tamp_lock); + break; + default: + break; + } + return NOTIFY_DONE; } static int idletimer_tg_create(struct idletimer_tg_info *info) @@ -187,6 +293,18 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) info->timer->refcnt = 1; info->timer->send_nl_msg = (info->send_nl_msg == 0) ? false : true; info->timer->active = true; + info->timer->timeout = info->timeout; + + info->timer->delayed_timer_trigger.tv_sec = 0; + info->timer->delayed_timer_trigger.tv_nsec = 0; + info->timer->work_pending = false; + get_monotonic_boottime(&info->timer->last_modified_timer); + + info->timer->pm_nb.notifier_call = idletimer_resume; + ret = register_pm_notifier(&info->timer->pm_nb); + if (ret) + printk(KERN_WARNING "[%s] Failed to register pm notifier %d\n", + __func__, ret); mod_timer(&info->timer->timer, msecs_to_jiffies(info->timeout * 1000) + jiffies); @@ -203,6 +321,34 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) return ret; } +static void reset_timer(const struct idletimer_tg_info *info) +{ + unsigned long now = jiffies; + struct idletimer_tg *timer = info->timer; + bool timer_prev; + + spin_lock_bh(×tamp_lock); + timer_prev = timer->active; + timer->active = true; + /* timer_prev is used to guard overflow problem in time_before*/ + if (!timer_prev || time_before(timer->timer.expires, now)) { + pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n", + timer->timer.expires, now); + /* checks if there is a pending inactive notification*/ + if (timer->work_pending) + timer->delayed_timer_trigger = timer->last_modified_timer; + else { + timer->work_pending = true; + schedule_work(&timer->work); + } + } + + get_monotonic_boottime(&timer->last_modified_timer); + mod_timer(&timer->timer, + msecs_to_jiffies(info->timeout * 1000) + now); + spin_unlock_bh(×tamp_lock); +} + /* * The actual xt_tables plugin. */ @@ -226,9 +372,7 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb, } /* TODO: Avoid modifying timers on each packet */ - mod_timer(&info->timer->timer, - msecs_to_jiffies(info->timeout * 1000) + now); - + reset_timer(info); return XT_CONTINUE; } @@ -257,17 +401,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) info->timer = __idletimer_tg_find_by_label(info->label); if (info->timer) { info->timer->refcnt++; - info->timer->active = true; - - if (time_before(info->timer->timer.expires, now)) { - schedule_work(&info->timer->work); - pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n", - info->timer->timer.expires, now); - } - - mod_timer(&info->timer->timer, - msecs_to_jiffies(info->timeout * 1000) + now); - + reset_timer(info); pr_debug("increased refcnt of timer %s to %u\n", info->label, info->timer->refcnt); } else { @@ -298,6 +432,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) list_del(&info->timer->entry); del_timer_sync(&info->timer->timer); sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr); + unregister_pm_notifier(&info->timer->pm_nb); kfree(info->timer->attr.attr.name); kfree(info->timer); } else { From c1bceaea3e32167babd4c89c7085f4c2f6ad473f Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Mon, 21 Apr 2014 13:09:23 -0700 Subject: [PATCH 10/21] video: adf: use rb_erase in adf_obj_destroy. Not calling rb_erase() can cause slab corruption, as the rb_first() call after kfree() in adf_obj_destroy() can return the same node twice unless it is erased. This problem was reproduced by unloading a kernel module that used the adf framework *after* a vsync event was registered. A crash would occur in rb_first(). (Just loading and immediately unloading the module without the vsync event worked correctly.) Change-Id: I9fa7cb5d7519691e38a281439844aa193da13d1b Signed-off-by: Alistair Strachan Cc: Jonathan Hamilton Cc: Greg Hackmann --- drivers/video/adf/adf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c index e6ef144136c2..231881c2b355 100644 --- a/drivers/video/adf/adf.c +++ b/drivers/video/adf/adf.c @@ -494,6 +494,7 @@ static void adf_obj_destroy(struct adf_obj *obj, struct idr *idr) struct adf_event_refcount *refcount = container_of(node, struct adf_event_refcount, node); + rb_erase(&refcount->node, &obj->event_refcount); kfree(refcount); node = rb_first(&obj->event_refcount); } From dcccad71cfc9012fce4bdb780f5e7e6166bb7fa0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Aug 2013 12:08:17 -0400 Subject: [PATCH 11/21] cope with potentially long ->d_dname() output for shmem/hugetlb commit 118b23022512eb2f41ce42db70dc0568d00be4ba upstream. dynamic_dname() is both too much and too little for those - the output may be well in excess of 64 bytes dynamic_dname() assumes to be enough (thanks to ashmem feeding really long names to shmem_file_setup()) and vsnprintf() is an overkill for those guys. Signed-off-by: Al Viro Cc: Colin Cross Signed-off-by: Greg Kroah-Hartman Change-Id: I70970c6125f377048664eb5bde08f3fae29aa348 --- fs/dcache.c | 11 +++++++++++ fs/hugetlbfs/inode.c | 8 +------- include/linux/dcache.h | 1 + mm/shmem.c | 8 +------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index f09b9085f7d8..da89cdfb21ab 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2724,6 +2724,17 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, return memcpy(buffer, temp, sz); } +char *simple_dname(struct dentry *dentry, char *buffer, int buflen) +{ + char *end = buffer + buflen; + /* these dentries are never renamed, so d_lock is not needed */ + if (prepend(&end, &buflen, " (deleted)", 11) || + prepend_name(&end, &buflen, &dentry->d_name) || + prepend(&end, &buflen, "/", 1)) + end = ERR_PTR(-ENAMETOOLONG); + return end; +} + /* * Write full pathname from the root of the filesystem into the buffer. */ diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index a3f868ae3fd4..4e5f332f15d9 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -916,14 +916,8 @@ static int get_hstate_idx(int page_size_log) return h - hstates; } -static char *hugetlb_dname(struct dentry *dentry, char *buffer, int buflen) -{ - return dynamic_dname(dentry, buffer, buflen, "/%s (deleted)", - dentry->d_name.name); -} - static struct dentry_operations anon_ops = { - .d_dname = hugetlb_dname + .d_dname = simple_dname }; /* diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 1a6bb81f0fe5..9be5ac960fd8 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -332,6 +332,7 @@ extern int d_validate(struct dentry *, struct dentry *); * helper function for dentry_operations.d_dname() members */ extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); +extern char *simple_dname(struct dentry *, char *, int); extern char *__d_path(const struct path *, const struct path *, char *, int); extern char *d_absolute_path(const struct path *, char *, int); diff --git a/mm/shmem.c b/mm/shmem.c index 695db3b6216b..6019778b951b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2879,14 +2879,8 @@ EXPORT_SYMBOL_GPL(shmem_truncate_range); /* common code */ -static char *shmem_dname(struct dentry *dentry, char *buffer, int buflen) -{ - return dynamic_dname(dentry, buffer, buflen, "/%s (deleted)", - dentry->d_name.name); -} - static struct dentry_operations anon_ops = { - .d_dname = shmem_dname + .d_dname = simple_dname }; /** From 999aaabf028243fbade7deeeba34e3513825bb91 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 24 Apr 2014 14:07:53 -0700 Subject: [PATCH 12/21] nf: Remove compilation error caused by e8430cbed3ef15fdb1ac26cfd020e010aa5f1c35 Signed-off-by: Ruchi Kandoi --- net/netfilter/xt_IDLETIMER.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index 43ced837a6c2..f6562ba97a97 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -380,7 +380,6 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) { struct idletimer_tg_info *info = par->targinfo; int ret; - unsigned long now = jiffies; pr_debug("checkentry targinfo %s\n", info->label); From 70dc3ed48fb6c02d2c651505d41f8988570f2f81 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 24 Apr 2014 14:31:57 -0700 Subject: [PATCH 13/21] Power: Changes the permission to read only for sysfs file /sys/kernel/wakeup_reasons/last_resume_reason Change-Id: I8ac568a7cb58c31decd379195de517ff3c6f9c65 Signed-off-by: Ruchi Kandoi --- kernel/power/wakeup_reason.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 188a6bfacf5a..187e4e9105fb 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -34,7 +34,7 @@ static int irqcount; static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; -static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, +static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int irq_no, buf_offset = 0; @@ -53,8 +53,7 @@ static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, return buf_offset; } -static struct kobj_attribute resume_reason = __ATTR(last_resume_reason, 0666, - reason_show, NULL); +static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason); static struct attribute *attrs[] = { &resume_reason.attr, From a8fe78a7aa86edfb1259585d2f6cb39b9fce768e Mon Sep 17 00:00:00 2001 From: "Wang, Xiaoming" Date: Mon, 14 Apr 2014 12:30:45 -0400 Subject: [PATCH 14/21] net: ipv4: current group_info should be put after using. Plug a group_info refcount leak in ping_init. group_info is only needed during initialization and the code failed to release the reference on exit. While here move grabbing the reference to a place where it is actually needed. Signed-off-by: Chuansheng Liu Signed-off-by: Zhang Dongxing Signed-off-by: xiaoming wang Signed-off-by: David S. Miller --- net/ipv4/ping.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index edd6e74cad35..111e5a409594 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -249,26 +249,33 @@ int ping_init_sock(struct sock *sk) { struct net *net = sock_net(sk); kgid_t group = current_egid(); - struct group_info *group_info = get_current_groups(); - int i, j, count = group_info->ngroups; + struct group_info *group_info; + int i, j, count; kgid_t low, high; + int ret = 0; inet_get_ping_group_range_net(net, &low, &high); if (gid_lte(low, group) && gid_lte(group, high)) return 0; + group_info = get_current_groups(); + count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { int cp_count = min_t(int, NGROUPS_PER_BLOCK, count); for (j = 0; j < cp_count; j++) { kgid_t gid = group_info->blocks[i][j]; if (gid_lte(low, gid) && gid_lte(gid, high)) - return 0; + goto out_release_group; } count -= cp_count; } - return -EACCES; + ret = -EACCES; + +out_release_group: + put_group_info(group_info); + return ret; } EXPORT_SYMBOL_GPL(ping_init_sock); From 77232898045d67b125d33399c91ae141d3e3c6c1 Mon Sep 17 00:00:00 2001 From: Mathieu Meisser Date: Fri, 11 Apr 2014 17:42:19 +0200 Subject: [PATCH 15/21] HID: add missing hid usages mappings Integrate several new definitions (not code) that add additional hid mappings from the HID HUT 1.12 and approved additional requests. Additions are taken from the commits in the linux-input upstream: f362e69, 2a4d815, 3b5a7ab, 358f247, 701ba53, d09bbfd, af8036d, 5820e4d, a443255 Change-Id: Id0e1cff5828062009b4f94c987ac91f88f14652e Signed-off-by: Mathieu Meisser Signed-off-by: Olivier Gay --- drivers/hid/hid-debug.c | 15 +++++++++++++- drivers/hid/hid-input.c | 17 ++++++++++++++++ include/uapi/linux/input.h | 40 ++++++++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 8453214ec376..941ab3c287ec 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -768,6 +768,8 @@ static const char *keys[KEY_MAX + 1] = { [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", + [BTN_DPAD_UP] = "BtnDPadUp", [BTN_DPAD_DOWN] = "BtnDPadDown", + [BTN_DPAD_LEFT] = "BtnDPadLeft", [BTN_DPAD_RIGHT] = "BtnDPadRight", [BTN_0] = "Btn0", [BTN_1] = "Btn1", [BTN_2] = "Btn2", [BTN_3] = "Btn3", [BTN_4] = "Btn4", [BTN_5] = "Btn5", @@ -797,7 +799,8 @@ static const char *keys[KEY_MAX + 1] = { [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", - [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", + [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_TOOL_QUADTAP] = "ToolQuadrupleTap", + [BTN_GEAR_DOWN] = "WheelBtn", [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", @@ -852,6 +855,16 @@ static const char *keys[KEY_MAX + 1] = { [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", [KEY_KBDILLUMUP] = "KbdIlluminationUp", [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", + [KEY_BUTTONCONFIG] = "ButtonConfig", + [KEY_TASKMANAGER] = "TaskManager", + [KEY_JOURNAL] = "Journal", + [KEY_CONTROLPANEL] = "ControlPanel", + [KEY_APPSELECT] = "AppSelect", + [KEY_SCREENSAVER] = "ScreenSaver", + [KEY_VOICECOMMAND] = "VoiceCommand", + [KEY_BRIGHTNESS_MIN] = "BrightnessMin", + [KEY_BRIGHTNESS_MAX] = "BrightnessMax", + [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", }; static const char *relatives[REL_MAX + 1] = { diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 4602d291c9bc..2df9cdcba0de 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -714,6 +714,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x06c: map_key_clear(KEY_YELLOW); break; case 0x06d: map_key_clear(KEY_ZOOM); break; + case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break; + case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break; + case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break; + case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break; + case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break; + case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); break; + case 0x082: map_key_clear(KEY_VIDEO_NEXT); break; case 0x083: map_key_clear(KEY_LAST); break; case 0x084: map_key_clear(KEY_ENTER); break; @@ -754,6 +761,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0bf: map_key_clear(KEY_SLOW); break; case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; + case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break; case 0x0e0: map_abs_clear(ABS_VOLUME); break; case 0x0e2: map_key_clear(KEY_MUTE); break; case 0x0e5: map_key_clear(KEY_BASSBOOST); break; @@ -761,6 +769,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; case 0x0f5: map_key_clear(KEY_SLOW); break; + case 0x181: map_key_clear(KEY_BUTTONCONFIG); break; case 0x182: map_key_clear(KEY_BOOKMARKS); break; case 0x183: map_key_clear(KEY_CONFIG); break; case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; @@ -774,6 +783,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x18c: map_key_clear(KEY_VOICEMAIL); break; case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break; case 0x18e: map_key_clear(KEY_CALENDAR); break; + case 0x18f: map_key_clear(KEY_TASKMANAGER); break; + case 0x190: map_key_clear(KEY_JOURNAL); break; case 0x191: map_key_clear(KEY_FINANCE); break; case 0x192: map_key_clear(KEY_CALC); break; case 0x193: map_key_clear(KEY_PLAYER); break; @@ -782,10 +793,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x199: map_key_clear(KEY_CHAT); break; case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19e: map_key_clear(KEY_COFFEE); break; + case 0x19f: map_key_clear(KEY_CONTROLPANEL); break; + case 0x1a2: map_key_clear(KEY_APPSELECT); break; + case 0x1a3: map_key_clear(KEY_NEXT); break; + case 0x1a4: map_key_clear(KEY_PREVIOUS); break; case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; case 0x1ae: map_key_clear(KEY_KEYBOARD); break; + case 0x1b1: map_key_clear(KEY_SCREENSAVER); break; + case 0x1b4: map_key_clear(KEY_FILE); break; case 0x1b6: map_key_clear(KEY_IMAGES); break; case 0x1b7: map_key_clear(KEY_AUDIO); break; case 0x1b8: map_key_clear(KEY_VIDEO); break; diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 93a956489e87..a86f5301c609 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -461,10 +461,14 @@ struct input_keymap_entry { #define KEY_VIDEO_NEXT 241 /* drive next video source */ #define KEY_VIDEO_PREV 242 /* drive previous video source */ #define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ -#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ +#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual + brightness control is off, + rely on ambient */ +#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO #define KEY_DISPLAY_OFF 245 /* display device to off state */ -#define KEY_WIMAX 246 +#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ +#define KEY_WIMAX KEY_WWAN #define KEY_RFKILL 247 /* Key that controls all radios */ #define KEY_MICMUTE 248 /* Mute / unmute the microphone */ @@ -509,11 +513,15 @@ struct input_keymap_entry { #define BTN_DEAD 0x12f #define BTN_GAMEPAD 0x130 -#define BTN_A 0x130 -#define BTN_B 0x131 +#define BTN_SOUTH 0x130 +#define BTN_A BTN_SOUTH +#define BTN_EAST 0x131 +#define BTN_B BTN_EAST #define BTN_C 0x132 -#define BTN_X 0x133 -#define BTN_Y 0x134 +#define BTN_NORTH 0x133 +#define BTN_X BTN_NORTH +#define BTN_WEST 0x134 +#define BTN_Y BTN_WEST #define BTN_Z 0x135 #define BTN_TL 0x136 #define BTN_TR 0x137 @@ -626,6 +634,7 @@ struct input_keymap_entry { #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ #define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ +#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE #define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ #define KEY_LOGOFF 0x1b1 /* AL Logoff */ @@ -710,6 +719,24 @@ struct input_keymap_entry { #define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ #define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ +#define BTN_DPAD_UP 0x220 +#define BTN_DPAD_DOWN 0x221 +#define BTN_DPAD_LEFT 0x222 +#define BTN_DPAD_RIGHT 0x223 + +#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ + +#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ +#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ +#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ +#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ +#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ +#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ +#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ + +#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ +#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ + #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY2 0x2c1 @@ -847,6 +874,7 @@ struct input_keymap_entry { #define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ #define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ #define SW_LINEIN_INSERT 0x0d /* set = inserted */ +#define SW_MUTE_DEVICE 0x0e /* set = device disabled */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) From 6cb247b4ad17862ca47cb251c23b69a2dc321e89 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 29 Apr 2014 11:29:04 -0700 Subject: [PATCH 16/21] selinux: Report permissive mode in avc: denied messages. We cannot presently tell from an avc: denied message whether access was in fact denied or was allowed due to global or per-domain permissive mode. Add a permissive= field to the avc message to reflect this information. Change-Id: I78176f8184e01226ece12f0eb38760cdcdc1ff87 Signed-off-by: Stephen Smalley --- security/selinux/avc.c | 7 ++++++- security/selinux/hooks.c | 5 +++-- security/selinux/include/avc.h | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index dad36a6ab45f..c223a32c0bb3 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -444,11 +444,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) avc_dump_query(ab, ad->selinux_audit_data->ssid, ad->selinux_audit_data->tsid, ad->selinux_audit_data->tclass); + if (ad->selinux_audit_data->denied) { + audit_log_format(ab, " permissive=%u", + ad->selinux_audit_data->result ? 0 : 1); + } } /* This is the slow part of avc audit with big stack footprint */ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags) { @@ -477,6 +481,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, sad.tsid = tsid; sad.audited = audited; sad.denied = denied; + sad.result = result; a->selinux_audit_data = &sad; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 11918d7ddb6e..44087388010c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2714,6 +2714,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na static noinline int audit_inode_permission(struct inode *inode, u32 perms, u32 audited, u32 denied, + int result, unsigned flags) { struct common_audit_data ad; @@ -2724,7 +2725,7 @@ static noinline int audit_inode_permission(struct inode *inode, ad.u.inode = inode; rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, - audited, denied, &ad, flags); + audited, denied, result, &ad, flags); if (rc) return rc; return 0; @@ -2766,7 +2767,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) if (likely(!audited)) return rc; - rc2 = audit_inode_permission(inode, perms, audited, denied, flags); + rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags); if (rc2) return rc2; return rc; diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 92d0ab561db8..28a08a891704 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -102,7 +102,7 @@ static inline u32 avc_audit_required(u32 requested, } int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags); @@ -137,7 +137,7 @@ static inline int avc_audit(u32 ssid, u32 tsid, if (likely(!audited)) return 0; return slow_avc_audit(ssid, tsid, tclass, - requested, audited, denied, + requested, audited, denied, result, a, flags); } From 220471ac6b644beb64a2d62eaaca409f56e75293 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Mon, 28 Apr 2014 17:00:44 -0700 Subject: [PATCH 17/21] video: adf: memblock: map buffer for dma Change-Id: I4df13c8b45b57fd0594b5e7bf351a4da33a8cb11 Signed-off-by: Greg Hackmann --- drivers/video/adf/adf_memblock.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/video/adf/adf_memblock.c b/drivers/video/adf/adf_memblock.c index aa03809e59b7..e73a7d59f1e6 100644 --- a/drivers/video/adf/adf_memblock.c +++ b/drivers/video/adf/adf_memblock.c @@ -28,7 +28,7 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach, unsigned long pfn = PFN_DOWN(pdata->base); struct page *page = pfn_to_page(pfn); struct sg_table *table; - int ret; + int nents, ret; table = kzalloc(sizeof(*table), GFP_KERNEL); if (!table) @@ -36,12 +36,21 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach, ret = sg_alloc_table(table, 1, GFP_KERNEL); if (ret < 0) - goto err; + goto err_alloc; sg_set_page(table->sgl, page, attach->dmabuf->size, 0); + + nents = dma_map_sg(attach->dev, table->sgl, 1, direction); + if (!nents) { + ret = -EINVAL; + goto err_map; + } + return table; -err: +err_map: + sg_free_table(table); +err_alloc: kfree(table); return ERR_PTR(ret); } @@ -49,6 +58,7 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach, static void adf_memblock_unmap(struct dma_buf_attachment *attach, struct sg_table *table, enum dma_data_direction direction) { + dma_unmap_sg(attach->dev, table->sgl, 1, direction); sg_free_table(table); } From 10689a3985d3a1689bd4f36f0d5327b7d655d1bb Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 29 Apr 2014 11:18:45 -0700 Subject: [PATCH 18/21] video: adf: fbdev: add stubs for kernels without ADF_FBDEV Change-Id: I42e087cddc29f6b93749791606e80dbd3e6f59ce Signed-off-by: Greg Hackmann --- include/video/adf_fbdev.h | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/include/video/adf_fbdev.h b/include/video/adf_fbdev.h index e4d6fb7b25df..b722c6b3ab02 100644 --- a/include/video/adf_fbdev.h +++ b/include/video/adf_fbdev.h @@ -39,6 +39,7 @@ struct adf_fbdev { u32 default_format; }; +#if IS_ENABLED(CONFIG_ADF_FBDEV) void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode, struct fb_videomode *vmode); void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode, @@ -57,5 +58,67 @@ int adf_fbdev_set_par(struct fb_info *info); int adf_fbdev_blank(int blank, struct fb_info *info); int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); int adf_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma); +#else +static inline void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode, + struct fb_videomode *vmode) +{ + WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__); +} + +static inline void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode, + struct drm_mode_modeinfo *mode) +{ + WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__); +} + +static inline int adf_fbdev_init(struct adf_fbdev *fbdev, + struct adf_interface *interface, + struct adf_overlay_engine *eng, + u16 xres_virtual, u16 yres_virtual, u32 format, + struct fb_ops *fbops, const char *fmt, ...) +{ + return -ENODEV; +} + +static inline void adf_fbdev_destroy(struct adf_fbdev *fbdev) { } + +static inline int adf_fbdev_open(struct fb_info *info, int user) +{ + return -ENODEV; +} + +static inline int adf_fbdev_release(struct fb_info *info, int user) +{ + return -ENODEV; +} + +static inline int adf_fbdev_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_set_par(struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_blank(int blank, struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_mmap(struct fb_info *info, + struct vm_area_struct *vma) +{ + return -ENODEV; +} +#endif #endif /* _VIDEO_ADF_FBDEV_H_ */ From 4498669afbf036ce296df6165fa1c46e23dc57c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Fri, 2 May 2014 19:52:54 -0700 Subject: [PATCH 19/21] fiq_debugger: Call fiq_debugger_printf through a function pointer from cpu specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the output from the register and stack trace code to be sent elsewhere. Change-Id: I41bb0d5a25e1b9ca55feef5dbd675818b2f832d5 Signed-off-by: Arve Hjønnevåg --- .../android/fiq_debugger/fiq_debugger.c | 67 ++++++------ .../android/fiq_debugger/fiq_debugger_arm.c | 58 +++++----- .../android/fiq_debugger/fiq_debugger_arm64.c | 102 +++++++++--------- .../android/fiq_debugger/fiq_debugger_priv.h | 15 +-- 4 files changed, 123 insertions(+), 119 deletions(-) diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index 5516d3113b94..7d6b4ae8a2cd 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -54,6 +54,7 @@ struct fiq_debugger_state { #ifdef CONFIG_FIQ_GLUE struct fiq_glue_handler handler; #endif + struct fiq_debugger_output output; int fiq; int uart_irq; @@ -229,18 +230,19 @@ static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state) } } -int fiq_debugger_printf(void *cookie, const char *fmt, ...) +static void fiq_debugger_printf(struct fiq_debugger_output *output, + const char *fmt, ...) { - struct fiq_debugger_state *state = cookie; + struct fiq_debugger_state *state; char buf[256]; va_list ap; + state = container_of(output, struct fiq_debugger_state, output); va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); fiq_debugger_puts(state, buf); - return state->debug_abort; } /* Safe outside fiq context */ @@ -267,13 +269,13 @@ static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) int n; struct irq_desc *desc; - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, "irqnr total since-last status name\n"); for_each_irq_desc(n, desc) { struct irqaction *act = desc->action; if (!act && !kstat_irqs(n)) continue; - fiq_debugger_printf(state, "%5d: %10u %11u %8x %s\n", n, + fiq_debugger_printf(&state->output, "%5d: %10u %11u %8x %s\n", n, kstat_irqs(n), kstat_irqs(n) - state->last_irqs[n], desc->status_use_accessors, @@ -289,18 +291,18 @@ static void fiq_debugger_do_ps(struct fiq_debugger_state *state) unsigned task_state; static const char stat_nam[] = "RSDTtZX"; - fiq_debugger_printf(state, "pid ppid prio task pc\n"); + fiq_debugger_printf(&state->output, "pid ppid prio task pc\n"); read_lock(&tasklist_lock); do_each_thread(g, p) { task_state = p->state ? __ffs(p->state) + 1 : 0; - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, "%5d %5d %4d ", p->pid, p->parent->pid, p->prio); - fiq_debugger_printf(state, "%-13.13s %c", p->comm, + fiq_debugger_printf(&state->output, "%-13.13s %c", p->comm, task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]); if (task_state == TASK_RUNNING) - fiq_debugger_printf(state, " running\n"); + fiq_debugger_printf(&state->output, " running\n"); else - fiq_debugger_printf(state, " %08lx\n", + fiq_debugger_printf(&state->output, " %08lx\n", thread_saved_pc(p)); } while_each_thread(g, p); read_unlock(&tasklist_lock); @@ -332,7 +334,7 @@ static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state) static void fiq_debugger_do_sysrq(struct fiq_debugger_state *state, char rq) { if ((rq == 'g' || rq == 'G') && !fiq_kgdb_enable) { - fiq_debugger_printf(state, "sysrq-g blocked\n"); + fiq_debugger_printf(&state->output, "sysrq-g blocked\n"); return; } fiq_debugger_begin_syslog_dump(state); @@ -344,11 +346,11 @@ static void fiq_debugger_do_sysrq(struct fiq_debugger_state *state, char rq) static void fiq_debugger_do_kgdb(struct fiq_debugger_state *state) { if (!fiq_kgdb_enable) { - fiq_debugger_printf(state, "kgdb through fiq debugger not enabled\n"); + fiq_debugger_printf(&state->output, "kgdb through fiq debugger not enabled\n"); return; } - fiq_debugger_printf(state, "enabling console and triggering kgdb\n"); + fiq_debugger_printf(&state->output, "enabling console and triggering kgdb\n"); state->console_enable = true; handle_sysrq('g'); } @@ -361,7 +363,7 @@ static void fiq_debugger_schedule_work(struct fiq_debugger_state *state, spin_lock_irqsave(&state->work_lock, flags); if (state->work_cmd[0] != '\0') { - fiq_debugger_printf(state, "work command processor busy\n"); + fiq_debugger_printf(&state->output, "work command processor busy\n"); spin_unlock_irqrestore(&state->work_lock, flags); return; } @@ -398,7 +400,7 @@ static void fiq_debugger_work(struct work_struct *work) else kernel_restart(NULL); } else { - fiq_debugger_printf(state, "unknown work command '%s'\n", + fiq_debugger_printf(&state->output, "unknown work command '%s'\n", work_cmd); } } @@ -422,7 +424,7 @@ static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd) static void fiq_debugger_help(struct fiq_debugger_state *state) { - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, "FIQ Debugger commands:\n" " pc PC status\n" " regs Register dump\n" @@ -433,18 +435,18 @@ static void fiq_debugger_help(struct fiq_debugger_state *state) " irqs Interupt status\n" " kmsg Kernel log\n" " version Kernel version\n"); - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, " sleep Allow sleep while in FIQ\n" " nosleep Disable sleep while in FIQ\n" " console Switch terminal to console\n" " cpu Current CPU\n" " cpu Switch to CPU\n"); - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, " ps Process list\n" " sysrq sysrq options\n" " sysrq Execute sysrq with \n"); #ifdef CONFIG_KGDB - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, " kgdb Enter kernel debugger\n"); #endif } @@ -477,13 +479,13 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { fiq_debugger_help(state); } else if (!strcmp(cmd, "pc")) { - fiq_debugger_dump_pc(state, regs); + fiq_debugger_dump_pc(&state->output, regs); } else if (!strcmp(cmd, "regs")) { - fiq_debugger_dump_regs(state, regs); + fiq_debugger_dump_regs(&state->output, regs); } else if (!strcmp(cmd, "allregs")) { - fiq_debugger_dump_allregs(state, regs); + fiq_debugger_dump_allregs(&state->output, regs); } else if (!strcmp(cmd, "bt")) { - fiq_debugger_dump_stacktrace(state, regs, 100, svc_sp); + fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp); } else if (!strncmp(cmd, "reset", 5)) { cmd += 5; while (*cmd == ' ') @@ -500,29 +502,29 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, } else if (!strcmp(cmd, "kmsg")) { fiq_debugger_dump_kernel_log(state); } else if (!strcmp(cmd, "version")) { - fiq_debugger_printf(state, "%s\n", linux_banner); + fiq_debugger_printf(&state->output, "%s\n", linux_banner); } else if (!strcmp(cmd, "sleep")) { state->no_sleep = false; - fiq_debugger_printf(state, "enabling sleep\n"); + fiq_debugger_printf(&state->output, "enabling sleep\n"); } else if (!strcmp(cmd, "nosleep")) { state->no_sleep = true; - fiq_debugger_printf(state, "disabling sleep\n"); + fiq_debugger_printf(&state->output, "disabling sleep\n"); } else if (!strcmp(cmd, "console")) { - fiq_debugger_printf(state, "console mode\n"); + fiq_debugger_printf(&state->output, "console mode\n"); fiq_debugger_uart_flush(state); state->console_enable = true; } else if (!strcmp(cmd, "cpu")) { - fiq_debugger_printf(state, "cpu %d\n", state->current_cpu); + fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); } else if (!strncmp(cmd, "cpu ", 4)) { unsigned long cpu = 0; if (strict_strtoul(cmd + 4, 10, &cpu) == 0) fiq_debugger_switch_cpu(state, cpu); else - fiq_debugger_printf(state, "invalid cpu\n"); - fiq_debugger_printf(state, "cpu %d\n", state->current_cpu); + fiq_debugger_printf(&state->output, "invalid cpu\n"); + fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); } else { if (state->debug_busy) { - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, "command processor busy. trying to abort.\n"); state->debug_abort = -1; } else { @@ -645,7 +647,7 @@ static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state, MAX_UNHANDLED_FIQ_COUNT) return false; - fiq_debugger_printf(state, + fiq_debugger_printf(&state->output, "fiq_debugger: cpu %d not responding, " "reverting to cpu %d\n", state->current_cpu, this_cpu); @@ -1053,6 +1055,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) return -EINVAL; state = kzalloc(sizeof(*state), GFP_KERNEL); + state->output.printf = fiq_debugger_printf; setup_timer(&state->sleep_timer, fiq_debugger_sleep_timer_expired, (unsigned long)state); state->pdata = pdata; diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c index fca12737d224..8b3e0137be1a 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c @@ -34,27 +34,27 @@ static char *mode_name(unsigned cpsr) } } -void fiq_debugger_dump_pc(struct fiq_debugger_state *state, +void fiq_debugger_dump_pc(struct fiq_debugger_output *output, const struct pt_regs *regs) { - fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n", + output->printf(output, " pc %08x cpsr %08x mode %s\n", regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr)); } -void fiq_debugger_dump_regs(struct fiq_debugger_state *state, +void fiq_debugger_dump_regs(struct fiq_debugger_output *output, const struct pt_regs *regs) { - fiq_debugger_printf(state, + output->printf(output, " r0 %08x r1 %08x r2 %08x r3 %08x\n", regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); - fiq_debugger_printf(state, + output->printf(output, " r4 %08x r5 %08x r6 %08x r7 %08x\n", regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); - fiq_debugger_printf(state, + output->printf(output, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, mode_name(regs->ARM_cpsr)); - fiq_debugger_printf(state, + output->printf(output, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, regs->ARM_cpsr); @@ -112,43 +112,43 @@ static void __naked get_mode_regs(struct mode_regs *regs) } -void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, +void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, const struct pt_regs *regs) { struct mode_regs mode_regs; unsigned long mode = regs->ARM_cpsr & MODE_MASK; - fiq_debugger_dump_regs(state, regs); + fiq_debugger_dump_regs(output, regs); get_mode_regs(&mode_regs); - fiq_debugger_printf(state, + output->printf(output, "%csvc: sp %08x lr %08x spsr %08x\n", mode == SVC_MODE ? '*' : ' ', mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); - fiq_debugger_printf(state, + output->printf(output, "%cabt: sp %08x lr %08x spsr %08x\n", mode == ABT_MODE ? '*' : ' ', mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); - fiq_debugger_printf(state, + output->printf(output, "%cund: sp %08x lr %08x spsr %08x\n", mode == UND_MODE ? '*' : ' ', mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); - fiq_debugger_printf(state, + output->printf(output, "%cirq: sp %08x lr %08x spsr %08x\n", mode == IRQ_MODE ? '*' : ' ', mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); - fiq_debugger_printf(state, + output->printf(output, "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", mode == FIQ_MODE ? '*' : ' ', mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, mode_regs.r11_fiq, mode_regs.r12_fiq); - fiq_debugger_printf(state, + output->printf(output, " fiq: sp %08x lr %08x spsr %08x\n", mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); } struct stacktrace_state { - struct fiq_debugger_state *state; + struct fiq_debugger_output *output; unsigned int depth; }; @@ -157,14 +157,14 @@ static int report_trace(struct stackframe *frame, void *d) struct stacktrace_state *sts = d; if (sts->depth) { - fiq_debugger_printf(sts->state, + sts->output->printf(sts->output, " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", frame->pc, frame->pc, frame->lr, frame->lr, frame->sp, frame->fp); sts->depth--; return 0; } - fiq_debugger_printf(sts->state, " ...\n"); + sts->output->printf(sts->output, " ...\n"); return sts->depth == 0; } @@ -175,24 +175,24 @@ struct frame_tail { unsigned long lr; } __attribute__((packed)); -static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, +static struct frame_tail *user_backtrace(struct fiq_debugger_output *output, struct frame_tail *tail) { struct frame_tail buftail[2]; /* Also check accessibility of one struct frame_tail beyond */ if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { - fiq_debugger_printf(state, " invalid frame pointer %p\n", + output->printf(output, " invalid frame pointer %p\n", tail); return NULL; } if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { - fiq_debugger_printf(state, + output->printf(output, " failed to copy frame pointer %p\n", tail); return NULL; } - fiq_debugger_printf(state, " %p\n", buftail[0].lr); + output->printf(output, " %p\n", buftail[0].lr); /* frame pointers should strictly progress back up the stack * (towards higher addresses) */ @@ -202,7 +202,7 @@ static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, return buftail[0].fp-1; } -void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, +void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, const struct pt_regs *regs, unsigned int depth, void *ssp) { struct frame_tail *tail; @@ -210,15 +210,15 @@ void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, struct stacktrace_state sts; sts.depth = depth; - sts.state = state; + sts.output = output; *current_thread_info() = *real_thread_info; if (!current) - fiq_debugger_printf(state, "current NULL\n"); + output->printf(output, "current NULL\n"); else - fiq_debugger_printf(state, "pid: %d comm: %s\n", + output->printf(output, "pid: %d comm: %s\n", current->pid, current->comm); - fiq_debugger_dump_regs(state, regs); + fiq_debugger_dump_regs(output, regs); if (!user_mode(regs)) { struct stackframe frame; @@ -226,7 +226,7 @@ void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, frame.sp = regs->ARM_sp; frame.lr = regs->ARM_lr; frame.pc = regs->ARM_pc; - fiq_debugger_printf(state, + output->printf(output, " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, regs->ARM_sp, regs->ARM_fp); @@ -236,5 +236,5 @@ void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, tail = ((struct frame_tail *) regs->ARM_fp) - 1; while (depth-- && tail && !((unsigned long) tail & 3)) - tail = user_backtrace(state, tail); + tail = user_backtrace(output, tail); } diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c index cbca82b70533..99c6584fcfa5 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c @@ -34,79 +34,79 @@ static char *mode_name(const struct pt_regs *regs) } } -void fiq_debugger_dump_pc(struct fiq_debugger_state *state, +void fiq_debugger_dump_pc(struct fiq_debugger_output *output, const struct pt_regs *regs) { - fiq_debugger_printf(state, " pc %016lx cpsr %08lx mode %s\n", + output->printf(output, " pc %016lx cpsr %08lx mode %s\n", regs->pc, regs->pstate, mode_name(regs)); } -void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_state *state, +void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output, const struct pt_regs *regs) { - fiq_debugger_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + output->printf(output, " r0 %08x r1 %08x r2 %08x r3 %08x\n", regs->compat_usr(0), regs->compat_usr(1), regs->compat_usr(2), regs->compat_usr(3)); - fiq_debugger_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + output->printf(output, " r4 %08x r5 %08x r6 %08x r7 %08x\n", regs->compat_usr(4), regs->compat_usr(5), regs->compat_usr(6), regs->compat_usr(7)); - fiq_debugger_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x\n", + output->printf(output, " r8 %08x r9 %08x r10 %08x r11 %08x\n", regs->compat_usr(8), regs->compat_usr(9), regs->compat_usr(10), regs->compat_usr(11)); - fiq_debugger_printf(state, " ip %08x sp %08x lr %08x pc %08x\n", + output->printf(output, " ip %08x sp %08x lr %08x pc %08x\n", regs->compat_usr(12), regs->compat_sp, regs->compat_lr, regs->pc); - fiq_debugger_printf(state, " cpsr %08x (%s)\n", + output->printf(output, " cpsr %08x (%s)\n", regs->pstate, mode_name(regs)); } -void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_state *state, +void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output, const struct pt_regs *regs) { - fiq_debugger_printf(state, " x0 %016lx x1 %016lx\n", + output->printf(output, " x0 %016lx x1 %016lx\n", regs->regs[0], regs->regs[1]); - fiq_debugger_printf(state, " x2 %016lx x3 %016lx\n", + output->printf(output, " x2 %016lx x3 %016lx\n", regs->regs[2], regs->regs[3]); - fiq_debugger_printf(state, " x4 %016lx x5 %016lx\n", + output->printf(output, " x4 %016lx x5 %016lx\n", regs->regs[4], regs->regs[5]); - fiq_debugger_printf(state, " x6 %016lx x7 %016lx\n", + output->printf(output, " x6 %016lx x7 %016lx\n", regs->regs[6], regs->regs[7]); - fiq_debugger_printf(state, " x8 %016lx x9 %016lx\n", + output->printf(output, " x8 %016lx x9 %016lx\n", regs->regs[8], regs->regs[9]); - fiq_debugger_printf(state, " x10 %016lx x11 %016lx\n", + output->printf(output, " x10 %016lx x11 %016lx\n", regs->regs[10], regs->regs[11]); - fiq_debugger_printf(state, " x12 %016lx x13 %016lx\n", + output->printf(output, " x12 %016lx x13 %016lx\n", regs->regs[12], regs->regs[13]); - fiq_debugger_printf(state, " x14 %016lx x15 %016lx\n", + output->printf(output, " x14 %016lx x15 %016lx\n", regs->regs[14], regs->regs[15]); - fiq_debugger_printf(state, " x16 %016lx x17 %016lx\n", + output->printf(output, " x16 %016lx x17 %016lx\n", regs->regs[16], regs->regs[17]); - fiq_debugger_printf(state, " x18 %016lx x19 %016lx\n", + output->printf(output, " x18 %016lx x19 %016lx\n", regs->regs[18], regs->regs[19]); - fiq_debugger_printf(state, " x20 %016lx x21 %016lx\n", + output->printf(output, " x20 %016lx x21 %016lx\n", regs->regs[20], regs->regs[21]); - fiq_debugger_printf(state, " x22 %016lx x23 %016lx\n", + output->printf(output, " x22 %016lx x23 %016lx\n", regs->regs[22], regs->regs[23]); - fiq_debugger_printf(state, " x24 %016lx x25 %016lx\n", + output->printf(output, " x24 %016lx x25 %016lx\n", regs->regs[24], regs->regs[25]); - fiq_debugger_printf(state, " x26 %016lx x27 %016lx\n", + output->printf(output, " x26 %016lx x27 %016lx\n", regs->regs[26], regs->regs[27]); - fiq_debugger_printf(state, " x28 %016lx x29 %016lx\n", + output->printf(output, " x28 %016lx x29 %016lx\n", regs->regs[28], regs->regs[29]); - fiq_debugger_printf(state, " x30 %016lx sp %016lx\n", + output->printf(output, " x30 %016lx sp %016lx\n", regs->regs[30], regs->sp); - fiq_debugger_printf(state, " pc %016lx cpsr %08x (%s)\n", + output->printf(output, " pc %016lx cpsr %08x (%s)\n", regs->pc, regs->pstate, mode_name(regs)); } -void fiq_debugger_dump_regs(struct fiq_debugger_state *state, +void fiq_debugger_dump_regs(struct fiq_debugger_output *output, const struct pt_regs *regs) { if (compat_user_mode(regs)) - fiq_debugger_dump_regs_aarch32(state, regs); + fiq_debugger_dump_regs_aarch32(output, regs); else - fiq_debugger_dump_regs_aarch64(state, regs); + fiq_debugger_dump_regs_aarch64(output, regs); } #define READ_SPECIAL_REG(x) ({ \ @@ -115,45 +115,45 @@ void fiq_debugger_dump_regs(struct fiq_debugger_state *state, val; \ }) -void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, +void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, const struct pt_regs *regs) { u32 pstate = READ_SPECIAL_REG(CurrentEl); bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t; - fiq_debugger_dump_regs(state, regs); + fiq_debugger_dump_regs(output, regs); - fiq_debugger_printf(state, " sp_el0 %016lx\n", + output->printf(output, " sp_el0 %016lx\n", READ_SPECIAL_REG(sp_el0)); if (in_el2) - fiq_debugger_printf(state, " sp_el1 %016lx\n", + output->printf(output, " sp_el1 %016lx\n", READ_SPECIAL_REG(sp_el1)); - fiq_debugger_printf(state, " elr_el1 %016lx\n", + output->printf(output, " elr_el1 %016lx\n", READ_SPECIAL_REG(elr_el1)); - fiq_debugger_printf(state, " spsr_el1 %08lx\n", + output->printf(output, " spsr_el1 %08lx\n", READ_SPECIAL_REG(spsr_el1)); if (in_el2) { - fiq_debugger_printf(state, " spsr_irq %08lx\n", + output->printf(output, " spsr_irq %08lx\n", READ_SPECIAL_REG(spsr_irq)); - fiq_debugger_printf(state, " spsr_abt %08lx\n", + output->printf(output, " spsr_abt %08lx\n", READ_SPECIAL_REG(spsr_abt)); - fiq_debugger_printf(state, " spsr_und %08lx\n", + output->printf(output, " spsr_und %08lx\n", READ_SPECIAL_REG(spsr_und)); - fiq_debugger_printf(state, " spsr_fiq %08lx\n", + output->printf(output, " spsr_fiq %08lx\n", READ_SPECIAL_REG(spsr_fiq)); - fiq_debugger_printf(state, " spsr_el2 %08lx\n", + output->printf(output, " spsr_el2 %08lx\n", READ_SPECIAL_REG(elr_el2)); - fiq_debugger_printf(state, " spsr_el2 %08lx\n", + output->printf(output, " spsr_el2 %08lx\n", READ_SPECIAL_REG(spsr_el2)); } } struct stacktrace_state { - struct fiq_debugger_state *state; + struct fiq_debugger_output *output; unsigned int depth; }; @@ -162,41 +162,41 @@ static int report_trace(struct stackframe *frame, void *d) struct stacktrace_state *sts = d; if (sts->depth) { - fiq_debugger_printf(sts->state, "%pF:\n", frame->pc); - fiq_debugger_printf(sts->state, + sts->output->printf(sts->output, "%pF:\n", frame->pc); + sts->output->printf(sts->output, " pc %016lx sp %016lx fp %016lx\n", frame->pc, frame->sp, frame->fp); sts->depth--; return 0; } - fiq_debugger_printf(sts->state, " ...\n"); + sts->output->printf(sts->output, " ...\n"); return sts->depth == 0; } -void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, +void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, const struct pt_regs *regs, unsigned int depth, void *ssp) { struct thread_info *real_thread_info = THREAD_INFO(ssp); struct stacktrace_state sts; sts.depth = depth; - sts.state = state; + sts.output = output; *current_thread_info() = *real_thread_info; if (!current) - fiq_debugger_printf(state, "current NULL\n"); + output->printf(output, "current NULL\n"); else - fiq_debugger_printf(state, "pid: %d comm: %s\n", + output->printf(output, "pid: %d comm: %s\n", current->pid, current->comm); - fiq_debugger_dump_regs(state, regs); + fiq_debugger_dump_regs(output, regs); if (!user_mode(regs)) { struct stackframe frame; frame.fp = regs->regs[29]; frame.sp = regs->sp; frame.pc = regs->pc; - fiq_debugger_printf(state, "\n"); + output->printf(output, "\n"); walk_stackframe(&frame, report_trace, &sts); } } diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h index 746cf1b5d55b..d5d051f727a8 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h @@ -19,18 +19,19 @@ #define THREAD_INFO(sp) ((struct thread_info *) \ ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) -struct fiq_debugger_state; +struct fiq_debugger_output { + void (*printf)(struct fiq_debugger_output *output, const char *fmt, ...); +}; + struct pt_regs; -int fiq_debugger_printf(void *cookie, const char *fmt, ...); - -void fiq_debugger_dump_pc(struct fiq_debugger_state *state, +void fiq_debugger_dump_pc(struct fiq_debugger_output *output, const struct pt_regs *regs); -void fiq_debugger_dump_regs(struct fiq_debugger_state *state, +void fiq_debugger_dump_regs(struct fiq_debugger_output *output, const struct pt_regs *regs); -void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, +void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, const struct pt_regs *regs); -void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, +void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, const struct pt_regs *regs, unsigned int depth, void *ssp); #endif From 3e966cff406d9b43a16e07291a918cb2a098e32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Fri, 2 May 2014 20:23:21 -0700 Subject: [PATCH 20/21] pstore/ram: Add ramoops_console_write_buf api MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow writing into the ramoops console buffer. Change-Id: Iff0d69b562e4dae33ea7f8d19412227bebb17e47 Signed-off-by: Arve Hjønnevåg --- fs/pstore/ram.c | 6 ++++++ include/linux/pstore_ram.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 1376e5a8f0d6..058f17f0b466 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -377,6 +377,12 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, return 0; } +void notrace ramoops_console_write_buf(const char *buf, size_t size) +{ + struct ramoops_context *cxt = &oops_cxt; + persistent_ram_write(cxt->cprz, buf, size); +} + static int ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 9974975d40db..9e370618352a 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -67,6 +67,8 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz); ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, char *str, size_t len); +void ramoops_console_write_buf(const char *buf, size_t size); + /* * Ramoops platform data * @mem_size memory size for ramoops From 1b48727337de9e12237583931315cc6d85532415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Fri, 2 May 2014 20:31:07 -0700 Subject: [PATCH 21/21] fiq_debugger: Add fiq_watchdog_triggered api MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dumps registers and stacktrace into console-ramoops when called from a watchdog fiq. Change-Id: Ib6fab5a52f670db18e64214d5e4890e8292a749c Signed-off-by: Arve Hjønnevåg --- drivers/staging/android/fiq_debugger/Kconfig | 6 ++ drivers/staging/android/fiq_debugger/Makefile | 3 +- .../android/fiq_debugger/fiq_watchdog.c | 56 +++++++++++++++++++ .../android/fiq_debugger/fiq_watchdog.h | 20 +++++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/android/fiq_debugger/fiq_watchdog.c create mode 100644 drivers/staging/android/fiq_debugger/fiq_watchdog.h diff --git a/drivers/staging/android/fiq_debugger/Kconfig b/drivers/staging/android/fiq_debugger/Kconfig index d87978cc7dee..56f7f999377e 100644 --- a/drivers/staging/android/fiq_debugger/Kconfig +++ b/drivers/staging/android/fiq_debugger/Kconfig @@ -41,3 +41,9 @@ config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE help If enabled, this puts the fiq debugger into console mode by default. Otherwise, the fiq debugger will start out in debug mode. + +config FIQ_WATCHDOG + bool + select FIQ_DEBUGGER + select PSTORE_RAM + default n diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile index c95da7eb1b33..a7ca4871cad3 100644 --- a/drivers/staging/android/fiq_debugger/Makefile +++ b/drivers/staging/android/fiq_debugger/Makefile @@ -1,3 +1,4 @@ obj-y += fiq_debugger.o obj-$(CONFIG_ARM) += fiq_debugger_arm.o -obj-$(CONFIG_ARM64) += fiq_debugger_arm64.o \ No newline at end of file +obj-$(CONFIG_ARM64) += fiq_debugger_arm64.o +obj-$(CONFIG_FIQ_WATCHDOG) += fiq_watchdog.o diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.c b/drivers/staging/android/fiq_debugger/fiq_watchdog.c new file mode 100644 index 000000000000..194b54138417 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "fiq_watchdog.h" +#include "fiq_debugger_priv.h" + +static DEFINE_RAW_SPINLOCK(fiq_watchdog_lock); + +static void fiq_watchdog_printf(struct fiq_debugger_output *output, + const char *fmt, ...) +{ + char buf[256]; + va_list ap; + int len; + + va_start(ap, fmt); + len = vscnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + ramoops_console_write_buf(buf, len); +} + +struct fiq_debugger_output fiq_watchdog_output = { + .printf = fiq_watchdog_printf, +}; + +void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp) +{ + char msg[24]; + int len; + + raw_spin_lock(&fiq_watchdog_lock); + + len = scnprintf(msg, sizeof(msg), "watchdog fiq cpu %d\n", + THREAD_INFO(svc_sp)->cpu); + ramoops_console_write_buf(msg, len); + + fiq_debugger_dump_stacktrace(&fiq_watchdog_output, regs, 100, svc_sp); + + raw_spin_unlock(&fiq_watchdog_lock); +} diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.h b/drivers/staging/android/fiq_debugger/fiq_watchdog.h new file mode 100644 index 000000000000..c6b507f8d976 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _FIQ_WATCHDOG_H_ +#define _FIQ_WATCHDOG_H_ + +void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp); + +#endif