summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/mmiotrace/testmmiotrace.c
diff options
context:
space:
mode:
authorPekka Paalanen <pq@iki.fi>2008-05-12 21:20:56 +0200
committerThomas Gleixner <tglx@linutronix.de>2008-05-24 11:21:14 +0200
commit8b7d89d02ef3c6a7c73d6596f28cea7632850af4 (patch)
tree32601bf4f34dd9e3ec1e9610c555e10dc448006c /arch/x86/kernel/mmiotrace/testmmiotrace.c
parent677aa9f77e8de3791b481a0cec6c8b84d1eec626 (diff)
downloadlwn-8b7d89d02ef3c6a7c73d6596f28cea7632850af4.tar.gz
lwn-8b7d89d02ef3c6a7c73d6596f28cea7632850af4.zip
x86: mmiotrace - trace memory mapped IO
Mmiotrace is a tool for trapping memory mapped IO (MMIO) accesses within the kernel. It is used for debugging and especially for reverse engineering evil binary drivers. Mmiotrace works by wrapping the ioremap family of kernel functions and marking the returned pages as not present. Access to the IO memory triggers a page fault, which will be handled by mmiotrace's custom page fault handler. This will single-step the faulted instruction with the MMIO page marked as present. Access logs are directed to user space via relay and debug_fs. This page fault approach is necessary, because binary drivers have readl/writel etc. calls inlined and therefore extremely difficult to trap with with e.g. kprobes. This patch depends on the custom page fault handlers patch. Signed-off-by: Pekka Paalanen <pq@iki.fi> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/mmiotrace/testmmiotrace.c')
-rw-r--r--arch/x86/kernel/mmiotrace/testmmiotrace.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/arch/x86/kernel/mmiotrace/testmmiotrace.c b/arch/x86/kernel/mmiotrace/testmmiotrace.c
new file mode 100644
index 000000000000..40e66b0e6480
--- /dev/null
+++ b/arch/x86/kernel/mmiotrace/testmmiotrace.c
@@ -0,0 +1,77 @@
+/*
+ * Written by Pekka Paalanen, 2008 <pq@iki.fi>
+ */
+#include <linux/module.h>
+#include <asm/io.h>
+
+extern void __iomem *ioremap_nocache_trace(unsigned long offset,
+ unsigned long size);
+extern void iounmap_trace(volatile void __iomem *addr);
+
+#define MODULE_NAME "testmmiotrace"
+
+static unsigned long mmio_address;
+module_param(mmio_address, ulong, 0);
+MODULE_PARM_DESC(mmio_address, "Start address of the mapping of 16 kB.");
+
+static void do_write_test(void __iomem *p)
+{
+ unsigned int i;
+ for (i = 0; i < 256; i++)
+ iowrite8(i, p + i);
+ for (i = 1024; i < (5 * 1024); i += 2)
+ iowrite16(i * 12 + 7, p + i);
+ for (i = (5 * 1024); i < (16 * 1024); i += 4)
+ iowrite32(i * 212371 + 13, p + i);
+}
+
+static void do_read_test(void __iomem *p)
+{
+ unsigned int i;
+ volatile unsigned int v;
+ for (i = 0; i < 256; i++)
+ v = ioread8(p + i);
+ for (i = 1024; i < (5 * 1024); i += 2)
+ v = ioread16(p + i);
+ for (i = (5 * 1024); i < (16 * 1024); i += 4)
+ v = ioread32(p + i);
+}
+
+static void do_test(void)
+{
+ void __iomem *p = ioremap_nocache_trace(mmio_address, 0x4000);
+ if (!p) {
+ printk(KERN_ERR MODULE_NAME ": could not ioremap IO memory, "
+ "aborting.\n");
+ return;
+ }
+ do_write_test(p);
+ do_read_test(p);
+ iounmap_trace(p);
+}
+
+static int __init init(void)
+{
+ if (mmio_address == 0) {
+ printk(KERN_ERR MODULE_NAME ": you have to use the module "
+ "argument mmio_address.\n");
+ printk(KERN_ERR MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS"
+ " YOU REALLY KNOW WHAT YOU ARE DOING!\n");
+ return -ENXIO;
+ }
+
+ printk(KERN_WARNING MODULE_NAME ": WARNING: mapping 16 kB @ 0x%08lx "
+ "in PCI address space, and writing "
+ "rubbish in there.\n", mmio_address);
+ do_test();
+ return 0;
+}
+
+static void __exit cleanup(void)
+{
+ printk(KERN_DEBUG MODULE_NAME ": unloaded.\n");
+}
+
+module_init(init);
+module_exit(cleanup);
+MODULE_LICENSE("GPL");