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 static void preempt_enable_sched_out_notifiers(void)
18 asm volatile ("mov %0, %%db0" : : "r"(schedule
));
19 asm volatile ("mov %0, %%db7" : : "r"(0x701ul
));
21 current
->thread
.debugreg7
= 0ul;
23 current
->thread
.debugreg
[7] = 0ul;
26 clear_tsk_thread_flag(current
, TIF_DEBUG
);
30 static void preempt_enable_sched_in_notifiers(void * addr
)
32 asm volatile ("mov %0, %%db0" : : "r"(addr
));
33 asm volatile ("mov %0, %%db7" : : "r"(0x701ul
));
35 current
->thread
.debugreg0
= (unsigned long) addr
;
36 current
->thread
.debugreg7
= 0x701ul
;
38 current
->thread
.debugreg
[0] = (unsigned long) addr
;
39 current
->thread
.debugreg
[7] = 0x701ul
;
42 set_tsk_thread_flag(current
, TIF_DEBUG
);
46 void special_reload_dr7(void)
48 asm volatile ("mov %0, %%db7" : : "r"(0x701ul
));
50 EXPORT_SYMBOL_GPL(special_reload_dr7
);
52 static void __preempt_disable_notifiers(void)
54 asm volatile ("mov %0, %%db7" : : "r"(0ul));
57 static void preempt_disable_notifiers(void)
59 __preempt_disable_notifiers();
61 current
->thread
.debugreg7
= 0ul;
63 current
->thread
.debugreg
[7] = 0ul;
66 clear_tsk_thread_flag(current
, TIF_DEBUG
);
70 static void fastcall
__attribute__((used
)) preempt_notifier_trigger(void *** ip
)
72 struct preempt_notifier
*pn
;
73 int cpu
= raw_smp_processor_id();
79 list_for_each_entry(pn
, &pn_list
, link
)
80 if (pn
->tsk
== current
) {
84 spin_unlock(&pn_lock
);
87 if ((void *) *ip
!= schedule
) {
88 dprintk("sched_in\n");
89 preempt_enable_sched_out_notifiers();
93 pn
->ops
->sched_in(pn
, cpu
);
95 preempt_enable_no_resched();
98 dprintk("sched_out\n");
100 sched_in_addr
= **(ip
+3);
102 /* no special debug stack switch on x86 */
103 sched_in_addr
= (void *) *(ip
+3);
105 preempt_enable_sched_in_notifiers(sched_in_addr
);
109 pn
->ops
->sched_out(pn
, NULL
);
111 preempt_enable_no_resched();
114 __preempt_disable_notifiers();
118 unsigned long orig_int1_handler
;
123 "push %rax; push %rbx; push %rcx; push %rdx; " \
124 "push %rsi; push %rdi; push %rbp; " \
125 "push %r8; push %r9; push %r10; push %r11; " \
126 "push %r12; push %r13; push %r14; push %r15"
128 #define RESTORE_REGS \
129 "pop %r15; pop %r14; pop %r13; pop %r12; " \
130 "pop %r11; pop %r10; pop %r9; pop %r8; " \
131 "pop %rbp; pop %rdi; pop %rsi; " \
132 "pop %rdx; pop %rcx; pop %rbx; pop %rax "
138 #define SAVE_REGS "pusha"
139 #define RESTORE_REGS "popa"
144 asm ("pn_int1_handler: \n\t"
146 "mov %db6, " TMP
" \n\t"
147 "test $1, " TMP
" \n\t"
152 "leaq 120(%rsp),%rdi\n\t"
154 "leal 32(%esp),%eax\n\t"
156 "call preempt_notifier_trigger \n\t"
159 "orq $0x10000, 16(%rsp) \n\t"
162 "orl $0x10000, 8(%esp) \n\t"
167 "jmpq *orig_int1_handler\n\t"
169 "jmpl *orig_int1_handler\n\t"
173 void preempt_notifier_register(struct preempt_notifier
*notifier
)
178 spin_lock_irqsave(&pn_lock
, flags
);
179 preempt_enable_sched_out_notifiers();
180 notifier
->tsk
= current
;
181 list_add(¬ifier
->link
, &pn_list
);
182 spin_unlock_irqrestore(&pn_lock
, flags
);
186 void preempt_notifier_unregister(struct preempt_notifier
*notifier
)
191 spin_lock_irqsave(&pn_lock
, flags
);
192 list_del(¬ifier
->link
);
193 spin_unlock_irqrestore(&pn_lock
, flags
);
194 preempt_disable_notifiers();
207 } __attribute__((packed
));
211 struct intr_gate
*gates
;
212 } __attribute__((packed
));
214 static struct intr_gate orig_int1_gate
;
216 void pn_int1_handler(void);
218 void preempt_notifier_sys_init(void)
220 struct idt_desc idt_desc
;
221 struct intr_gate
*int1_gate
;
223 printk("kvm: emulating preempt notifiers;"
224 " do not benchmark on this machine\n");
226 asm ("sidt %0" : "=m"(idt_desc
));
227 int1_gate
= &idt_desc
.gates
[1];
228 orig_int1_gate
= *int1_gate
;
229 orig_int1_handler
= int1_gate
->offset0
230 | ((u32
)int1_gate
->offset1
<< 16);
232 orig_int1_handler
|= (u64
)int1_gate
->offset2
<< 32;
234 int1_gate
->offset0
= (unsigned long)pn_int1_handler
;
235 int1_gate
->offset1
= (unsigned long)pn_int1_handler
>> 16;
237 int1_gate
->offset2
= (unsigned long)pn_int1_handler
>> 32;
241 static void do_disable(void *blah
)
244 if (!test_tsk_thread_flag(current
, TIF_DEBUG
))
247 if (!current
->thread
.debugreg7
)
249 if (!current
->thread
.debugreg
[7])
252 __preempt_disable_notifiers();
255 void preempt_notifier_sys_exit(void)
257 struct idt_desc idt_desc
;
260 on_each_cpu(do_disable
, NULL
, 1, 1);
261 asm ("sidt %0" : "=m"(idt_desc
));
262 idt_desc
.gates
[1] = orig_int1_gate
;