2012-03-05 15:49:33 +04:00
/*
* ARMv8 single - step debug support and mdscr context switching .
*
* Copyright ( C ) 2012 ARM Limited
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* Author : Will Deacon < will . deacon @ arm . com >
*/
# include <linux/cpu.h>
# include <linux/debugfs.h>
# include <linux/hardirq.h>
# include <linux/init.h>
# include <linux/ptrace.h>
# include <linux/stat.h>
2013-03-16 12:48:13 +04:00
# include <linux/uaccess.h>
2012-03-05 15:49:33 +04:00
2015-10-19 16:24:54 +03:00
# include <asm/cpufeature.h>
2012-03-05 15:49:33 +04:00
# include <asm/cputype.h>
2015-10-19 16:24:54 +03:00
# include <asm/debug-monitors.h>
2012-03-05 15:49:33 +04:00
# include <asm/system_misc.h>
/* Determine debug architecture. */
u8 debug_monitors_arch ( void )
{
2016-01-26 13:58:16 +03:00
return cpuid_feature_extract_unsigned_field ( read_system_reg ( SYS_ID_AA64DFR0_EL1 ) ,
2015-10-19 16:24:54 +03:00
ID_AA64DFR0_DEBUGVER_SHIFT ) ;
2012-03-05 15:49:33 +04:00
}
/*
* MDSCR access routines .
*/
static void mdscr_write ( u32 mdscr )
{
unsigned long flags ;
local_dbg_save ( flags ) ;
asm volatile ( " msr mdscr_el1, %0 " : : " r " ( mdscr ) ) ;
local_dbg_restore ( flags ) ;
}
static u32 mdscr_read ( void )
{
u32 mdscr ;
asm volatile ( " mrs %0, mdscr_el1 " : " =r " ( mdscr ) ) ;
return mdscr ;
}
/*
* Allow root to disable self - hosted debug from userspace .
* This is useful if you want to connect an external JTAG debugger .
*/
2015-09-27 01:04:07 +03:00
static bool debug_enabled = true ;
2012-03-05 15:49:33 +04:00
static int create_debug_debugfs_entry ( void )
{
debugfs_create_bool ( " debug_enabled " , 0644 , NULL , & debug_enabled ) ;
return 0 ;
}
fs_initcall ( create_debug_debugfs_entry ) ;
static int __init early_debug_disable ( char * buf )
{
2015-09-27 01:04:07 +03:00
debug_enabled = false ;
2012-03-05 15:49:33 +04:00
return 0 ;
}
early_param ( " nodebugmon " , early_debug_disable ) ;
/*
* Keep track of debug users on each core .
* The ref counts are per - cpu so we use a local_t type .
*/
2013-10-21 16:17:08 +04:00
static DEFINE_PER_CPU ( int , mde_ref_count ) ;
static DEFINE_PER_CPU ( int , kde_ref_count ) ;
2012-03-05 15:49:33 +04:00
2015-07-27 20:36:54 +03:00
void enable_debug_monitors ( enum dbg_active_el el )
2012-03-05 15:49:33 +04:00
{
u32 mdscr , enable = 0 ;
WARN_ON ( preemptible ( ) ) ;
2013-10-21 16:17:08 +04:00
if ( this_cpu_inc_return ( mde_ref_count ) = = 1 )
2012-03-05 15:49:33 +04:00
enable = DBG_MDSCR_MDE ;
if ( el = = DBG_ACTIVE_EL1 & &
2013-10-21 16:17:08 +04:00
this_cpu_inc_return ( kde_ref_count ) = = 1 )
2012-03-05 15:49:33 +04:00
enable | = DBG_MDSCR_KDE ;
if ( enable & & debug_enabled ) {
mdscr = mdscr_read ( ) ;
mdscr | = enable ;
mdscr_write ( mdscr ) ;
}
}
2015-07-27 20:36:54 +03:00
void disable_debug_monitors ( enum dbg_active_el el )
2012-03-05 15:49:33 +04:00
{
u32 mdscr , disable = 0 ;
WARN_ON ( preemptible ( ) ) ;
2013-10-21 16:17:08 +04:00
if ( this_cpu_dec_return ( mde_ref_count ) = = 0 )
2012-03-05 15:49:33 +04:00
disable = ~ DBG_MDSCR_MDE ;
if ( el = = DBG_ACTIVE_EL1 & &
2013-10-21 16:17:08 +04:00
this_cpu_dec_return ( kde_ref_count ) = = 0 )
2012-03-05 15:49:33 +04:00
disable & = ~ DBG_MDSCR_KDE ;
if ( disable ) {
mdscr = mdscr_read ( ) ;
mdscr & = disable ;
mdscr_write ( mdscr ) ;
}
}
/*
* OS lock clearing .
*/
static void clear_os_lock ( void * unused )
{
asm volatile ( " msr oslar_el1, %0 " : : " r " ( 0 ) ) ;
}
2013-06-18 18:18:31 +04:00
static int os_lock_notify ( struct notifier_block * self ,
2012-03-05 15:49:33 +04:00
unsigned long action , void * data )
{
2015-09-11 17:31:24 +03:00
if ( ( action & ~ CPU_TASKS_FROZEN ) = = CPU_ONLINE )
2016-04-06 11:42:28 +03:00
clear_os_lock ( NULL ) ;
2012-03-05 15:49:33 +04:00
return NOTIFY_OK ;
}
2013-06-18 18:18:31 +04:00
static struct notifier_block os_lock_nb = {
2012-03-05 15:49:33 +04:00
. notifier_call = os_lock_notify ,
} ;
2013-06-18 18:18:31 +04:00
static int debug_monitors_init ( void )
2012-03-05 15:49:33 +04:00
{
2014-03-11 00:39:20 +04:00
cpu_notifier_register_begin ( ) ;
2012-03-05 15:49:33 +04:00
/* Clear the OS lock. */
2014-02-21 09:13:49 +04:00
on_each_cpu ( clear_os_lock , NULL , 1 ) ;
isb ( ) ;
local_dbg_enable ( ) ;
2012-03-05 15:49:33 +04:00
/* Register hotplug handler. */
2014-03-11 00:39:20 +04:00
__register_cpu_notifier ( & os_lock_nb ) ;
cpu_notifier_register_done ( ) ;
2012-03-05 15:49:33 +04:00
return 0 ;
}
postcore_initcall ( debug_monitors_init ) ;
/*
* Single step API and exception handling .
*/
static void set_regs_spsr_ss ( struct pt_regs * regs )
{
unsigned long spsr ;
spsr = regs - > pstate ;
spsr & = ~ DBG_SPSR_SS ;
spsr | = DBG_SPSR_SS ;
regs - > pstate = spsr ;
}
static void clear_regs_spsr_ss ( struct pt_regs * regs )
{
unsigned long spsr ;
spsr = regs - > pstate ;
spsr & = ~ DBG_SPSR_SS ;
regs - > pstate = spsr ;
}
2013-12-04 09:50:20 +04:00
/* EL1 Single Step Handler hooks */
static LIST_HEAD ( step_hook ) ;
2016-02-09 01:49:24 +03:00
static DEFINE_SPINLOCK ( step_hook_lock ) ;
2013-12-04 09:50:20 +04:00
void register_step_hook ( struct step_hook * hook )
{
2016-02-09 01:49:24 +03:00
spin_lock ( & step_hook_lock ) ;
list_add_rcu ( & hook - > node , & step_hook ) ;
spin_unlock ( & step_hook_lock ) ;
2013-12-04 09:50:20 +04:00
}
void unregister_step_hook ( struct step_hook * hook )
{
2016-02-09 01:49:24 +03:00
spin_lock ( & step_hook_lock ) ;
list_del_rcu ( & hook - > node ) ;
spin_unlock ( & step_hook_lock ) ;
synchronize_rcu ( ) ;
2013-12-04 09:50:20 +04:00
}
/*
2015-09-19 00:09:00 +03:00
* Call registered single step handlers
2013-12-04 09:50:20 +04:00
* There is no Syndrome info to check for determining the handler .
* So we call all the registered handlers , until the right handler is
* found which returns zero .
*/
static int call_step_hook ( struct pt_regs * regs , unsigned int esr )
{
struct step_hook * hook ;
int retval = DBG_HOOK_ERROR ;
2016-02-09 01:49:24 +03:00
rcu_read_lock ( ) ;
2013-12-04 09:50:20 +04:00
2016-02-09 01:49:24 +03:00
list_for_each_entry_rcu ( hook , & step_hook , node ) {
2013-12-04 09:50:20 +04:00
retval = hook - > fn ( regs , esr ) ;
if ( retval = = DBG_HOOK_HANDLED )
break ;
}
2016-02-09 01:49:24 +03:00
rcu_read_unlock ( ) ;
2013-12-04 09:50:20 +04:00
return retval ;
}
2016-02-10 19:05:28 +03:00
static void send_user_sigtrap ( int si_code )
{
struct pt_regs * regs = current_pt_regs ( ) ;
siginfo_t info = {
. si_signo = SIGTRAP ,
. si_errno = 0 ,
. si_code = si_code ,
. si_addr = ( void __user * ) instruction_pointer ( regs ) ,
} ;
if ( WARN_ON ( ! user_mode ( regs ) ) )
return ;
if ( interrupts_enabled ( regs ) )
local_irq_enable ( ) ;
force_sig_info ( SIGTRAP , & info , current ) ;
}
2012-03-05 15:49:33 +04:00
static int single_step_handler ( unsigned long addr , unsigned int esr ,
struct pt_regs * regs )
{
/*
* If we are stepping a pending breakpoint , call the hw_breakpoint
* handler first .
*/
if ( ! reinstall_suspended_bps ( regs ) )
return 0 ;
if ( user_mode ( regs ) ) {
2016-02-10 19:05:28 +03:00
send_user_sigtrap ( TRAP_HWBKPT ) ;
2012-03-05 15:49:33 +04:00
/*
* ptrace will disable single step unless explicitly
* asked to re - enable it . For other clients , it makes
* sense to leave it enabled ( i . e . rewind the controls
* to the active - not - pending state ) .
*/
user_rewind_single_step ( current ) ;
} else {
2013-12-04 09:50:20 +04:00
if ( call_step_hook ( regs , esr ) = = DBG_HOOK_HANDLED )
return 0 ;
2012-03-05 15:49:33 +04:00
pr_warning ( " Unexpected kernel single-step exception at EL1 \n " ) ;
/*
* Re - enable stepping since we know that we will be
* returning to regs .
*/
set_regs_spsr_ss ( regs ) ;
}
return 0 ;
}
2013-12-04 09:50:20 +04:00
/*
* Breakpoint handler is re - entrant as another breakpoint can
* hit within breakpoint handler , especically in kprobes .
* Use reader / writer locks instead of plain spinlock .
*/
static LIST_HEAD ( break_hook ) ;
2015-10-06 00:32:51 +03:00
static DEFINE_SPINLOCK ( break_hook_lock ) ;
2013-12-04 09:50:20 +04:00
void register_break_hook ( struct break_hook * hook )
{
2015-10-06 00:32:51 +03:00
spin_lock ( & break_hook_lock ) ;
list_add_rcu ( & hook - > node , & break_hook ) ;
spin_unlock ( & break_hook_lock ) ;
2013-12-04 09:50:20 +04:00
}
void unregister_break_hook ( struct break_hook * hook )
{
2015-10-06 00:32:51 +03:00
spin_lock ( & break_hook_lock ) ;
list_del_rcu ( & hook - > node ) ;
spin_unlock ( & break_hook_lock ) ;
synchronize_rcu ( ) ;
2013-12-04 09:50:20 +04:00
}
static int call_break_hook ( struct pt_regs * regs , unsigned int esr )
{
struct break_hook * hook ;
int ( * fn ) ( struct pt_regs * regs , unsigned int esr ) = NULL ;
2015-10-06 00:32:51 +03:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( hook , & break_hook , node )
2013-12-04 09:50:20 +04:00
if ( ( esr & hook - > esr_mask ) = = hook - > esr_val )
fn = hook - > fn ;
2015-10-06 00:32:51 +03:00
rcu_read_unlock ( ) ;
2013-12-04 09:50:20 +04:00
return fn ? fn ( regs , esr ) : DBG_HOOK_ERROR ;
}
2013-03-16 12:48:13 +04:00
static int brk_handler ( unsigned long addr , unsigned int esr ,
struct pt_regs * regs )
{
2014-07-31 14:36:08 +04:00
if ( user_mode ( regs ) ) {
2016-02-10 19:05:28 +03:00
send_user_sigtrap ( TRAP_BRKPT ) ;
2014-07-31 14:36:08 +04:00
} else if ( call_break_hook ( regs , esr ) ! = DBG_HOOK_HANDLED ) {
pr_warning ( " Unexpected kernel BRK exception at EL1 \n " ) ;
2013-03-16 12:48:13 +04:00
return - EFAULT ;
2014-07-31 14:36:08 +04:00
}
2013-03-16 12:48:13 +04:00
return 0 ;
}
int aarch32_break_handler ( struct pt_regs * regs )
{
2013-11-28 16:07:23 +04:00
u32 arm_instr ;
u16 thumb_instr ;
2013-03-16 12:48:13 +04:00
bool bp = false ;
void __user * pc = ( void __user * ) instruction_pointer ( regs ) ;
if ( ! compat_user_mode ( regs ) )
return - EFAULT ;
if ( compat_thumb_mode ( regs ) ) {
/* get 16-bit Thumb instruction */
2013-11-28 16:07:23 +04:00
get_user ( thumb_instr , ( u16 __user * ) pc ) ;
thumb_instr = le16_to_cpu ( thumb_instr ) ;
if ( thumb_instr = = AARCH32_BREAK_THUMB2_LO ) {
2013-03-16 12:48:13 +04:00
/* get second half of 32-bit Thumb-2 instruction */
2013-11-28 16:07:23 +04:00
get_user ( thumb_instr , ( u16 __user * ) ( pc + 2 ) ) ;
thumb_instr = le16_to_cpu ( thumb_instr ) ;
bp = thumb_instr = = AARCH32_BREAK_THUMB2_HI ;
2013-03-16 12:48:13 +04:00
} else {
2013-11-28 16:07:23 +04:00
bp = thumb_instr = = AARCH32_BREAK_THUMB ;
2013-03-16 12:48:13 +04:00
}
} else {
/* 32-bit ARM instruction */
2013-11-28 16:07:23 +04:00
get_user ( arm_instr , ( u32 __user * ) pc ) ;
arm_instr = le32_to_cpu ( arm_instr ) ;
bp = ( arm_instr & ~ 0xf0000000 ) = = AARCH32_BREAK_ARM ;
2013-03-16 12:48:13 +04:00
}
if ( ! bp )
return - EFAULT ;
2016-02-10 19:05:28 +03:00
send_user_sigtrap ( TRAP_BRKPT ) ;
2013-03-16 12:48:13 +04:00
return 0 ;
}
static int __init debug_traps_init ( void )
2012-03-05 15:49:33 +04:00
{
hook_debug_fault_code ( DBG_ESR_EVT_HWSS , single_step_handler , SIGTRAP ,
TRAP_HWBKPT , " single-step handler " ) ;
2013-03-16 12:48:13 +04:00
hook_debug_fault_code ( DBG_ESR_EVT_BRK , brk_handler , SIGTRAP ,
TRAP_BRKPT , " ptrace BRK handler " ) ;
2012-03-05 15:49:33 +04:00
return 0 ;
}
2013-03-16 12:48:13 +04:00
arch_initcall ( debug_traps_init ) ;
2012-03-05 15:49:33 +04:00
/* Re-enable single step for syscall restarting. */
void user_rewind_single_step ( struct task_struct * task )
{
/*
* If single step is active for this thread , then set SPSR . SS
* to 1 to avoid returning to the active - pending state .
*/
if ( test_ti_thread_flag ( task_thread_info ( task ) , TIF_SINGLESTEP ) )
set_regs_spsr_ss ( task_pt_regs ( task ) ) ;
}
void user_fastforward_single_step ( struct task_struct * task )
{
if ( test_ti_thread_flag ( task_thread_info ( task ) , TIF_SINGLESTEP ) )
clear_regs_spsr_ss ( task_pt_regs ( task ) ) ;
}
/* Kernel API */
void kernel_enable_single_step ( struct pt_regs * regs )
{
WARN_ON ( ! irqs_disabled ( ) ) ;
set_regs_spsr_ss ( regs ) ;
mdscr_write ( mdscr_read ( ) | DBG_MDSCR_SS ) ;
enable_debug_monitors ( DBG_ACTIVE_EL1 ) ;
}
void kernel_disable_single_step ( void )
{
WARN_ON ( ! irqs_disabled ( ) ) ;
mdscr_write ( mdscr_read ( ) & ~ DBG_MDSCR_SS ) ;
disable_debug_monitors ( DBG_ACTIVE_EL1 ) ;
}
int kernel_active_single_step ( void )
{
WARN_ON ( ! irqs_disabled ( ) ) ;
return mdscr_read ( ) & DBG_MDSCR_SS ;
}
/* ptrace API */
void user_enable_single_step ( struct task_struct * task )
{
set_ti_thread_flag ( task_thread_info ( task ) , TIF_SINGLESTEP ) ;
set_regs_spsr_ss ( task_pt_regs ( task ) ) ;
}
void user_disable_single_step ( struct task_struct * task )
{
clear_ti_thread_flag ( task_thread_info ( task ) , TIF_SINGLESTEP ) ;
}