aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm
diff options
context:
space:
mode:
authorPekka Paalanen <pq@iki.fi>2008-05-12 15:20:59 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-24 05:25:37 -0400
commitff3a3e9ba5e4273a8bc10570adab4a390fb90757 (patch)
tree63fd9b1c69ba53c514b9b2eb59ee17f10d6511de /arch/x86/mm
parent49023168261a7f9a2fd4a1ca1adbfea922556015 (diff)
x86 mmiotrace: move files into arch/x86/mm/.
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/mm')
-rw-r--r--arch/x86/mm/Makefile5
-rw-r--r--arch/x86/mm/kmmio.c499
-rw-r--r--arch/x86/mm/mmio-mod.c457
-rw-r--r--arch/x86/mm/pf_in.c489
-rw-r--r--arch/x86/mm/pf_in.h39
-rw-r--r--arch/x86/mm/testmmiotrace.c71
6 files changed, 1560 insertions, 0 deletions
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index b7b3e4c7cfc9..07dab503c9e3 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -8,6 +8,11 @@ obj-$(CONFIG_X86_PTDUMP) += dump_pagetables.o
8 8
9obj-$(CONFIG_HIGHMEM) += highmem_32.o 9obj-$(CONFIG_HIGHMEM) += highmem_32.o
10 10
11obj-$(CONFIG_MMIOTRACE_HOOKS) += kmmio.o
12obj-$(CONFIG_MMIOTRACE) += mmiotrace.o
13mmiotrace-y := pf_in.o mmio-mod.o
14obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o
15
11ifeq ($(CONFIG_X86_32),y) 16ifeq ($(CONFIG_X86_32),y)
12obj-$(CONFIG_NUMA) += discontig_32.o 17obj-$(CONFIG_NUMA) += discontig_32.o
13else 18else
diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c
new file mode 100644
index 000000000000..3ad27b8504a5
--- /dev/null
+++ b/arch/x86/mm/kmmio.c
@@ -0,0 +1,499 @@
1/* Support for MMIO probes.
2 * Benfit many code from kprobes
3 * (C) 2002 Louis Zhuang <louis.zhuang@intel.com>.
4 * 2007 Alexander Eichner
5 * 2008 Pekka Paalanen <pq@iki.fi>
6 */
7
8#include <linux/list.h>
9#include <linux/spinlock.h>
10#include <linux/hash.h>
11#include <linux/init.h>
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/uaccess.h>
15#include <linux/ptrace.h>
16#include <linux/preempt.h>
17#include <linux/percpu.h>
18#include <linux/kdebug.h>
19#include <linux/mutex.h>
20#include <asm/io.h>
21#include <asm/cacheflush.h>
22#include <asm/tlbflush.h>
23#include <asm/errno.h>
24#include <asm/debugreg.h>
25#include <linux/mmiotrace.h>
26
27#define KMMIO_PAGE_HASH_BITS 4
28#define KMMIO_PAGE_TABLE_SIZE (1 << KMMIO_PAGE_HASH_BITS)
29
30struct kmmio_fault_page {
31 struct list_head list;
32 struct kmmio_fault_page *release_next;
33 unsigned long page; /* location of the fault page */
34
35 /*
36 * Number of times this page has been registered as a part
37 * of a probe. If zero, page is disarmed and this may be freed.
38 * Used only by writers (RCU).
39 */
40 int count;
41};
42
43struct kmmio_delayed_release {
44 struct rcu_head rcu;
45 struct kmmio_fault_page *release_list;
46};
47
48struct kmmio_context {
49 struct kmmio_fault_page *fpage;
50 struct kmmio_probe *probe;
51 unsigned long saved_flags;
52 unsigned long addr;
53 int active;
54};
55
56static DEFINE_SPINLOCK(kmmio_lock);
57
58/* Protected by kmmio_lock */
59unsigned int kmmio_count;
60
61/* Read-protected by RCU, write-protected by kmmio_lock. */
62static struct list_head kmmio_page_table[KMMIO_PAGE_TABLE_SIZE];
63static LIST_HEAD(kmmio_probes);
64
65static struct list_head *kmmio_page_list(unsigned long page)
66{
67 return &kmmio_page_table[hash_long(page, KMMIO_PAGE_HASH_BITS)];
68}
69
70/* Accessed per-cpu */
71static DEFINE_PER_CPU(struct kmmio_context, kmmio_ctx);
72
73/*
74 * this is basically a dynamic stabbing problem:
75 * Could use the existing prio tree code or
76 * Possible better implementations:
77 * The Interval Skip List: A Data Structure for Finding All Intervals That
78 * Overlap a Point (might be simple)
79 * Space Efficient Dynamic Stabbing with Fast Queries - Mikkel Thorup
80 */
81/* Get the kmmio at this addr (if any). You must be holding RCU read lock. */
82static struct kmmio_probe *get_kmmio_probe(unsigned long addr)
83{
84 struct kmmio_probe *p;
85 list_for_each_entry_rcu(p, &kmmio_probes, list) {
86 if (addr >= p->addr && addr <= (p->addr + p->len))
87 return p;
88 }
89 return NULL;
90}
91
92/* You must be holding RCU read lock. */
93static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page)
94{
95 struct list_head *head;
96 struct kmmio_fault_page *p;
97
98 page &= PAGE_MASK;
99 head = kmmio_page_list(page);
100 list_for_each_entry_rcu(p, head, list) {
101 if (p->page == page)
102 return p;
103 }
104 return NULL;
105}
106
107static void set_page_present(unsigned long addr, bool present, int *pglevel)
108{
109 pteval_t pteval;
110 pmdval_t pmdval;
111 int level;
112 pmd_t *pmd;
113 pte_t *pte = lookup_address(addr, &level);
114
115 if (!pte) {
116 pr_err("kmmio: no pte for page 0x%08lx\n", addr);
117 return;
118 }
119
120 if (pglevel)
121 *pglevel = level;
122
123 switch (level) {
124 case PG_LEVEL_2M:
125 pmd = (pmd_t *)pte;
126 pmdval = pmd_val(*pmd) & ~_PAGE_PRESENT;
127 if (present)
128 pmdval |= _PAGE_PRESENT;
129 set_pmd(pmd, __pmd(pmdval));
130 break;
131
132 case PG_LEVEL_4K:
133 pteval = pte_val(*pte) & ~_PAGE_PRESENT;
134 if (present)
135 pteval |= _PAGE_PRESENT;
136 set_pte_atomic(pte, __pte(pteval));
137 break;
138
139 default:
140 pr_err("kmmio: unexpected page level 0x%x.\n", level);
141 return;
142 }
143
144 __flush_tlb_one(addr);
145}
146
147/** Mark the given page as not present. Access to it will trigger a fault. */
148static void arm_kmmio_fault_page(unsigned long page, int *page_level)
149{
150 set_page_present(page & PAGE_MASK, false, page_level);
151}
152
153/** Mark the given page as present. */
154static void disarm_kmmio_fault_page(unsigned long page, int *page_level)
155{
156 set_page_present(page & PAGE_MASK, true, page_level);
157}
158
159/*
160 * This is being called from do_page_fault().
161 *
162 * We may be in an interrupt or a critical section. Also prefecthing may
163 * trigger a page fault. We may be in the middle of process switch.
164 * We cannot take any locks, because we could be executing especially
165 * within a kmmio critical section.
166 *
167 * Local interrupts are disabled, so preemption cannot happen.
168 * Do not enable interrupts, do not sleep, and watch out for other CPUs.
169 */
170/*
171 * Interrupts are disabled on entry as trap3 is an interrupt gate
172 * and they remain disabled thorough out this function.
173 */
174int kmmio_handler(struct pt_regs *regs, unsigned long addr)
175{
176 struct kmmio_context *ctx;
177 struct kmmio_fault_page *faultpage;
178 int ret = 0; /* default to fault not handled */
179
180 /*
181 * Preemption is now disabled to prevent process switch during
182 * single stepping. We can only handle one active kmmio trace
183 * per cpu, so ensure that we finish it before something else
184 * gets to run. We also hold the RCU read lock over single
185 * stepping to avoid looking up the probe and kmmio_fault_page
186 * again.
187 */
188 preempt_disable();
189 rcu_read_lock();
190
191 faultpage = get_kmmio_fault_page(addr);
192 if (!faultpage) {
193 /*
194 * Either this page fault is not caused by kmmio, or
195 * another CPU just pulled the kmmio probe from under
196 * our feet. The latter case should not be possible.
197 */
198 goto no_kmmio;
199 }
200
201 ctx = &get_cpu_var(kmmio_ctx);
202 if (ctx->active) {
203 disarm_kmmio_fault_page(faultpage->page, NULL);
204 if (addr == ctx->addr) {
205 /*
206 * On SMP we sometimes get recursive probe hits on the
207 * same address. Context is already saved, fall out.
208 */
209 pr_debug("kmmio: duplicate probe hit on CPU %d, for "
210 "address 0x%08lx.\n",
211 smp_processor_id(), addr);
212 ret = 1;
213 goto no_kmmio_ctx;
214 }
215 /*
216 * Prevent overwriting already in-flight context.
217 * This should not happen, let's hope disarming at least
218 * prevents a panic.
219 */
220 pr_emerg("kmmio: recursive probe hit on CPU %d, "
221 "for address 0x%08lx. Ignoring.\n",
222 smp_processor_id(), addr);
223 pr_emerg("kmmio: previous hit was at 0x%08lx.\n",
224 ctx->addr);
225 goto no_kmmio_ctx;
226 }
227 ctx->active++;
228
229 ctx->fpage = faultpage;
230 ctx->probe = get_kmmio_probe(addr);
231 ctx->saved_flags = (regs->flags & (X86_EFLAGS_TF | X86_EFLAGS_IF));
232 ctx->addr = addr;
233
234 if (ctx->probe && ctx->probe->pre_handler)
235 ctx->probe->pre_handler(ctx->probe, regs, addr);
236
237 /*
238 * Enable single-stepping and disable interrupts for the faulting
239 * context. Local interrupts must not get enabled during stepping.
240 */
241 regs->flags |= X86_EFLAGS_TF;
242 regs->flags &= ~X86_EFLAGS_IF;
243
244 /* Now we set present bit in PTE and single step. */
245 disarm_kmmio_fault_page(ctx->fpage->page, NULL);
246
247 /*
248 * If another cpu accesses the same page while we are stepping,
249 * the access will not be caught. It will simply succeed and the
250 * only downside is we lose the event. If this becomes a problem,
251 * the user should drop to single cpu before tracing.
252 */
253
254 put_cpu_var(kmmio_ctx);
255 return 1; /* fault handled */
256
257no_kmmio_ctx:
258 put_cpu_var(kmmio_ctx);
259no_kmmio:
260 rcu_read_unlock();
261 preempt_enable_no_resched();
262 return ret;
263}
264
265/*
266 * Interrupts are disabled on entry as trap1 is an interrupt gate
267 * and they remain disabled thorough out this function.
268 * This must always get called as the pair to kmmio_handler().
269 */
270static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
271{
272 int ret = 0;
273 struct kmmio_context *ctx = &get_cpu_var(kmmio_ctx);
274
275 if (!ctx->active) {
276 pr_debug("kmmio: spurious debug trap on CPU %d.\n",
277 smp_processor_id());
278 goto out;
279 }
280
281 if (ctx->probe && ctx->probe->post_handler)
282 ctx->probe->post_handler(ctx->probe, condition, regs);
283
284 arm_kmmio_fault_page(ctx->fpage->page, NULL);
285
286 regs->flags &= ~X86_EFLAGS_TF;
287 regs->flags |= ctx->saved_flags;
288
289 /* These were acquired in kmmio_handler(). */
290 ctx->active--;
291 BUG_ON(ctx->active);
292 rcu_read_unlock();
293 preempt_enable_no_resched();
294
295 /*
296 * if somebody else is singlestepping across a probe point, flags
297 * will have TF set, in which case, continue the remaining processing
298 * of do_debug, as if this is not a probe hit.
299 */
300 if (!(regs->flags & X86_EFLAGS_TF))
301 ret = 1;
302out:
303 put_cpu_var(kmmio_ctx);
304 return ret;
305}
306
307/* You must be holding kmmio_lock. */
308static int add_kmmio_fault_page(unsigned long page)
309{
310 struct kmmio_fault_page *f;
311
312 page &= PAGE_MASK;
313 f = get_kmmio_fault_page(page);
314 if (f) {
315 if (!f->count)
316 arm_kmmio_fault_page(f->page, NULL);
317 f->count++;
318 return 0;
319 }
320
321 f = kmalloc(sizeof(*f), GFP_ATOMIC);
322 if (!f)
323 return -1;
324
325 f->count = 1;
326 f->page = page;
327 list_add_rcu(&f->list, kmmio_page_list(f->page));
328
329 arm_kmmio_fault_page(f->page, NULL);
330
331 return 0;
332}
333
334/* You must be holding kmmio_lock. */
335static void release_kmmio_fault_page(unsigned long page,
336 struct kmmio_fault_page **release_list)
337{
338 struct kmmio_fault_page *f;
339
340 page &= PAGE_MASK;
341 f = get_kmmio_fault_page(page);
342 if (!f)
343 return;
344
345 f->count--;
346 BUG_ON(f->count < 0);
347 if (!f->count) {
348 disarm_kmmio_fault_page(f->page, NULL);
349 f->release_next = *release_list;
350 *release_list = f;
351 }
352}
353
354int register_kmmio_probe(struct kmmio_probe *p)
355{
356 unsigned long flags;
357 int ret = 0;
358 unsigned long size = 0;
359
360 spin_lock_irqsave(&kmmio_lock, flags);
361 if (get_kmmio_probe(p->addr)) {
362 ret = -EEXIST;
363 goto out;
364 }
365 kmmio_count++;
366 list_add_rcu(&p->list, &kmmio_probes);
367 while (size < p->len) {
368 if (add_kmmio_fault_page(p->addr + size))
369 pr_err("kmmio: Unable to set page fault.\n");
370 size += PAGE_SIZE;
371 }
372out:
373 spin_unlock_irqrestore(&kmmio_lock, flags);
374 /*
375 * XXX: What should I do here?
376 * Here was a call to global_flush_tlb(), but it does not exist
377 * anymore. It seems it's not needed after all.
378 */
379 return ret;
380}
381EXPORT_SYMBOL(register_kmmio_probe);
382
383static void rcu_free_kmmio_fault_pages(struct rcu_head *head)
384{
385 struct kmmio_delayed_release *dr = container_of(
386 head,
387 struct kmmio_delayed_release,
388 rcu);
389 struct kmmio_fault_page *p = dr->release_list;
390 while (p) {
391 struct kmmio_fault_page *next = p->release_next;
392 BUG_ON(p->count);
393 kfree(p);
394 p = next;
395 }
396 kfree(dr);
397}
398
399static void remove_kmmio_fault_pages(struct rcu_head *head)
400{
401 struct kmmio_delayed_release *dr = container_of(
402 head,
403 struct kmmio_delayed_release,
404 rcu);
405 struct kmmio_fault_page *p = dr->release_list;
406 struct kmmio_fault_page **prevp = &dr->release_list;
407 unsigned long flags;
408 spin_lock_irqsave(&kmmio_lock, flags);
409 while (p) {
410 if (!p->count)
411 list_del_rcu(&p->list);
412 else
413 *prevp = p->release_next;
414 prevp = &p->release_next;
415 p = p->release_next;
416 }
417 spin_unlock_irqrestore(&kmmio_lock, flags);
418 /* This is the real RCU destroy call. */
419 call_rcu(&dr->rcu, rcu_free_kmmio_fault_pages);
420}
421
422/*
423 * Remove a kmmio probe. You have to synchronize_rcu() before you can be
424 * sure that the callbacks will not be called anymore. Only after that
425 * you may actually release your struct kmmio_probe.
426 *
427 * Unregistering a kmmio fault page has three steps:
428 * 1. release_kmmio_fault_page()
429 * Disarm the page, wait a grace period to let all faults finish.
430 * 2. remove_kmmio_fault_pages()
431 * Remove the pages from kmmio_page_table.
432 * 3. rcu_free_kmmio_fault_pages()
433 * Actally free the kmmio_fault_page structs as with RCU.
434 */
435void unregister_kmmio_probe(struct kmmio_probe *p)
436{
437 unsigned long flags;
438 unsigned long size = 0;
439 struct kmmio_fault_page *release_list = NULL;
440 struct kmmio_delayed_release *drelease;
441
442 spin_lock_irqsave(&kmmio_lock, flags);
443 while (size < p->len) {
444 release_kmmio_fault_page(p->addr + size, &release_list);
445 size += PAGE_SIZE;
446 }
447 list_del_rcu(&p->list);
448 kmmio_count--;
449 spin_unlock_irqrestore(&kmmio_lock, flags);
450
451 drelease = kmalloc(sizeof(*drelease), GFP_ATOMIC);
452 if (!drelease) {
453 pr_crit("kmmio: leaking kmmio_fault_page objects.\n");
454 return;
455 }
456 drelease->release_list = release_list;
457
458 /*
459 * This is not really RCU here. We have just disarmed a set of
460 * pages so that they cannot trigger page faults anymore. However,
461 * we cannot remove the pages from kmmio_page_table,
462 * because a probe hit might be in flight on another CPU. The
463 * pages are collected into a list, and they will be removed from
464 * kmmio_page_table when it is certain that no probe hit related to
465 * these pages can be in flight. RCU grace period sounds like a
466 * good choice.
467 *
468 * If we removed the pages too early, kmmio page fault handler might
469 * not find the respective kmmio_fault_page and determine it's not
470 * a kmmio fault, when it actually is. This would lead to madness.
471 */
472 call_rcu(&drelease->rcu, remove_kmmio_fault_pages);
473}
474EXPORT_SYMBOL(unregister_kmmio_probe);
475
476static int kmmio_die_notifier(struct notifier_block *nb, unsigned long val,
477 void *args)
478{
479 struct die_args *arg = args;
480
481 if (val == DIE_DEBUG && (arg->err & DR_STEP))
482 if (post_kmmio_handler(arg->err, arg->regs) == 1)
483 return NOTIFY_STOP;
484
485 return NOTIFY_DONE;
486}
487
488static struct notifier_block nb_die = {
489 .notifier_call = kmmio_die_notifier
490};
491
492static int __init init_kmmio(void)
493{
494 int i;
495 for (i = 0; i < KMMIO_PAGE_TABLE_SIZE; i++)
496 INIT_LIST_HEAD(&kmmio_page_table[i]);
497 return register_die_notifier(&nb_die);
498}
499fs_initcall(init_kmmio); /* should be before device_initcall() */
diff --git a/arch/x86/mm/mmio-mod.c b/arch/x86/mm/mmio-mod.c
new file mode 100644
index 000000000000..8256546d49bf
--- /dev/null
+++ b/arch/x86/mm/mmio-mod.c
@@ -0,0 +1,457 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * Copyright (C) IBM Corporation, 2005
17 * Jeff Muizelaar, 2006, 2007
18 * Pekka Paalanen, 2008 <pq@iki.fi>
19 *
20 * Derived from the read-mod example from relay-examples by Tom Zanussi.
21 */
22#define DEBUG 1
23
24#include <linux/module.h>
25#include <linux/debugfs.h>
26#include <linux/uaccess.h>
27#include <asm/io.h>
28#include <linux/version.h>
29#include <linux/kallsyms.h>
30#include <asm/pgtable.h>
31#include <linux/mmiotrace.h>
32#include <asm/e820.h> /* for ISA_START_ADDRESS */
33#include <asm/atomic.h>
34#include <linux/percpu.h>
35
36#include "pf_in.h"
37
38#define NAME "mmiotrace: "
39
40struct trap_reason {
41 unsigned long addr;
42 unsigned long ip;
43 enum reason_type type;
44 int active_traces;
45};
46
47struct remap_trace {
48 struct list_head list;
49 struct kmmio_probe probe;
50 unsigned long phys;
51 unsigned long id;
52};
53
54/* Accessed per-cpu. */
55static DEFINE_PER_CPU(struct trap_reason, pf_reason);
56static DEFINE_PER_CPU(struct mmiotrace_rw, cpu_trace);
57
58#if 0 /* XXX: no way gather this info anymore */
59/* Access to this is not per-cpu. */
60static DEFINE_PER_CPU(atomic_t, dropped);
61#endif
62
63static struct dentry *marker_file;
64
65static DEFINE_MUTEX(mmiotrace_mutex);
66static DEFINE_SPINLOCK(trace_lock);
67static atomic_t mmiotrace_enabled;
68static LIST_HEAD(trace_list); /* struct remap_trace */
69
70/*
71 * Locking in this file:
72 * - mmiotrace_mutex enforces enable/disable_mmiotrace() critical sections.
73 * - mmiotrace_enabled may be modified only when holding mmiotrace_mutex
74 * and trace_lock.
75 * - Routines depending on is_enabled() must take trace_lock.
76 * - trace_list users must hold trace_lock.
77 * - is_enabled() guarantees that mmio_trace_record is allowed.
78 * - pre/post callbacks assume the effect of is_enabled() being true.
79 */
80
81/* module parameters */
82static unsigned long filter_offset;
83static int nommiotrace;
84static int ISA_trace;
85static int trace_pc;
86
87module_param(filter_offset, ulong, 0);
88module_param(nommiotrace, bool, 0);
89module_param(ISA_trace, bool, 0);
90module_param(trace_pc, bool, 0);
91
92MODULE_PARM_DESC(filter_offset, "Start address of traced mappings.");
93MODULE_PARM_DESC(nommiotrace, "Disable actual MMIO tracing.");
94MODULE_PARM_DESC(ISA_trace, "Do not exclude the low ISA range.");
95MODULE_PARM_DESC(trace_pc, "Record address of faulting instructions.");
96
97static bool is_enabled(void)
98{
99 return atomic_read(&mmiotrace_enabled);
100}
101
102#if 0 /* XXX: needs rewrite */
103/*
104 * Write callback for the debugfs entry:
105 * Read a marker and write it to the mmio trace log
106 */
107static ssize_t write_marker(struct file *file, const char __user *buffer,
108 size_t count, loff_t *ppos)
109{
110 char *event = NULL;
111 struct mm_io_header *headp;
112 ssize_t len = (count > 65535) ? 65535 : count;
113
114 event = kzalloc(sizeof(*headp) + len, GFP_KERNEL);
115 if (!event)
116 return -ENOMEM;
117
118 headp = (struct mm_io_header *)event;
119 headp->type = MMIO_MAGIC | (MMIO_MARKER << MMIO_OPCODE_SHIFT);
120 headp->data_len = len;
121
122 if (copy_from_user(event + sizeof(*headp), buffer, len)) {
123 kfree(event);
124 return -EFAULT;
125 }
126
127 spin_lock_irq(&trace_lock);
128#if 0 /* XXX: convert this to use tracing */
129 if (is_enabled())
130 relay_write(chan, event, sizeof(*headp) + len);
131 else
132#endif
133 len = -EINVAL;
134 spin_unlock_irq(&trace_lock);
135 kfree(event);
136 return len;
137}
138#endif
139
140static void print_pte(unsigned long address)
141{
142 int level;
143 pte_t *pte = lookup_address(address, &level);
144
145 if (!pte) {
146 pr_err(NAME "Error in %s: no pte for page 0x%08lx\n",
147 __func__, address);
148 return;
149 }
150
151 if (level == PG_LEVEL_2M) {
152 pr_emerg(NAME "4MB pages are not currently supported: "
153 "0x%08lx\n", address);
154 BUG();
155 }
156 pr_info(NAME "pte for 0x%lx: 0x%lx 0x%lx\n", address, pte_val(*pte),
157 pte_val(*pte) & _PAGE_PRESENT);
158}
159
160/*
161 * For some reason the pre/post pairs have been called in an
162 * unmatched order. Report and die.
163 */
164static void die_kmmio_nesting_error(struct pt_regs *regs, unsigned long addr)
165{
166 const struct trap_reason *my_reason = &get_cpu_var(pf_reason);
167 pr_emerg(NAME "unexpected fault for address: 0x%08lx, "
168 "last fault for address: 0x%08lx\n",
169 addr, my_reason->addr);
170 print_pte(addr);
171 print_symbol(KERN_EMERG "faulting IP is at %s\n", regs->ip);
172 print_symbol(KERN_EMERG "last faulting IP was at %s\n", my_reason->ip);
173#ifdef __i386__
174 pr_emerg("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
175 regs->ax, regs->bx, regs->cx, regs->dx);
176 pr_emerg("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
177 regs->si, regs->di, regs->bp, regs->sp);
178#else
179 pr_emerg("rax: %016lx rcx: %016lx rdx: %016lx\n",
180 regs->ax, regs->cx, regs->dx);
181 pr_emerg("rsi: %016lx rdi: %016lx rbp: %016lx rsp: %016lx\n",
182 regs->si, regs->di, regs->bp, regs->sp);
183#endif
184 put_cpu_var(pf_reason);
185 BUG();
186}
187
188static void pre(struct kmmio_probe *p, struct pt_regs *regs,
189 unsigned long addr)
190{
191 struct trap_reason *my_reason = &get_cpu_var(pf_reason);
192 struct mmiotrace_rw *my_trace = &get_cpu_var(cpu_trace);
193 const unsigned long instptr = instruction_pointer(regs);
194 const enum reason_type type = get_ins_type(instptr);
195 struct remap_trace *trace = p->user_data;
196
197 /* it doesn't make sense to have more than one active trace per cpu */
198 if (my_reason->active_traces)
199 die_kmmio_nesting_error(regs, addr);
200 else
201 my_reason->active_traces++;
202
203 my_reason->type = type;
204 my_reason->addr = addr;
205 my_reason->ip = instptr;
206
207 my_trace->phys = addr - trace->probe.addr + trace->phys;
208 my_trace->map_id = trace->id;
209
210 /*
211 * Only record the program counter when requested.
212 * It may taint clean-room reverse engineering.
213 */
214 if (trace_pc)
215 my_trace->pc = instptr;
216 else
217 my_trace->pc = 0;
218
219 /*
220 * XXX: the timestamp recorded will be *after* the tracing has been
221 * done, not at the time we hit the instruction. SMP implications
222 * on event ordering?
223 */
224
225 switch (type) {
226 case REG_READ:
227 my_trace->opcode = MMIO_READ;
228 my_trace->width = get_ins_mem_width(instptr);
229 break;
230 case REG_WRITE:
231 my_trace->opcode = MMIO_WRITE;
232 my_trace->width = get_ins_mem_width(instptr);
233 my_trace->value = get_ins_reg_val(instptr, regs);
234 break;
235 case IMM_WRITE:
236 my_trace->opcode = MMIO_WRITE;
237 my_trace->width = get_ins_mem_width(instptr);
238 my_trace->value = get_ins_imm_val(instptr);
239 break;
240 default:
241 {
242 unsigned char *ip = (unsigned char *)instptr;
243 my_trace->opcode = MMIO_UNKNOWN_OP;
244 my_trace->width = 0;
245 my_trace->value = (*ip) << 16 | *(ip + 1) << 8 |
246 *(ip + 2);
247 }
248 }
249 put_cpu_var(cpu_trace);
250 put_cpu_var(pf_reason);
251}
252
253static void post(struct kmmio_probe *p, unsigned long condition,
254 struct pt_regs *regs)
255{
256 struct trap_reason *my_reason = &get_cpu_var(pf_reason);
257 struct mmiotrace_rw *my_trace = &get_cpu_var(cpu_trace);
258
259 /* this should always return the active_trace count to 0 */
260 my_reason->active_traces--;
261 if (my_reason->active_traces) {
262 pr_emerg(NAME "unexpected post handler");
263 BUG();
264 }
265
266 switch (my_reason->type) {
267 case REG_READ:
268 my_trace->value = get_ins_reg_val(my_reason->ip, regs);
269 break;
270 default:
271 break;
272 }
273
274 mmio_trace_rw(my_trace);
275 put_cpu_var(cpu_trace);
276 put_cpu_var(pf_reason);
277}
278
279static void ioremap_trace_core(unsigned long offset, unsigned long size,
280 void __iomem *addr)
281{
282 static atomic_t next_id;
283 struct remap_trace *trace = kmalloc(sizeof(*trace), GFP_KERNEL);
284 struct mmiotrace_map map = {
285 .phys = offset,
286 .virt = (unsigned long)addr,
287 .len = size,
288 .opcode = MMIO_PROBE
289 };
290
291 if (!trace) {
292 pr_err(NAME "kmalloc failed in ioremap\n");
293 return;
294 }
295
296 *trace = (struct remap_trace) {
297 .probe = {
298 .addr = (unsigned long)addr,
299 .len = size,
300 .pre_handler = pre,
301 .post_handler = post,
302 .user_data = trace
303 },
304 .phys = offset,
305 .id = atomic_inc_return(&next_id)
306 };
307 map.map_id = trace->id;
308
309 spin_lock_irq(&trace_lock);
310 if (!is_enabled())
311 goto not_enabled;
312
313 mmio_trace_mapping(&map);
314 list_add_tail(&trace->list, &trace_list);
315 if (!nommiotrace)
316 register_kmmio_probe(&trace->probe);
317
318not_enabled:
319 spin_unlock_irq(&trace_lock);
320}
321
322void
323mmiotrace_ioremap(unsigned long offset, unsigned long size, void __iomem *addr)
324{
325 if (!is_enabled()) /* recheck and proper locking in *_core() */
326 return;
327
328 pr_debug(NAME "ioremap_*(0x%lx, 0x%lx) = %p\n", offset, size, addr);
329 if ((filter_offset) && (offset != filter_offset))
330 return;
331 ioremap_trace_core(offset, size, addr);
332}
333
334static void iounmap_trace_core(volatile void __iomem *addr)
335{
336 struct mmiotrace_map map = {
337 .phys = 0,
338 .virt = (unsigned long)addr,
339 .len = 0,
340 .opcode = MMIO_UNPROBE
341 };
342 struct remap_trace *trace;
343 struct remap_trace *tmp;
344 struct remap_trace *found_trace = NULL;
345
346 pr_debug(NAME "Unmapping %p.\n", addr);
347
348 spin_lock_irq(&trace_lock);
349 if (!is_enabled())
350 goto not_enabled;
351
352 list_for_each_entry_safe(trace, tmp, &trace_list, list) {
353 if ((unsigned long)addr == trace->probe.addr) {
354 if (!nommiotrace)
355 unregister_kmmio_probe(&trace->probe);
356 list_del(&trace->list);
357 found_trace = trace;
358 break;
359 }
360 }
361 map.map_id = (found_trace) ? found_trace->id : -1;
362 mmio_trace_mapping(&map);
363
364not_enabled:
365 spin_unlock_irq(&trace_lock);
366 if (found_trace) {
367 synchronize_rcu(); /* unregister_kmmio_probe() requirement */
368 kfree(found_trace);
369 }
370}
371
372void mmiotrace_iounmap(volatile void __iomem *addr)
373{
374 might_sleep();
375 if (is_enabled()) /* recheck and proper locking in *_core() */
376 iounmap_trace_core(addr);
377}
378
379static void clear_trace_list(void)
380{
381 struct remap_trace *trace;
382 struct remap_trace *tmp;
383
384 /*
385 * No locking required, because the caller ensures we are in a
386 * critical section via mutex, and is_enabled() is false,
387 * i.e. nothing can traverse or modify this list.
388 * Caller also ensures is_enabled() cannot change.
389 */
390 list_for_each_entry(trace, &trace_list, list) {
391 pr_notice(NAME "purging non-iounmapped "
392 "trace @0x%08lx, size 0x%lx.\n",
393 trace->probe.addr, trace->probe.len);
394 if (!nommiotrace)
395 unregister_kmmio_probe(&trace->probe);
396 }
397 synchronize_rcu(); /* unregister_kmmio_probe() requirement */
398
399 list_for_each_entry_safe(trace, tmp, &trace_list, list) {
400 list_del(&trace->list);
401 kfree(trace);
402 }
403}
404
405#if 0 /* XXX: out of order */
406static struct file_operations fops_marker = {
407 .owner = THIS_MODULE,
408 .write = write_marker
409};
410#endif
411
412void enable_mmiotrace(void)
413{
414 mutex_lock(&mmiotrace_mutex);
415 if (is_enabled())
416 goto out;
417
418#if 0 /* XXX: tracing does not support text entries */
419 marker_file = debugfs_create_file("marker", 0660, dir, NULL,
420 &fops_marker);
421 if (!marker_file)
422 pr_err(NAME "marker file creation failed.\n");
423#endif
424
425 if (nommiotrace)
426 pr_info(NAME "MMIO tracing disabled.\n");
427 if (ISA_trace)
428 pr_warning(NAME "Warning! low ISA range will be traced.\n");
429 spin_lock_irq(&trace_lock);
430 atomic_inc(&mmiotrace_enabled);
431 spin_unlock_irq(&trace_lock);
432 pr_info(NAME "enabled.\n");
433out:
434 mutex_unlock(&mmiotrace_mutex);
435}
436
437void disable_mmiotrace(void)
438{
439 mutex_lock(&mmiotrace_mutex);
440 if (!is_enabled())
441 goto out;
442
443 spin_lock_irq(&trace_lock);
444 atomic_dec(&mmiotrace_enabled);
445 BUG_ON(is_enabled());
446 spin_unlock_irq(&trace_lock);
447
448 clear_trace_list(); /* guarantees: no more kmmio callbacks */
449 if (marker_file) {
450 debugfs_remove(marker_file);
451 marker_file = NULL;
452 }
453
454 pr_info(NAME "disabled.\n");
455out:
456 mutex_unlock(&mmiotrace_mutex);
457}
diff --git a/arch/x86/mm/pf_in.c b/arch/x86/mm/pf_in.c
new file mode 100644
index 000000000000..efa1911e20ca
--- /dev/null
+++ b/arch/x86/mm/pf_in.c
@@ -0,0 +1,489 @@
1/*
2 * Fault Injection Test harness (FI)
3 * Copyright (C) Intel Crop.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 *
20 */
21
22/* Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp
23 * Copyright by Intel Crop., 2002
24 * Louis Zhuang (louis.zhuang@intel.com)
25 *
26 * Bjorn Steinbrink (B.Steinbrink@gmx.de), 2007
27 */
28
29#include <linux/module.h>
30#include <linux/ptrace.h> /* struct pt_regs */
31#include "pf_in.h"
32
33#ifdef __i386__
34/* IA32 Manual 3, 2-1 */
35static unsigned char prefix_codes[] = {
36 0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
37 0x65, 0x2E, 0x3E, 0x66, 0x67
38};
39/* IA32 Manual 3, 3-432*/
40static unsigned int reg_rop[] = {
41 0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
42};
43static unsigned int reg_wop[] = { 0x88, 0x89 };
44static unsigned int imm_wop[] = { 0xC6, 0xC7 };
45/* IA32 Manual 3, 3-432*/
46static unsigned int rw8[] = { 0x88, 0x8A, 0xC6 };
47static unsigned int rw32[] = {
48 0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
49};
50static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F };
51static unsigned int mw16[] = { 0xB70F, 0xBF0F };
52static unsigned int mw32[] = { 0x89, 0x8B, 0xC7 };
53static unsigned int mw64[] = {};
54#else /* not __i386__ */
55static unsigned char prefix_codes[] = {
56 0x66, 0x67, 0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36,
57 0xF0, 0xF3, 0xF2,
58 /* REX Prefixes */
59 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
60 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
61};
62/* AMD64 Manual 3, Appendix A*/
63static unsigned int reg_rop[] = {
64 0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
65};
66static unsigned int reg_wop[] = { 0x88, 0x89 };
67static unsigned int imm_wop[] = { 0xC6, 0xC7 };
68static unsigned int rw8[] = { 0xC6, 0x88, 0x8A };
69static unsigned int rw32[] = {
70 0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
71};
72/* 8 bit only */
73static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F };
74/* 16 bit only */
75static unsigned int mw16[] = { 0xB70F, 0xBF0F };
76/* 16 or 32 bit */
77static unsigned int mw32[] = { 0xC7 };
78/* 16, 32 or 64 bit */
79static unsigned int mw64[] = { 0x89, 0x8B };
80#endif /* not __i386__ */
81
82static int skip_prefix(unsigned char *addr, int *shorted, int *enlarged,
83 int *rexr)
84{
85 int i;
86 unsigned char *p = addr;
87 *shorted = 0;
88 *enlarged = 0;
89 *rexr = 0;
90
91restart:
92 for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) {
93 if (*p == prefix_codes[i]) {
94 if (*p == 0x66)
95 *shorted = 1;
96#ifdef __amd64__
97 if ((*p & 0xf8) == 0x48)
98 *enlarged = 1;
99 if ((*p & 0xf4) == 0x44)
100 *rexr = 1;
101#endif
102 p++;
103 goto restart;
104 }
105 }
106
107 return (p - addr);
108}
109
110static int get_opcode(unsigned char *addr, unsigned int *opcode)
111{
112 int len;
113
114 if (*addr == 0x0F) {
115 /* 0x0F is extension instruction */
116 *opcode = *(unsigned short *)addr;
117 len = 2;
118 } else {
119 *opcode = *addr;
120 len = 1;
121 }
122
123 return len;
124}
125
126#define CHECK_OP_TYPE(opcode, array, type) \
127 for (i = 0; i < ARRAY_SIZE(array); i++) { \
128 if (array[i] == opcode) { \
129 rv = type; \
130 goto exit; \
131 } \
132 }
133
134enum reason_type get_ins_type(unsigned long ins_addr)
135{
136 unsigned int opcode;
137 unsigned char *p;
138 int shorted, enlarged, rexr;
139 int i;
140 enum reason_type rv = OTHERS;
141
142 p = (unsigned char *)ins_addr;
143 p += skip_prefix(p, &shorted, &enlarged, &rexr);
144 p += get_opcode(p, &opcode);
145
146 CHECK_OP_TYPE(opcode, reg_rop, REG_READ);
147 CHECK_OP_TYPE(opcode, reg_wop, REG_WRITE);
148 CHECK_OP_TYPE(opcode, imm_wop, IMM_WRITE);
149
150exit:
151 return rv;
152}
153#undef CHECK_OP_TYPE
154
155static unsigned int get_ins_reg_width(unsigned long ins_addr)
156{
157 unsigned int opcode;
158 unsigned char *p;
159 int i, shorted, enlarged, rexr;
160
161 p = (unsigned char *)ins_addr;
162 p += skip_prefix(p, &shorted, &enlarged, &rexr);
163 p += get_opcode(p, &opcode);
164
165 for (i = 0; i < ARRAY_SIZE(rw8); i++)
166 if (rw8[i] == opcode)
167 return 1;
168
169 for (i = 0; i < ARRAY_SIZE(rw32); i++)
170 if (rw32[i] == opcode)
171 return (shorted ? 2 : (enlarged ? 8 : 4));
172
173 printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
174 return 0;
175}
176
177unsigned int get_ins_mem_width(unsigned long ins_addr)
178{
179 unsigned int opcode;
180 unsigned char *p;
181 int i, shorted, enlarged, rexr;
182
183 p = (unsigned char *)ins_addr;
184 p += skip_prefix(p, &shorted, &enlarged, &rexr);
185 p += get_opcode(p, &opcode);
186
187 for (i = 0; i < ARRAY_SIZE(mw8); i++)
188 if (mw8[i] == opcode)
189 return 1;
190
191 for (i = 0; i < ARRAY_SIZE(mw16); i++)
192 if (mw16[i] == opcode)
193 return 2;
194
195 for (i = 0; i < ARRAY_SIZE(mw32); i++)
196 if (mw32[i] == opcode)
197 return shorted ? 2 : 4;
198
199 for (i = 0; i < ARRAY_SIZE(mw64); i++)
200 if (mw64[i] == opcode)
201 return shorted ? 2 : (enlarged ? 8 : 4);
202
203 printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
204 return 0;
205}
206
207/*
208 * Define register ident in mod/rm byte.
209 * Note: these are NOT the same as in ptrace-abi.h.
210 */
211enum {
212 arg_AL = 0,
213 arg_CL = 1,
214 arg_DL = 2,
215 arg_BL = 3,
216 arg_AH = 4,
217 arg_CH = 5,
218 arg_DH = 6,
219 arg_BH = 7,
220
221 arg_AX = 0,
222 arg_CX = 1,
223 arg_DX = 2,
224 arg_BX = 3,
225 arg_SP = 4,
226 arg_BP = 5,
227 arg_SI = 6,
228 arg_DI = 7,
229#ifdef __amd64__
230 arg_R8 = 8,
231 arg_R9 = 9,
232 arg_R10 = 10,
233 arg_R11 = 11,
234 arg_R12 = 12,
235 arg_R13 = 13,
236 arg_R14 = 14,
237 arg_R15 = 15
238#endif
239};
240
241static unsigned char *get_reg_w8(int no, struct pt_regs *regs)
242{
243 unsigned char *rv = NULL;
244
245 switch (no) {
246 case arg_AL:
247 rv = (unsigned char *)&regs->ax;
248 break;
249 case arg_BL:
250 rv = (unsigned char *)&regs->bx;
251 break;
252 case arg_CL:
253 rv = (unsigned char *)&regs->cx;
254 break;
255 case arg_DL:
256 rv = (unsigned char *)&regs->dx;
257 break;
258 case arg_AH:
259 rv = 1 + (unsigned char *)&regs->ax;
260 break;
261 case arg_BH:
262 rv = 1 + (unsigned char *)&regs->bx;
263 break;
264 case arg_CH:
265 rv = 1 + (unsigned char *)&regs->cx;
266 break;
267 case arg_DH:
268 rv = 1 + (unsigned char *)&regs->dx;
269 break;
270#ifdef __amd64__
271 case arg_R8:
272 rv = (unsigned char *)&regs->r8;
273 break;
274 case arg_R9:
275 rv = (unsigned char *)&regs->r9;
276 break;
277 case arg_R10:
278 rv = (unsigned char *)&regs->r10;
279 break;
280 case arg_R11:
281 rv = (unsigned char *)&regs->r11;
282 break;
283 case arg_R12:
284 rv = (unsigned char *)&regs->r12;
285 break;
286 case arg_R13:
287 rv = (unsigned char *)&regs->r13;
288 break;
289 case arg_R14:
290 rv = (unsigned char *)&regs->r14;
291 break;
292 case arg_R15:
293 rv = (unsigned char *)&regs->r15;
294 break;
295#endif
296 default:
297 printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
298 break;
299 }
300 return rv;
301}
302
303static unsigned long *get_reg_w32(int no, struct pt_regs *regs)
304{
305 unsigned long *rv = NULL;
306
307 switch (no) {
308 case arg_AX:
309 rv = &regs->ax;
310 break;
311 case arg_BX:
312 rv = &regs->bx;
313 break;
314 case arg_CX:
315 rv = &regs->cx;
316 break;
317 case arg_DX:
318 rv = &regs->dx;
319 break;
320 case arg_SP:
321 rv = &regs->sp;
322 break;
323 case arg_BP:
324 rv = &regs->bp;
325 break;
326 case arg_SI:
327 rv = &regs->si;
328 break;
329 case arg_DI:
330 rv = &regs->di;
331 break;
332#ifdef __amd64__
333 case arg_R8:
334 rv = &regs->r8;
335 break;
336 case arg_R9:
337 rv = &regs->r9;
338 break;
339 case arg_R10:
340 rv = &regs->r10;
341 break;
342 case arg_R11:
343 rv = &regs->r11;
344 break;
345 case arg_R12:
346 rv = &regs->r12;
347 break;
348 case arg_R13:
349 rv = &regs->r13;
350 break;
351 case arg_R14:
352 rv = &regs->r14;
353 break;
354 case arg_R15:
355 rv = &regs->r15;
356 break;
357#endif
358 default:
359 printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
360 }
361
362 return rv;
363}
364
365unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
366{
367 unsigned int opcode;
368 unsigned char mod_rm;
369 int reg;
370 unsigned char *p;
371 int i, shorted, enlarged, rexr;
372 unsigned long rv;
373
374 p = (unsigned char *)ins_addr;
375 p += skip_prefix(p, &shorted, &enlarged, &rexr);
376 p += get_opcode(p, &opcode);
377 for (i = 0; i < ARRAY_SIZE(reg_rop); i++)
378 if (reg_rop[i] == opcode) {
379 rv = REG_READ;
380 goto do_work;
381 }
382
383 for (i = 0; i < ARRAY_SIZE(reg_wop); i++)
384 if (reg_wop[i] == opcode) {
385 rv = REG_WRITE;
386 goto do_work;
387 }
388
389 printk(KERN_ERR "mmiotrace: Not a register instruction, opcode "
390 "0x%02x\n", opcode);
391 goto err;
392
393do_work:
394 mod_rm = *p;
395 reg = ((mod_rm >> 3) & 0x7) | (rexr << 3);
396 switch (get_ins_reg_width(ins_addr)) {
397 case 1:
398 return *get_reg_w8(reg, regs);
399
400 case 2:
401 return *(unsigned short *)get_reg_w32(reg, regs);
402
403 case 4:
404 return *(unsigned int *)get_reg_w32(reg, regs);
405
406#ifdef __amd64__
407 case 8:
408 return *(unsigned long *)get_reg_w32(reg, regs);
409#endif
410
411 default:
412 printk(KERN_ERR "mmiotrace: Error width# %d\n", reg);
413 }
414
415err:
416 return 0;
417}
418
419unsigned long get_ins_imm_val(unsigned long ins_addr)
420{
421 unsigned int opcode;
422 unsigned char mod_rm;
423 unsigned char mod;
424 unsigned char *p;
425 int i, shorted, enlarged, rexr;
426 unsigned long rv;
427
428 p = (unsigned char *)ins_addr;
429 p += skip_prefix(p, &shorted, &enlarged, &rexr);
430 p += get_opcode(p, &opcode);
431 for (i = 0; i < ARRAY_SIZE(imm_wop); i++)
432 if (imm_wop[i] == opcode) {
433 rv = IMM_WRITE;
434 goto do_work;
435 }
436
437 printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode "
438 "0x%02x\n", opcode);
439 goto err;
440
441do_work:
442 mod_rm = *p;
443 mod = mod_rm >> 6;
444 p++;
445 switch (mod) {
446 case 0:
447 /* if r/m is 5 we have a 32 disp (IA32 Manual 3, Table 2-2) */
448 /* AMD64: XXX Check for address size prefix? */
449 if ((mod_rm & 0x7) == 0x5)
450 p += 4;
451 break;
452
453 case 1:
454 p += 1;
455 break;
456
457 case 2:
458 p += 4;
459 break;
460
461 case 3:
462 default:
463 printk(KERN_ERR "mmiotrace: not a memory access instruction "
464 "at 0x%lx, rm_mod=0x%02x\n",
465 ins_addr, mod_rm);
466 }
467
468 switch (get_ins_reg_width(ins_addr)) {
469 case 1:
470 return *(unsigned char *)p;
471
472 case 2:
473 return *(unsigned short *)p;
474
475 case 4:
476 return *(unsigned int *)p;
477
478#ifdef __amd64__
479 case 8:
480 return *(unsigned long *)p;
481#endif
482
483 default:
484 printk(KERN_ERR "mmiotrace: Error: width.\n");
485 }
486
487err:
488 return 0;
489}
diff --git a/arch/x86/mm/pf_in.h b/arch/x86/mm/pf_in.h
new file mode 100644
index 000000000000..e05341a51a27
--- /dev/null
+++ b/arch/x86/mm/pf_in.h
@@ -0,0 +1,39 @@
1/*
2 * Fault Injection Test harness (FI)
3 * Copyright (C) Intel Crop.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 *
20 */
21
22#ifndef __PF_H_
23#define __PF_H_
24
25enum reason_type {
26 NOT_ME, /* page fault is not in regions */
27 NOTHING, /* access others point in regions */
28 REG_READ, /* read from addr to reg */
29 REG_WRITE, /* write from reg to addr */
30 IMM_WRITE, /* write from imm to addr */
31 OTHERS /* Other instructions can not intercept */
32};
33
34enum reason_type get_ins_type(unsigned long ins_addr);
35unsigned int get_ins_mem_width(unsigned long ins_addr);
36unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs);
37unsigned long get_ins_imm_val(unsigned long ins_addr);
38
39#endif /* __PF_H_ */
diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c
new file mode 100644
index 000000000000..cfa60b227c8d
--- /dev/null
+++ b/arch/x86/mm/testmmiotrace.c
@@ -0,0 +1,71 @@
1/*
2 * Written by Pekka Paalanen, 2008 <pq@iki.fi>
3 */
4#include <linux/module.h>
5#include <asm/io.h>
6
7#define MODULE_NAME "testmmiotrace"
8
9static unsigned long mmio_address;
10module_param(mmio_address, ulong, 0);
11MODULE_PARM_DESC(mmio_address, "Start address of the mapping of 16 kB.");
12
13static void do_write_test(void __iomem *p)
14{
15 unsigned int i;
16 for (i = 0; i < 256; i++)
17 iowrite8(i, p + i);
18 for (i = 1024; i < (5 * 1024); i += 2)
19 iowrite16(i * 12 + 7, p + i);
20 for (i = (5 * 1024); i < (16 * 1024); i += 4)
21 iowrite32(i * 212371 + 13, p + i);
22}
23
24static void do_read_test(void __iomem *p)
25{
26 unsigned int i;
27 for (i = 0; i < 256; i++)
28 ioread8(p + i);
29 for (i = 1024; i < (5 * 1024); i += 2)
30 ioread16(p + i);
31 for (i = (5 * 1024); i < (16 * 1024); i += 4)
32 ioread32(p + i);
33}
34
35static void do_test(void)
36{
37 void __iomem *p = ioremap_nocache(mmio_address, 0x4000);
38 if (!p) {
39 pr_err(MODULE_NAME ": could not ioremap, aborting.\n");
40 return;
41 }
42 do_write_test(p);
43 do_read_test(p);
44 iounmap(p);
45}
46
47static int __init init(void)
48{
49 if (mmio_address == 0) {
50 pr_err(MODULE_NAME ": you have to use the module argument "
51 "mmio_address.\n");
52 pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS"
53 " YOU REALLY KNOW WHAT YOU ARE DOING!\n");
54 return -ENXIO;
55 }
56
57 pr_warning(MODULE_NAME ": WARNING: mapping 16 kB @ 0x%08lx "
58 "in PCI address space, and writing "
59 "rubbish in there.\n", mmio_address);
60 do_test();
61 return 0;
62}
63
64static void __exit cleanup(void)
65{
66 pr_debug(MODULE_NAME ": unloaded.\n");
67}
68
69module_init(init);
70module_exit(cleanup);
71MODULE_LICENSE("GPL");