aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/mmiotrace/mmio-mod.c
diff options
context:
space:
mode:
authorPekka Paalanen <pq@iki.fi>2008-05-12 15:20:57 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-24 05:22:12 -0400
commit0fd0e3da4557c479b820b9a4a7afa25b4637ddf2 (patch)
tree5f34b3673202303f394c6dd180a15751f50014e9 /arch/x86/kernel/mmiotrace/mmio-mod.c
parentf513638030ca384b0bace4df64f0b82f6ae1e4c6 (diff)
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>
Diffstat (limited to 'arch/x86/kernel/mmiotrace/mmio-mod.c')
-rw-r--r--arch/x86/kernel/mmiotrace/mmio-mod.c81
1 files changed, 39 insertions, 42 deletions
diff --git a/arch/x86/kernel/mmiotrace/mmio-mod.c b/arch/x86/kernel/mmiotrace/mmio-mod.c
index f9c609266d83..e1a508588f03 100644
--- a/arch/x86/kernel/mmiotrace/mmio-mod.c
+++ b/arch/x86/kernel/mmiotrace/mmio-mod.c
@@ -32,7 +32,6 @@
32#include <asm/atomic.h> 32#include <asm/atomic.h>
33#include <linux/percpu.h> 33#include <linux/percpu.h>
34 34
35#include "kmmio.h"
36#include "pf_in.h" 35#include "pf_in.h"
37 36
38/* This app's relay channel files will appear in /debug/mmio-trace */ 37/* This app's relay channel files will appear in /debug/mmio-trace */
@@ -129,18 +128,17 @@ static void print_pte(unsigned long address)
129 pte_t *pte = lookup_address(address, &level); 128 pte_t *pte = lookup_address(address, &level);
130 129
131 if (!pte) { 130 if (!pte) {
132 printk(KERN_ERR "Error in %s: no pte for page 0x%08lx\n", 131 pr_err(MODULE_NAME ": Error in %s: no pte for page 0x%08lx\n",
133 __FUNCTION__, address); 132 __func__, address);
134 return; 133 return;
135 } 134 }
136 135
137 if (level == PG_LEVEL_2M) { 136 if (level == PG_LEVEL_2M) {
138 printk(KERN_EMERG MODULE_NAME ": 4MB pages are not " 137 pr_emerg(MODULE_NAME ": 4MB pages are not currently "
139 "currently supported: %lx\n", 138 "supported: %lx\n", address);
140 address);
141 BUG(); 139 BUG();
142 } 140 }
143 printk(KERN_DEBUG MODULE_NAME ": pte for 0x%lx: 0x%lx 0x%lx\n", 141 pr_info(MODULE_NAME ": pte for 0x%lx: 0x%lx 0x%lx\n",
144 address, pte_val(*pte), 142 address, pte_val(*pte),
145 pte_val(*pte) & _PAGE_PRESENT); 143 pte_val(*pte) & _PAGE_PRESENT);
146} 144}
@@ -152,7 +150,7 @@ static void print_pte(unsigned long address)
152static void die_kmmio_nesting_error(struct pt_regs *regs, unsigned long addr) 150static void die_kmmio_nesting_error(struct pt_regs *regs, unsigned long addr)
153{ 151{
154 const struct trap_reason *my_reason = &get_cpu_var(pf_reason); 152 const struct trap_reason *my_reason = &get_cpu_var(pf_reason);
155 printk(KERN_EMERG MODULE_NAME ": unexpected fault for address: %lx, " 153 pr_emerg(MODULE_NAME ": unexpected fault for address: %lx, "
156 "last fault for address: %lx\n", 154 "last fault for address: %lx\n",
157 addr, my_reason->addr); 155 addr, my_reason->addr);
158 print_pte(addr); 156 print_pte(addr);
@@ -160,20 +158,17 @@ static void die_kmmio_nesting_error(struct pt_regs *regs, unsigned long addr)
160 print_symbol(KERN_EMERG "faulting EIP is at %s\n", regs->ip); 158 print_symbol(KERN_EMERG "faulting EIP is at %s\n", regs->ip);
161 print_symbol(KERN_EMERG "last faulting EIP was at %s\n", 159 print_symbol(KERN_EMERG "last faulting EIP was at %s\n",
162 my_reason->ip); 160 my_reason->ip);
163 printk(KERN_EMERG 161 pr_emerg("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
164 "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
165 regs->ax, regs->bx, regs->cx, regs->dx); 162 regs->ax, regs->bx, regs->cx, regs->dx);
166 printk(KERN_EMERG 163 pr_emerg("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
167 "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
168 regs->si, regs->di, regs->bp, regs->sp); 164 regs->si, regs->di, regs->bp, regs->sp);
169#else 165#else
170 print_symbol(KERN_EMERG "faulting RIP is at %s\n", regs->ip); 166 print_symbol(KERN_EMERG "faulting RIP is at %s\n", regs->ip);
171 print_symbol(KERN_EMERG "last faulting RIP was at %s\n", 167 print_symbol(KERN_EMERG "last faulting RIP was at %s\n",
172 my_reason->ip); 168 my_reason->ip);
173 printk(KERN_EMERG "rax: %016lx rcx: %016lx rdx: %016lx\n", 169 pr_emerg("rax: %016lx rcx: %016lx rdx: %016lx\n",
174 regs->ax, regs->cx, regs->dx); 170 regs->ax, regs->cx, regs->dx);
175 printk(KERN_EMERG "rsi: %016lx rdi: %016lx " 171 pr_emerg("rsi: %016lx rdi: %016lx rbp: %016lx rsp: %016lx\n",
176 "rbp: %016lx rsp: %016lx\n",
177 regs->si, regs->di, regs->bp, regs->sp); 172 regs->si, regs->di, regs->bp, regs->sp);
178#endif 173#endif
179 put_cpu_var(pf_reason); 174 put_cpu_var(pf_reason);
@@ -251,10 +246,15 @@ static void post(struct kmmio_probe *p, unsigned long condition,
251 struct trap_reason *my_reason = &get_cpu_var(pf_reason); 246 struct trap_reason *my_reason = &get_cpu_var(pf_reason);
252 struct mm_io_header_rw *my_trace = &get_cpu_var(cpu_trace); 247 struct mm_io_header_rw *my_trace = &get_cpu_var(cpu_trace);
253 248
249 /*
250 * XXX: This might not get called, if the probe is removed while
251 * trace hit is on flight.
252 */
253
254 /* this should always return the active_trace count to 0 */ 254 /* this should always return the active_trace count to 0 */
255 my_reason->active_traces--; 255 my_reason->active_traces--;
256 if (my_reason->active_traces) { 256 if (my_reason->active_traces) {
257 printk(KERN_EMERG MODULE_NAME ": unexpected post handler"); 257 pr_emerg(MODULE_NAME ": unexpected post handler");
258 BUG(); 258 BUG();
259 } 259 }
260 260
@@ -283,16 +283,15 @@ static int subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
283 atomic_t *drop = &per_cpu(dropped, cpu); 283 atomic_t *drop = &per_cpu(dropped, cpu);
284 int count; 284 int count;
285 if (relay_buf_full(buf)) { 285 if (relay_buf_full(buf)) {
286 if (atomic_inc_return(drop) == 1) { 286 if (atomic_inc_return(drop) == 1)
287 printk(KERN_ERR MODULE_NAME ": cpu %d buffer full!\n", 287 pr_err(MODULE_NAME ": cpu %d buffer full!\n", cpu);
288 cpu);
289 }
290 return 0; 288 return 0;
291 } else if ((count = atomic_read(drop))) { 289 }
292 printk(KERN_ERR MODULE_NAME 290 count = atomic_read(drop);
293 ": cpu %d buffer no longer full, " 291 if (count) {
294 "missed %d events.\n", 292 pr_err(MODULE_NAME ": cpu %d buffer no longer full, "
295 cpu, count); 293 "missed %d events.\n",
294 cpu, count);
296 atomic_sub(count, drop); 295 atomic_sub(count, drop);
297 } 296 }
298 297
@@ -407,8 +406,8 @@ static void ioremap_trace_core(unsigned long offset, unsigned long size,
407 /* Don't trace the low PCI/ISA area, it's always mapped.. */ 406 /* Don't trace the low PCI/ISA area, it's always mapped.. */
408 if (!ISA_trace && (offset < ISA_END_ADDRESS) && 407 if (!ISA_trace && (offset < ISA_END_ADDRESS) &&
409 (offset + size > ISA_START_ADDRESS)) { 408 (offset + size > ISA_START_ADDRESS)) {
410 printk(KERN_NOTICE MODULE_NAME ": Ignoring map of low " 409 pr_notice(MODULE_NAME ": Ignoring map of low PCI/ISA area "
411 "PCI/ISA area (0x%lx-0x%lx)\n", 410 "(0x%lx-0x%lx)\n",
412 offset, offset + size); 411 offset, offset + size);
413 return; 412 return;
414 } 413 }
@@ -418,7 +417,7 @@ static void ioremap_trace_core(unsigned long offset, unsigned long size,
418void __iomem *ioremap_cache_trace(unsigned long offset, unsigned long size) 417void __iomem *ioremap_cache_trace(unsigned long offset, unsigned long size)
419{ 418{
420 void __iomem *p = ioremap_cache(offset, size); 419 void __iomem *p = ioremap_cache(offset, size);
421 printk(KERN_DEBUG MODULE_NAME ": ioremap_cache(0x%lx, 0x%lx) = %p\n", 420 pr_debug(MODULE_NAME ": ioremap_cache(0x%lx, 0x%lx) = %p\n",
422 offset, size, p); 421 offset, size, p);
423 ioremap_trace_core(offset, size, p); 422 ioremap_trace_core(offset, size, p);
424 return p; 423 return p;
@@ -428,7 +427,7 @@ EXPORT_SYMBOL(ioremap_cache_trace);
428void __iomem *ioremap_nocache_trace(unsigned long offset, unsigned long size) 427void __iomem *ioremap_nocache_trace(unsigned long offset, unsigned long size)
429{ 428{
430 void __iomem *p = ioremap_nocache(offset, size); 429 void __iomem *p = ioremap_nocache(offset, size);
431 printk(KERN_DEBUG MODULE_NAME ": ioremap_nocache(0x%lx, 0x%lx) = %p\n", 430 pr_debug(MODULE_NAME ": ioremap_nocache(0x%lx, 0x%lx) = %p\n",
432 offset, size, p); 431 offset, size, p);
433 ioremap_trace_core(offset, size, p); 432 ioremap_trace_core(offset, size, p);
434 return p; 433 return p;
@@ -455,7 +454,7 @@ void iounmap_trace(volatile void __iomem *addr)
455 }; 454 };
456 struct remap_trace *trace; 455 struct remap_trace *trace;
457 struct remap_trace *tmp; 456 struct remap_trace *tmp;
458 printk(KERN_DEBUG MODULE_NAME ": Unmapping %p.\n", addr); 457 pr_debug(MODULE_NAME ": Unmapping %p.\n", addr);
459 record_timestamp(&event.header); 458 record_timestamp(&event.header);
460 459
461 spin_lock(&trace_list_lock); 460 spin_lock(&trace_list_lock);
@@ -481,7 +480,7 @@ static void clear_trace_list(void)
481 480
482 spin_lock(&trace_list_lock); 481 spin_lock(&trace_list_lock);
483 list_for_each_entry_safe(trace, tmp, &trace_list, list) { 482 list_for_each_entry_safe(trace, tmp, &trace_list, list) {
484 printk(KERN_WARNING MODULE_NAME ": purging non-iounmapped " 483 pr_warning(MODULE_NAME ": purging non-iounmapped "
485 "trace @0x%08lx, size 0x%lx.\n", 484 "trace @0x%08lx, size 0x%lx.\n",
486 trace->probe.addr, trace->probe.len); 485 trace->probe.addr, trace->probe.len);
487 if (!nommiotrace) 486 if (!nommiotrace)
@@ -500,39 +499,37 @@ static int __init init(void)
500 499
501 dir = debugfs_create_dir(APP_DIR, NULL); 500 dir = debugfs_create_dir(APP_DIR, NULL);
502 if (!dir) { 501 if (!dir) {
503 printk(KERN_ERR MODULE_NAME 502 pr_err(MODULE_NAME ": Couldn't create relay app directory.\n");
504 ": Couldn't create relay app directory.\n");
505 return -ENOMEM; 503 return -ENOMEM;
506 } 504 }
507 505
508 chan = create_channel(subbuf_size, n_subbufs); 506 chan = create_channel(subbuf_size, n_subbufs);
509 if (!chan) { 507 if (!chan) {
510 debugfs_remove(dir); 508 debugfs_remove(dir);
511 printk(KERN_ERR MODULE_NAME 509 pr_err(MODULE_NAME ": relay app channel creation failed\n");
512 ": relay app channel creation failed\n");
513 return -ENOMEM; 510 return -ENOMEM;
514 } 511 }
515 512
516 init_kmmio(); 513 reference_kmmio();
517 514
518 proc_marker_file = create_proc_entry(MARKER_FILE, 0, NULL); 515 proc_marker_file = create_proc_entry(MARKER_FILE, 0, NULL);
519 if (proc_marker_file) 516 if (proc_marker_file)
520 proc_marker_file->write_proc = write_marker; 517 proc_marker_file->write_proc = write_marker;
521 518
522 printk(KERN_DEBUG MODULE_NAME ": loaded.\n"); 519 pr_debug(MODULE_NAME ": loaded.\n");
523 if (nommiotrace) 520 if (nommiotrace)
524 printk(KERN_DEBUG MODULE_NAME ": MMIO tracing disabled.\n"); 521 pr_info(MODULE_NAME ": MMIO tracing disabled.\n");
525 if (ISA_trace) 522 if (ISA_trace)
526 printk(KERN_WARNING MODULE_NAME 523 pr_warning(MODULE_NAME ": Warning! low ISA range will be "
527 ": Warning! low ISA range will be traced.\n"); 524 "traced.\n");
528 return 0; 525 return 0;
529} 526}
530 527
531static void __exit cleanup(void) 528static void __exit cleanup(void)
532{ 529{
533 printk(KERN_DEBUG MODULE_NAME ": unload...\n"); 530 pr_debug(MODULE_NAME ": unload...\n");
534 clear_trace_list(); 531 clear_trace_list();
535 cleanup_kmmio(); 532 unreference_kmmio();
536 remove_proc_entry(MARKER_FILE, NULL); 533 remove_proc_entry(MARKER_FILE, NULL);
537 destroy_channel(); 534 destroy_channel();
538 if (dir) 535 if (dir)