Add support for port I/O tracing on x86. Memory mapped I/O tracing is available on x86 via CONFIG_MMIOTRACE but that relies on page faults so it doesn't work with port I/O. This feature uses tracepoints in a similar manner as CONFIG_TRACE_MMIO_ACCESS. Signed-off-by: Dan Raymond <draymond@xxxxxxxxxxxxx> --- arch/x86/include/asm/shared/io.h | 11 +++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/trace_portio.c | 18 ++++++++++++ include/trace/events/portio.h | 49 ++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 arch/x86/lib/trace_portio.c create mode 100644 include/trace/events/portio.h diff --git a/arch/x86/include/asm/shared/io.h b/arch/x86/include/asm/shared/io.h index c0ef921c0586..e7ef4212e00b 100644 --- a/arch/x86/include/asm/shared/io.h +++ b/arch/x86/include/asm/shared/io.h @@ -2,13 +2,23 @@ #ifndef _ASM_X86_SHARED_IO_H #define _ASM_X86_SHARED_IO_H +#include <linux/instruction_pointer.h> #include <linux/types.h> +#if defined(CONFIG_TRACEPOINTS) && !defined(BOOT_COMPRESSED_MISC_H) && !defined(BOOT_BOOT_H) +extern void do_trace_portio_read(u32 value, u16 port, char width, long ip_addr); +extern void do_trace_portio_write(u32 value, u16 port, char width, long ip_addr); +#else +static inline void do_trace_portio_read(u32 value, u16 port, char width, long ip_addr) {} +static inline void do_trace_portio_write(u32 value, u16 port, char width, long ip_addr) {} +#endif + #define BUILDIO(bwl, bw, type) \ static inline void __out##bwl(type value, u16 port) \ { \ asm volatile("out" #bwl " %" #bw "0, %w1" \ : : "a"(value), "Nd"(port)); \ + do_trace_portio_write(value, port, #bwl[0], _THIS_IP_); \ } \ \ static inline type __in##bwl(u16 port) \ @@ -16,6 +26,7 @@ static inline type __in##bwl(u16 port) \ type value; \ asm volatile("in" #bwl " %w1, %" #bw "0" \ : "=a"(value) : "Nd"(port)); \ + do_trace_portio_read(value, port, #bwl[0], _THIS_IP_); \ return value; \ } diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index f76747862bd2..254f223c025d 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -40,6 +40,7 @@ $(obj)/inat.o: $(obj)/inat-tables.c clean-files := inat-tables.c obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o +obj-$(CONFIG_TRACEPOINTS) += trace_portio.o lib-y := delay.o misc.o cmdline.o cpu.o lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o diff --git a/arch/x86/lib/trace_portio.c b/arch/x86/lib/trace_portio.c new file mode 100644 index 000000000000..443361b460a5 --- /dev/null +++ b/arch/x86/lib/trace_portio.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#define CREATE_TRACE_POINTS +#include <trace/events/portio.h> + +void do_trace_portio_read(u32 value, u16 port, char width, long ip_addr) +{ + trace_portio_read(value, port, width, ip_addr); +} +EXPORT_SYMBOL_GPL(do_trace_portio_read); +EXPORT_TRACEPOINT_SYMBOL_GPL(portio_read); + +void do_trace_portio_write(u32 value, u16 port, char width, long ip_addr) +{ + trace_portio_write(value, port, width, ip_addr); +} +EXPORT_SYMBOL_GPL(do_trace_portio_write); +EXPORT_TRACEPOINT_SYMBOL_GPL(portio_write); diff --git a/include/trace/events/portio.h b/include/trace/events/portio.h new file mode 100644 index 000000000000..3591a75a475e --- /dev/null +++ b/include/trace/events/portio.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM portio + +#if !defined(_TRACE_PORTIO_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_PORTIO_H + +#include <linux/tracepoint.h> + +DECLARE_EVENT_CLASS(portio_class, + TP_PROTO(u32 value, u16 port, char width, long ip_addr), + + TP_ARGS(value, port, width, ip_addr), + + TP_STRUCT__entry( + __field(u32, value) + __field(u16, port) + __field(char, width) + __field(long, ip_addr) + ), + + TP_fast_assign( + __entry->value = value; + __entry->port = port; + __entry->width = width; + __entry->ip_addr = ip_addr; + ), + + TP_printk("port=0x%04x value=0x%0*x %pS", + __entry->port, + __entry->width == 'b' ? 2 : + __entry->width == 'w' ? 4 : 8, + __entry->value, (void *)__entry->ip_addr) +); + +DEFINE_EVENT(portio_class, portio_read, + TP_PROTO(u32 value, u16 port, char width, long ip_addr), + TP_ARGS(value, port, width, ip_addr) +); + +DEFINE_EVENT(portio_class, portio_write, + TP_PROTO(u32 value, u16 port, char width, long ip_addr), + TP_ARGS(value, port, width, ip_addr) +); + +#endif /* _TRACE_PORTIO_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> base-commit: be8b93b5cc7d533eb8c9b0590cdac055ecafe13a -- 2.25.1