diff --git a/drivers/segger/note_sysview.c b/drivers/segger/note_sysview.c index 053eb1a99e..be3b472ab9 100644 --- a/drivers/segger/note_sysview.c +++ b/drivers/segger/note_sysview.c @@ -40,12 +40,16 @@ struct sysview_s { - unsigned int irq[CONFIG_SMP_NCPUS]; + unsigned int irq[CONFIG_SMP_NCPUS]; #ifdef CONFIG_SCHED_INSTRUMENTATION_FILTER - struct note_filter_mode_s mode; + struct note_filter_mode_s mode; #endif #ifdef CONFIG_SCHED_INSTRUMENTATION_IRQHANDLER - struct note_filter_irq_s irq_mask; + struct note_filter_irq_s irq_mask; +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_SYSCALL + struct note_filter_syscall_s syscall_mask; + struct note_filter_syscall_s syscall_marker; #endif }; @@ -155,11 +159,24 @@ static bool sysview_isenabled(void) } #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_SYSCALL + /* Use the Syscall "0" to identify whether the syscall is enabled, + * if the host tool is closed abnormally, use this bit to clear + * the active set. + */ + + if (!enable && + NOTE_FILTER_SYSCALLMASK_ISSET(0, &g_sysview.syscall_marker)) + { + NOTE_FILTER_SYSCALLMASK_ZERO(&g_sysview.syscall_marker); + } +#endif + return enable; } /**************************************************************************** - * Name: sysview_isenabled_irqhandler + * Name: sysview_isenabled_irq * * Description: * Check whether the interrupt handler instrumentation is enabled. @@ -197,6 +214,44 @@ static bool sysview_isenabled_irq(int irq, bool enter) } #endif +/**************************************************************************** + * Name: sysview_isenabled_syscall + * + * Description: + * Check whether the syscall instrumentation is enabled. + * + * Input Parameters: + * nr - syscall number + * + * Returned Value: + * True is returned if the instrumentation is enabled. + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_INSTRUMENTATION_SYSCALL +static inline int sysview_isenabled_syscall(int nr) +{ +#ifdef CONFIG_SCHED_INSTRUMENTATION_FILTER + if (!sysview_isenabled()) + { + return false; + } + + /* If the syscall trace is disabled or the syscall number is masked, + * do nothing. + */ + + if ((g_sysview.mode.flag & NOTE_FILTER_MODE_FLAG_SYSCALL) == 0 || + NOTE_FILTER_SYSCALLMASK_ISSET(nr, &g_sysview.syscall_mask)) + { + return false; + } +#endif + + return true; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -310,6 +365,58 @@ void sched_note_irqhandler(int irq, FAR void *handler, bool enter) } #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_SYSCALL +void sched_note_syscall_enter(int nr, int argc, ...) +{ + nr -= CONFIG_SYS_RESERVED; + + if (sysview_isenabled_syscall(nr) == 0) + { + return; + } + + /* Set the name marker if the current syscall nr is not active */ + + if (NOTE_FILTER_SYSCALLMASK_ISSET(nr, &g_sysview.syscall_marker) == 0) + { + /* Set the name marker */ + + SEGGER_SYSVIEW_NameMarker(nr, g_funcnames[nr]); + + /* Mark the syscall active */ + + NOTE_FILTER_SYSCALLMASK_SET(nr, &g_sysview.syscall_marker); + + /* Use the Syscall "0" to identify whether the syscall is enabled, + * if the host tool is closed abnormally, use this bit to clear + * the active set. + */ + + if (NOTE_FILTER_SYSCALLMASK_ISSET(0, &g_sysview.syscall_marker) == 0) + { + NOTE_FILTER_SYSCALLMASK_SET(0, &g_sysview.syscall_marker); + } + } + + SEGGER_SYSVIEW_MarkStart(nr); +} + +void sched_note_syscall_leave(int nr, uintptr_t result) +{ + nr -= CONFIG_SYS_RESERVED; + + if (sysview_isenabled_syscall(nr) == 0) + { + return; + } + + if (NOTE_FILTER_SYSCALLMASK_ISSET(nr, &g_sysview.syscall_marker) != 0) + { + SEGGER_SYSVIEW_MarkStop(nr); + } +} +#endif + /**************************************************************************** * Name: sysview_get_interrupt_id * @@ -490,4 +597,50 @@ void sched_note_filter_irq(struct note_filter_irq_s *oldf, } #endif +/**************************************************************************** + * Name: sched_note_filter_syscall + * + * Description: + * Set and get syscall filter setting + * (Same as NOTECTL_GETSYSCALLFILTER / NOTECTL_SETSYSCALLFILTER ioctls) + * + * Input Parameters: + * oldf - A writable pointer to struct note_filter_syscall_s to get + * current syscall filter setting + * If 0, no data is written. + * newf - A read-only pointer to struct note_filter_syscall_s of the + * new syscall filter setting + * If 0, the setting is not updated. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_INSTRUMENTATION_SYSCALL +void sched_note_filter_syscall(struct note_filter_syscall_s *oldf, + struct note_filter_syscall_s *newf) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(NULL); + + if (oldf != NULL) + { + /* Return the current filter setting */ + + *oldf = g_sysview.syscall_mask; + } + + if (newf != NULL) + { + /* Replace the syscall filter mask by the provided setting */ + + g_sysview.syscall_mask = *newf; + } + + spin_unlock_irqrestore(NULL, flags); +} #endif + +#endif /* CONFIG_SCHED_INSTRUMENTATION_FILTER */