2 #ifdef CONFIG_PREEMPT_NOTIFIERS_COMPAT
4 #include <linux/sched.h>
5 #include <linux/percpu.h>
7 static DEFINE_SPINLOCK(pn_lock
);
8 static LIST_HEAD(pn_list
);
10 #define dprintk(fmt) do { \
12 printk("%s (%d/%d): " fmt, __FUNCTION__, \
13 current->pid, raw_smp_processor_id()); \
16 #if !defined(CONFIG_X86_64) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
17 #define debugreg(x) debugreg[x]
19 #define debugreg(x) debugreg##x
22 static void preempt_enable_sched_out_notifiers(void)
24 asm volatile ("mov %0, %%db0" : : "r"(schedule
));
25 asm volatile ("mov %0, %%db7" : : "r"(0x701ul
));
26 current
->thread
.debugreg(7) = 0ul;
28 clear_tsk_thread_flag(current
, TIF_DEBUG
);
32 static void preempt_enable_sched_in_notifiers(void * addr
)
34 asm volatile ("mov %0, %%db0" : : "r"(addr
));
35 asm volatile ("mov %0, %%db7" : : "r"(0x701ul
));
36 current
->thread
.debugreg(0) = (unsigned long) addr
;
37 current
->thread
.debugreg(7) = 0x701ul
;
39 set_tsk_thread_flag(current
, TIF_DEBUG
);
43 void special_reload_dr7(void)
45 asm volatile ("mov %0, %%db7" : : "r"(0x701ul
));
47 EXPORT_SYMBOL_GPL(special_reload_dr7
);
49 static void __preempt_disable_notifiers(void)
51 asm volatile ("mov %0, %%db7" : : "r"(0ul));
54 static void preempt_disable_notifiers(void)
56 __preempt_disable_notifiers();
57 current
->thread
.debugreg(7) = 0ul;
59 clear_tsk_thread_flag(current
, TIF_DEBUG
);
63 static void fastcall
__attribute__((used
)) preempt_notifier_trigger(void *** ip
)
65 struct preempt_notifier
*pn
;
66 int cpu
= raw_smp_processor_id();
72 list_for_each_entry(pn
, &pn_list
, link
)
73 if (pn
->tsk
== current
) {
77 spin_unlock(&pn_lock
);
80 if ((void *) *ip
!= schedule
) {
81 dprintk("sched_in\n");
82 preempt_enable_sched_out_notifiers();
86 pn
->ops
->sched_in(pn
, cpu
);
88 preempt_enable_no_resched();
91 dprintk("sched_out\n");
93 sched_in_addr
= **(ip
+3);
95 /* no special debug stack switch on x86 */
96 sched_in_addr
= (void *) *(ip
+3);
98 preempt_enable_sched_in_notifiers(sched_in_addr
);
102 pn
->ops
->sched_out(pn
, NULL
);
104 preempt_enable_no_resched();
107 __preempt_disable_notifiers();
111 unsigned long orig_int1_handler
;
116 "push %rax; push %rbx; push %rcx; push %rdx; " \
117 "push %rsi; push %rdi; push %rbp; " \
118 "push %r8; push %r9; push %r10; push %r11; " \
119 "push %r12; push %r13; push %r14; push %r15"
121 #define RESTORE_REGS \
122 "pop %r15; pop %r14; pop %r13; pop %r12; " \
123 "pop %r11; pop %r10; pop %r9; pop %r8; " \
124 "pop %rbp; pop %rdi; pop %rsi; " \
125 "pop %rdx; pop %rcx; pop %rbx; pop %rax "
131 #define SAVE_REGS "pusha"
132 #define RESTORE_REGS "popa"
137 asm ("pn_int1_handler: \n\t"
139 "mov %db7, " TMP
" \n\t"
140 "cmp $0x701, " TMP
" \n\t"
145 "leaq 120(%rsp),%rdi\n\t"
147 "leal 32(%esp),%eax\n\t"
149 "call preempt_notifier_trigger \n\t"
152 "orq $0x10000, 16(%rsp) \n\t"
155 "orl $0x10000, 8(%esp) \n\t"
160 "jmpq *orig_int1_handler\n\t"
162 "jmpl *orig_int1_handler\n\t"
166 void preempt_notifier_register(struct preempt_notifier
*notifier
)
171 spin_lock_irqsave(&pn_lock
, flags
);
172 preempt_enable_sched_out_notifiers();
173 notifier
->tsk
= current
;
174 list_add(¬ifier
->link
, &pn_list
);
175 spin_unlock_irqrestore(&pn_lock
, flags
);
179 void preempt_notifier_unregister(struct preempt_notifier
*notifier
)
184 spin_lock_irqsave(&pn_lock
, flags
);
185 list_del(¬ifier
->link
);
186 spin_unlock_irqrestore(&pn_lock
, flags
);
187 preempt_disable_notifiers();
200 } __attribute__((packed
));
204 struct intr_gate
*gates
;
205 } __attribute__((packed
));
207 static struct intr_gate orig_int1_gate
;
209 void pn_int1_handler(void);
211 void preempt_notifier_sys_init(void)
213 struct idt_desc idt_desc
;
214 struct intr_gate
*int1_gate
;
216 printk("kvm: emulating preempt notifiers;"
217 " do not benchmark on this machine\n");
219 asm ("sidt %0" : "=m"(idt_desc
));
220 int1_gate
= &idt_desc
.gates
[1];
221 orig_int1_gate
= *int1_gate
;
222 orig_int1_handler
= int1_gate
->offset0
223 | ((u32
)int1_gate
->offset1
<< 16);
225 orig_int1_handler
|= (u64
)int1_gate
->offset2
<< 32;
227 int1_gate
->offset0
= (unsigned long)pn_int1_handler
;
228 int1_gate
->offset1
= (unsigned long)pn_int1_handler
>> 16;
230 int1_gate
->offset2
= (unsigned long)pn_int1_handler
>> 32;
234 static void do_disable(void *blah
)
237 if (!test_tsk_thread_flag(current
, TIF_DEBUG
))
239 if (!current
->thread
.debugreg(7))
241 __preempt_disable_notifiers();
244 void preempt_notifier_sys_exit(void)
246 struct idt_desc idt_desc
;
249 on_each_cpu(do_disable
, NULL
, 1, 1);
250 asm ("sidt %0" : "=m"(idt_desc
));
251 idt_desc
.gates
[1] = orig_int1_gate
;