aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/kmmio.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/kmmio.c')
-rw-r--r--arch/x86/mm/kmmio.c58
1 files changed, 33 insertions, 25 deletions
diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c
index 16ccbd77917f..5d0e67fff1a6 100644
--- a/arch/x86/mm/kmmio.c
+++ b/arch/x86/mm/kmmio.c
@@ -5,6 +5,8 @@
5 * 2008 Pekka Paalanen <pq@iki.fi> 5 * 2008 Pekka Paalanen <pq@iki.fi>
6 */ 6 */
7 7
8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
8#include <linux/list.h> 10#include <linux/list.h>
9#include <linux/rculist.h> 11#include <linux/rculist.h>
10#include <linux/spinlock.h> 12#include <linux/spinlock.h>
@@ -19,6 +21,7 @@
19#include <linux/kdebug.h> 21#include <linux/kdebug.h>
20#include <linux/mutex.h> 22#include <linux/mutex.h>
21#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/slab.h>
22#include <asm/cacheflush.h> 25#include <asm/cacheflush.h>
23#include <asm/tlbflush.h> 26#include <asm/tlbflush.h>
24#include <linux/errno.h> 27#include <linux/errno.h>
@@ -136,7 +139,7 @@ static int clear_page_presence(struct kmmio_fault_page *f, bool clear)
136 pte_t *pte = lookup_address(f->page, &level); 139 pte_t *pte = lookup_address(f->page, &level);
137 140
138 if (!pte) { 141 if (!pte) {
139 pr_err("kmmio: no pte for page 0x%08lx\n", f->page); 142 pr_err("no pte for page 0x%08lx\n", f->page);
140 return -1; 143 return -1;
141 } 144 }
142 145
@@ -148,7 +151,7 @@ static int clear_page_presence(struct kmmio_fault_page *f, bool clear)
148 clear_pte_presence(pte, clear, &f->old_presence); 151 clear_pte_presence(pte, clear, &f->old_presence);
149 break; 152 break;
150 default: 153 default:
151 pr_err("kmmio: unexpected page level 0x%x.\n", level); 154 pr_err("unexpected page level 0x%x.\n", level);
152 return -1; 155 return -1;
153 } 156 }
154 157
@@ -170,13 +173,14 @@ static int clear_page_presence(struct kmmio_fault_page *f, bool clear)
170static int arm_kmmio_fault_page(struct kmmio_fault_page *f) 173static int arm_kmmio_fault_page(struct kmmio_fault_page *f)
171{ 174{
172 int ret; 175 int ret;
173 WARN_ONCE(f->armed, KERN_ERR "kmmio page already armed.\n"); 176 WARN_ONCE(f->armed, KERN_ERR pr_fmt("kmmio page already armed.\n"));
174 if (f->armed) { 177 if (f->armed) {
175 pr_warning("kmmio double-arm: page 0x%08lx, ref %d, old %d\n", 178 pr_warning("double-arm: page 0x%08lx, ref %d, old %d\n",
176 f->page, f->count, !!f->old_presence); 179 f->page, f->count, !!f->old_presence);
177 } 180 }
178 ret = clear_page_presence(f, true); 181 ret = clear_page_presence(f, true);
179 WARN_ONCE(ret < 0, KERN_ERR "kmmio arming 0x%08lx failed.\n", f->page); 182 WARN_ONCE(ret < 0, KERN_ERR pr_fmt("arming 0x%08lx failed.\n"),
183 f->page);
180 f->armed = true; 184 f->armed = true;
181 return ret; 185 return ret;
182} 186}
@@ -203,7 +207,7 @@ static void disarm_kmmio_fault_page(struct kmmio_fault_page *f)
203 */ 207 */
204/* 208/*
205 * Interrupts are disabled on entry as trap3 is an interrupt gate 209 * Interrupts are disabled on entry as trap3 is an interrupt gate
206 * and they remain disabled thorough out this function. 210 * and they remain disabled throughout this function.
207 */ 211 */
208int kmmio_handler(struct pt_regs *regs, unsigned long addr) 212int kmmio_handler(struct pt_regs *regs, unsigned long addr)
209{ 213{
@@ -240,24 +244,21 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr)
240 * condition needs handling by do_page_fault(), the 244 * condition needs handling by do_page_fault(), the
241 * page really not being present is the most common. 245 * page really not being present is the most common.
242 */ 246 */
243 pr_debug("kmmio: secondary hit for 0x%08lx CPU %d.\n", 247 pr_debug("secondary hit for 0x%08lx CPU %d.\n",
244 addr, smp_processor_id()); 248 addr, smp_processor_id());
245 249
246 if (!faultpage->old_presence) 250 if (!faultpage->old_presence)
247 pr_info("kmmio: unexpected secondary hit for " 251 pr_info("unexpected secondary hit for address 0x%08lx on CPU %d.\n",
248 "address 0x%08lx on CPU %d.\n", addr, 252 addr, smp_processor_id());
249 smp_processor_id());
250 } else { 253 } else {
251 /* 254 /*
252 * Prevent overwriting already in-flight context. 255 * Prevent overwriting already in-flight context.
253 * This should not happen, let's hope disarming at 256 * This should not happen, let's hope disarming at
254 * least prevents a panic. 257 * least prevents a panic.
255 */ 258 */
256 pr_emerg("kmmio: recursive probe hit on CPU %d, " 259 pr_emerg("recursive probe hit on CPU %d, for address 0x%08lx. Ignoring.\n",
257 "for address 0x%08lx. Ignoring.\n", 260 smp_processor_id(), addr);
258 smp_processor_id(), addr); 261 pr_emerg("previous hit was at 0x%08lx.\n", ctx->addr);
259 pr_emerg("kmmio: previous hit was at 0x%08lx.\n",
260 ctx->addr);
261 disarm_kmmio_fault_page(faultpage); 262 disarm_kmmio_fault_page(faultpage);
262 } 263 }
263 goto no_kmmio_ctx; 264 goto no_kmmio_ctx;
@@ -302,7 +303,7 @@ no_kmmio:
302 303
303/* 304/*
304 * Interrupts are disabled on entry as trap1 is an interrupt gate 305 * Interrupts are disabled on entry as trap1 is an interrupt gate
305 * and they remain disabled thorough out this function. 306 * and they remain disabled throughout this function.
306 * This must always get called as the pair to kmmio_handler(). 307 * This must always get called as the pair to kmmio_handler().
307 */ 308 */
308static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs) 309static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
@@ -316,8 +317,8 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
316 * something external causing them (f.e. using a debugger while 317 * something external causing them (f.e. using a debugger while
317 * mmio tracing enabled), or erroneous behaviour 318 * mmio tracing enabled), or erroneous behaviour
318 */ 319 */
319 pr_warning("kmmio: unexpected debug trap on CPU %d.\n", 320 pr_warning("unexpected debug trap on CPU %d.\n",
320 smp_processor_id()); 321 smp_processor_id());
321 goto out; 322 goto out;
322 } 323 }
323 324
@@ -425,7 +426,7 @@ int register_kmmio_probe(struct kmmio_probe *p)
425 list_add_rcu(&p->list, &kmmio_probes); 426 list_add_rcu(&p->list, &kmmio_probes);
426 while (size < size_lim) { 427 while (size < size_lim) {
427 if (add_kmmio_fault_page(p->addr + size)) 428 if (add_kmmio_fault_page(p->addr + size))
428 pr_err("kmmio: Unable to set page fault.\n"); 429 pr_err("Unable to set page fault.\n");
429 size += PAGE_SIZE; 430 size += PAGE_SIZE;
430 } 431 }
431out: 432out:
@@ -490,7 +491,7 @@ static void remove_kmmio_fault_pages(struct rcu_head *head)
490 * 2. remove_kmmio_fault_pages() 491 * 2. remove_kmmio_fault_pages()
491 * Remove the pages from kmmio_page_table. 492 * Remove the pages from kmmio_page_table.
492 * 3. rcu_free_kmmio_fault_pages() 493 * 3. rcu_free_kmmio_fault_pages()
493 * Actally free the kmmio_fault_page structs as with RCU. 494 * Actually free the kmmio_fault_page structs as with RCU.
494 */ 495 */
495void unregister_kmmio_probe(struct kmmio_probe *p) 496void unregister_kmmio_probe(struct kmmio_probe *p)
496{ 497{
@@ -511,7 +512,7 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
511 512
512 drelease = kmalloc(sizeof(*drelease), GFP_ATOMIC); 513 drelease = kmalloc(sizeof(*drelease), GFP_ATOMIC);
513 if (!drelease) { 514 if (!drelease) {
514 pr_crit("kmmio: leaking kmmio_fault_page objects.\n"); 515 pr_crit("leaking kmmio_fault_page objects.\n");
515 return; 516 return;
516 } 517 }
517 drelease->release_list = release_list; 518 drelease->release_list = release_list;
@@ -538,10 +539,17 @@ static int
538kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args) 539kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args)
539{ 540{
540 struct die_args *arg = args; 541 struct die_args *arg = args;
542 unsigned long* dr6_p = (unsigned long *)ERR_PTR(arg->err);
541 543
542 if (val == DIE_DEBUG && (arg->err & DR_STEP)) 544 if (val == DIE_DEBUG && (*dr6_p & DR_STEP))
543 if (post_kmmio_handler(arg->err, arg->regs) == 1) 545 if (post_kmmio_handler(*dr6_p, arg->regs) == 1) {
546 /*
547 * Reset the BS bit in dr6 (pointed by args->err) to
548 * denote completion of processing
549 */
550 *dr6_p &= ~DR_STEP;
544 return NOTIFY_STOP; 551 return NOTIFY_STOP;
552 }
545 553
546 return NOTIFY_DONE; 554 return NOTIFY_DONE;
547} 555}