2008-05-12 12:20:56 -07:00
|
|
|
/*
|
2009-03-01 07:09:14 -07:00
|
|
|
* Written by Pekka Paalanen, 2008-2009 <pq@iki.fi>
|
2008-05-12 12:20:56 -07:00
|
|
|
*/
|
|
|
|
#include <linux/module.h>
|
2008-05-12 12:21:03 -07:00
|
|
|
#include <linux/io.h>
|
2008-09-16 12:00:34 -07:00
|
|
|
#include <linux/mmiotrace.h>
|
2008-05-12 12:20:56 -07:00
|
|
|
|
|
|
|
#define MODULE_NAME "testmmiotrace"
|
|
|
|
|
|
|
|
static unsigned long mmio_address;
|
|
|
|
module_param(mmio_address, ulong, 0);
|
2009-03-01 07:10:08 -07:00
|
|
|
MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
|
|
|
|
"(or 8 MB if read_far is non-zero).");
|
|
|
|
|
|
|
|
static unsigned long read_far = 0x400100;
|
|
|
|
module_param(read_far, ulong, 0);
|
|
|
|
MODULE_PARM_DESC(read_far, " Offset of a 32-bit read within 8 MB "
|
|
|
|
"(default: 0x400100).");
|
2008-05-12 12:20:56 -07:00
|
|
|
|
2009-03-01 07:09:14 -07:00
|
|
|
static unsigned v16(unsigned i)
|
|
|
|
{
|
|
|
|
return i * 12 + 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned v32(unsigned i)
|
|
|
|
{
|
|
|
|
return i * 212371 + 13;
|
|
|
|
}
|
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
static void do_write_test(void __iomem *p)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
2009-03-01 07:10:08 -07:00
|
|
|
pr_info(MODULE_NAME ": write test.\n");
|
2008-09-16 12:00:34 -07:00
|
|
|
mmiotrace_printk("Write test.\n");
|
2009-03-01 07:09:14 -07:00
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
iowrite8(i, p + i);
|
2009-03-01 07:09:14 -07:00
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
for (i = 1024; i < (5 * 1024); i += 2)
|
2009-03-01 07:09:14 -07:00
|
|
|
iowrite16(v16(i), p + i);
|
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
for (i = (5 * 1024); i < (16 * 1024); i += 4)
|
2009-03-01 07:09:14 -07:00
|
|
|
iowrite32(v32(i), p + i);
|
2008-05-12 12:20:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void do_read_test(void __iomem *p)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
2009-03-01 07:09:14 -07:00
|
|
|
unsigned errs[3] = { 0 };
|
2009-03-01 07:10:08 -07:00
|
|
|
pr_info(MODULE_NAME ": read test.\n");
|
2008-09-16 12:00:34 -07:00
|
|
|
mmiotrace_printk("Read test.\n");
|
2009-03-01 07:09:14 -07:00
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
for (i = 0; i < 256; i++)
|
2009-03-01 07:09:14 -07:00
|
|
|
if (ioread8(p + i) != i)
|
|
|
|
++errs[0];
|
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
for (i = 1024; i < (5 * 1024); i += 2)
|
2009-03-01 07:09:14 -07:00
|
|
|
if (ioread16(p + i) != v16(i))
|
|
|
|
++errs[1];
|
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
for (i = (5 * 1024); i < (16 * 1024); i += 4)
|
2009-03-01 07:09:14 -07:00
|
|
|
if (ioread32(p + i) != v32(i))
|
|
|
|
++errs[2];
|
|
|
|
|
|
|
|
mmiotrace_printk("Read errors: 8-bit %d, 16-bit %d, 32-bit %d.\n",
|
|
|
|
errs[0], errs[1], errs[2]);
|
2008-05-12 12:20:56 -07:00
|
|
|
}
|
|
|
|
|
2009-03-01 07:10:08 -07:00
|
|
|
static void do_read_far_test(void __iomem *p)
|
|
|
|
{
|
|
|
|
pr_info(MODULE_NAME ": read far test.\n");
|
|
|
|
mmiotrace_printk("Read far test.\n");
|
|
|
|
|
|
|
|
ioread32(p + read_far);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_test(unsigned long size)
|
2008-05-12 12:20:56 -07:00
|
|
|
{
|
2009-03-01 07:10:08 -07:00
|
|
|
void __iomem *p = ioremap_nocache(mmio_address, size);
|
2008-05-12 12:20:56 -07:00
|
|
|
if (!p) {
|
x86: mmiotrace full patch, preview 1
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>
2008-05-12 12:20:57 -07:00
|
|
|
pr_err(MODULE_NAME ": could not ioremap, aborting.\n");
|
2008-05-12 12:20:56 -07:00
|
|
|
return;
|
|
|
|
}
|
2008-09-16 12:00:34 -07:00
|
|
|
mmiotrace_printk("ioremap returned %p.\n", p);
|
2008-05-12 12:20:56 -07:00
|
|
|
do_write_test(p);
|
|
|
|
do_read_test(p);
|
2009-03-01 07:10:08 -07:00
|
|
|
if (read_far && read_far < size - 4)
|
|
|
|
do_read_far_test(p);
|
2008-05-12 12:20:57 -07:00
|
|
|
iounmap(p);
|
2008-05-12 12:20:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int __init init(void)
|
|
|
|
{
|
2009-03-01 07:10:08 -07:00
|
|
|
unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
|
|
|
|
|
2008-05-12 12:20:56 -07:00
|
|
|
if (mmio_address == 0) {
|
x86: mmiotrace full patch, preview 1
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>
2008-05-12 12:20:57 -07:00
|
|
|
pr_err(MODULE_NAME ": you have to use the module argument "
|
|
|
|
"mmio_address.\n");
|
|
|
|
pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS"
|
2008-05-12 12:20:56 -07:00
|
|
|
" YOU REALLY KNOW WHAT YOU ARE DOING!\n");
|
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
|
2009-03-01 07:10:08 -07:00
|
|
|
pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI "
|
|
|
|
"address space, and writing 16 kB of rubbish in there.\n",
|
|
|
|
size >> 10, mmio_address);
|
|
|
|
do_test(size);
|
|
|
|
pr_info(MODULE_NAME ": All done.\n");
|
2008-05-12 12:20:56 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit cleanup(void)
|
|
|
|
{
|
x86: mmiotrace full patch, preview 1
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>
2008-05-12 12:20:57 -07:00
|
|
|
pr_debug(MODULE_NAME ": unloaded.\n");
|
2008-05-12 12:20:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(init);
|
|
|
|
module_exit(cleanup);
|
|
|
|
MODULE_LICENSE("GPL");
|