mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
![Pekka Paalanen](/assets/img/avatar_default.png)
kmmio.c handles the list of mmio probes with callbacks, list of traced pages, and attaching into the page fault handler and die notifier. It arms, traps and disarms the given pages, this is the core of mmiotrace. mmio-mod.c is a user interface, hooking into ioremap functions and registering the mmio probes. It also decodes the required information from trapped mmio accesses via the pre and post callbacks in each probe. Currently, hooking into ioremap functions works by redefining the symbols of the target (binary) kernel module, so that it calls the traced versions of the functions. The most notable changes done since the last discussion are: - kmmio.c is a built-in, not part of the module - direct call from fault.c to kmmio.c, removing all dynamic hooks - prepare for unregistering probes at any time - make kmmio re-initializable and accessible to more than one user - rewrite kmmio locking to remove all spinlocks from page fault path Can I abuse call_rcu() like I do in kmmio.c:unregister_kmmio_probe() or is there a better way? The function called via call_rcu() itself calls call_rcu() again, will this work or break? There I need a second grace period for RCU after the first grace period for page faults. Mmiotrace itself (mmio-mod.c) is still a module, I am going to attack that next. At some point I will start looking into how to make mmiotrace a tracer component of ftrace (thanks for the hint, Ingo). Ftrace should make the user space part of mmiotracing as simple as 'cat /debug/trace/mmio > dump.txt'. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
104 lines
2.6 KiB
C
104 lines
2.6 KiB
C
#ifndef MMIOTRACE_H
|
|
#define MMIOTRACE_H
|
|
|
|
#include <asm/types.h>
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
#include <linux/list.h>
|
|
|
|
struct kmmio_probe;
|
|
struct pt_regs;
|
|
|
|
typedef void (*kmmio_pre_handler_t)(struct kmmio_probe *,
|
|
struct pt_regs *, unsigned long addr);
|
|
typedef void (*kmmio_post_handler_t)(struct kmmio_probe *,
|
|
unsigned long condition, struct pt_regs *);
|
|
|
|
struct kmmio_probe {
|
|
struct list_head list;
|
|
unsigned long addr; /* start location of the probe point */
|
|
unsigned long len; /* length of the probe region */
|
|
kmmio_pre_handler_t pre_handler; /* Called before addr is executed. */
|
|
kmmio_post_handler_t post_handler; /* Called after addr is executed */
|
|
};
|
|
|
|
/* kmmio is active by some kmmio_probes? */
|
|
static inline int is_kmmio_active(void)
|
|
{
|
|
extern unsigned int kmmio_count;
|
|
return kmmio_count;
|
|
}
|
|
|
|
extern void reference_kmmio(void);
|
|
extern void unreference_kmmio(void);
|
|
extern int register_kmmio_probe(struct kmmio_probe *p);
|
|
extern void unregister_kmmio_probe(struct kmmio_probe *p);
|
|
|
|
/* Called from page fault handler. */
|
|
extern int kmmio_handler(struct pt_regs *regs, unsigned long addr);
|
|
|
|
#endif /* __KERNEL__ */
|
|
|
|
|
|
/*
|
|
* If you change anything here, you must bump MMIO_VERSION.
|
|
* This is the relay data format for user space.
|
|
*/
|
|
#define MMIO_VERSION 0x04
|
|
|
|
/* mm_io_header.type */
|
|
#define MMIO_OPCODE_MASK 0xff
|
|
#define MMIO_OPCODE_SHIFT 0
|
|
#define MMIO_WIDTH_MASK 0xff00
|
|
#define MMIO_WIDTH_SHIFT 8
|
|
#define MMIO_MAGIC (0x6f000000 | (MMIO_VERSION<<16))
|
|
#define MMIO_MAGIC_MASK 0xffff0000
|
|
|
|
enum mm_io_opcode { /* payload type: */
|
|
MMIO_READ = 0x1, /* struct mm_io_rw */
|
|
MMIO_WRITE = 0x2, /* struct mm_io_rw */
|
|
MMIO_PROBE = 0x3, /* struct mm_io_map */
|
|
MMIO_UNPROBE = 0x4, /* struct mm_io_map */
|
|
MMIO_MARKER = 0x5, /* raw char data */
|
|
MMIO_UNKNOWN_OP = 0x6, /* struct mm_io_rw */
|
|
};
|
|
|
|
struct mm_io_header {
|
|
__u32 type; /* see MMIO_* macros above */
|
|
__u32 sec; /* timestamp */
|
|
__u32 nsec;
|
|
__u32 pid; /* PID of the process, or 0 for kernel core */
|
|
__u16 data_len; /* length of the following payload */
|
|
};
|
|
|
|
struct mm_io_rw {
|
|
__u64 address; /* virtual address of register */
|
|
__u64 value;
|
|
__u64 pc; /* optional program counter */
|
|
};
|
|
|
|
struct mm_io_map {
|
|
__u64 phys; /* base address in PCI space */
|
|
__u64 addr; /* base virtual address */
|
|
__u64 len; /* mapping size */
|
|
__u64 pc; /* optional program counter */
|
|
};
|
|
|
|
|
|
/*
|
|
* These structures are used to allow a single relay_write()
|
|
* call to write a full packet.
|
|
*/
|
|
|
|
struct mm_io_header_rw {
|
|
struct mm_io_header header;
|
|
struct mm_io_rw rw;
|
|
} __attribute__((packed));
|
|
|
|
struct mm_io_header_map {
|
|
struct mm_io_header header;
|
|
struct mm_io_map map;
|
|
} __attribute__((packed));
|
|
|
|
#endif /* MMIOTRACE_H */
|