Commit 86069782 authored by Pekka Paalanen's avatar Pekka Paalanen Committed by Thomas Gleixner
Browse files

x86: add a list for custom page fault handlers.

Provides kernel modules a way to register custom page fault handlers.
On every page fault this will call a list of registered functions. The
functions may handle the fault and force do_page_fault() to return

This functionality is similar to the now removed page fault notifiers.
Custom page fault handlers are used by debugging and reverse engineering
tools. Mmiotrace is one such tool and a patch to add it into the tree
will follow.

The custom page fault handlers are called earlier in do_page_fault()
than the page fault notifiers were.
Signed-off-by: default avatarPekka Paalanen <>
Signed-off-by: default avatarIngo Molnar <>
Signed-off-by: default avatarThomas Gleixner <>
parent 8f0f996e
......@@ -168,6 +168,14 @@ config IOMMU_LEAK
Add a simple leak tracer to the IOMMU code. This is useful when you
are debugging a buggy device driver that leaks IOMMU mappings.
bool "Custom page fault handlers"
depends on DEBUG_KERNEL
Allow the use of custom page fault handlers. A kernel module may
register a function that is called on every page fault. Custom
handlers are used by some debugging and reverse engineering tools.
# IO delay types:
......@@ -49,6 +49,60 @@
#define PF_RSVD (1<<3)
#define PF_INSTR (1<<4)
static HLIST_HEAD(pf_handlers); /* protected by RCU */
static DEFINE_SPINLOCK(pf_handlers_writer);
void register_page_fault_handler(struct pf_handler *new_pfh)
unsigned long flags;
spin_lock_irqsave(&pf_handlers_writer, flags);
hlist_add_head_rcu(&new_pfh->hlist, &pf_handlers);
spin_unlock_irqrestore(&pf_handlers_writer, flags);
* unregister_page_fault_handler:
* The caller must ensure @old_pfh is not in use anymore before freeing it.
* This function does not guarantee it. The list of handlers is protected by
* RCU, so you can do this by e.g. calling synchronize_rcu().
void unregister_page_fault_handler(struct pf_handler *old_pfh)
unsigned long flags;
spin_lock_irqsave(&pf_handlers_writer, flags);
spin_unlock_irqrestore(&pf_handlers_writer, flags);
/* returns non-zero if do_page_fault() should return */
static int handle_custom_pf(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
int ret = 0;
struct pf_handler *cur;
struct hlist_node *ncur;
if (hlist_empty(&pf_handlers))
return 0;
hlist_for_each_entry_rcu(cur, ncur, &pf_handlers, hlist) {
ret = cur->handler(regs, error_code, address);
if (ret)
return ret;
return 0;
static inline int notify_page_fault(struct pt_regs *regs)
......@@ -601,6 +655,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
if (notify_page_fault(regs))
if (handle_custom_pf(regs, error_code, address))
* We fault-in kernel-space virtual memory on-demand. The
......@@ -35,4 +35,13 @@ extern void show_regs(struct pt_regs *regs);
extern unsigned long oops_begin(void);
extern void oops_end(unsigned long, struct pt_regs *, int signr);
struct pf_handler {
struct hlist_node hlist;
int (*handler)(struct pt_regs *regs, unsigned long error_code,
unsigned long address);
extern void register_page_fault_handler(struct pf_handler *new_pfh);
extern void unregister_page_fault_handler(struct pf_handler *old_pfh);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment