The core x86-64 NLKD adjustments to pre-existing code. From: Jan Beulich Index: 2.6.14-nlkd/arch/x86_64/ia32/ptrace32.c =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/ia32/ptrace32.c 2005-11-09 11:12:50.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/ia32/ptrace32.c 2005-11-04 16:19:33.000000000 +0100 @@ -88,22 +88,32 @@ static int putreg32(struct task_struct * return -EIO; case offsetof(struct user32, u_debugreg[0]): + if (enable_debugreg(child, 0, val) < 0) + return -EBUSY; child->thread.debugreg0 = val; break; case offsetof(struct user32, u_debugreg[1]): + if (enable_debugreg(child, 1, val) < 0) + return -EBUSY; child->thread.debugreg1 = val; break; case offsetof(struct user32, u_debugreg[2]): + if (enable_debugreg(child, 2, val) < 0) + return -EBUSY; child->thread.debugreg2 = val; break; case offsetof(struct user32, u_debugreg[3]): + if (enable_debugreg(child, 3, val) < 0) + return -EBUSY; child->thread.debugreg3 = val; break; case offsetof(struct user32, u_debugreg[6]): + if (enable_debugreg(child, 6, val) < 0) + return -EBUSY; child->thread.debugreg6 = val; break; @@ -112,8 +122,10 @@ static int putreg32(struct task_struct * /* See arch/i386/kernel/ptrace.c for an explanation of * this awkward check.*/ for(i=0; i<4; i++) - if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1) + if ((0x5554 >> ((val >> (16 + 4*i)) & 0xf)) & 1) return -EIO; + if (enable_debugreg(child, 7, val) < 0) + return -EBUSY; child->thread.debugreg7 = val; break; Index: 2.6.14-nlkd/arch/x86_64/kernel/process.c =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/kernel/process.c 2005-11-04 16:19:33.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/kernel/process.c 2005-11-04 16:19:33.000000000 +0100 @@ -50,6 +50,7 @@ #include #include #include +#include asmlinkage extern void ret_from_fork(void); @@ -346,6 +347,10 @@ void exit_thread(void) t->io_bitmap_max = 0; put_cpu(); } + if (me->thread.debugreg7) { + enable_debugreg(me, 7, 0); + me->thread.debugreg7 = 0; + } } void flush_thread(void) @@ -363,6 +368,8 @@ void flush_thread(void) if (t->flags & _TIF_ABI_PENDING) t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32); + if (tsk->thread.debugreg7) + enable_debugreg(tsk, 7, 0); tsk->thread.debugreg0 = 0; tsk->thread.debugreg1 = 0; tsk->thread.debugreg2 = 0; @@ -477,6 +484,13 @@ int copy_thread(int nr, unsigned long cl if (err) goto out; } + + if (me->thread.debugreg7) { + p->thread.debugreg7 = 0; + enable_debugreg(p, 7, me->thread.debugreg7); + p->thread.debugreg7 = me->thread.debugreg7; + } + err = 0; out: if (err && p->thread.io_bitmap_ptr) { @@ -489,7 +503,7 @@ out: /* * This special macro can be used to load a debugging register */ -#define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) +#define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r) /* * switch_to(x,y) should switch tasks from x to y. Index: 2.6.14-nlkd/arch/x86_64/kernel/ptrace.c =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/kernel/ptrace.c 2005-11-09 11:12:50.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/kernel/ptrace.c 2005-11-04 16:19:33.000000000 +0100 @@ -433,42 +433,66 @@ asmlinkage long sys_ptrace(long request, /* Disallows to set a breakpoint into the vsyscall */ case offsetof(struct user, u_debugreg[0]): if (data >= TASK_SIZE_OF(child) - dsize) break; + if (enable_debugreg(child, 0, data) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg0 = data; ret = 0; break; case offsetof(struct user, u_debugreg[1]): if (data >= TASK_SIZE_OF(child) - dsize) break; + if (enable_debugreg(child, 1, data) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg1 = data; ret = 0; break; case offsetof(struct user, u_debugreg[2]): if (data >= TASK_SIZE_OF(child) - dsize) break; + if (enable_debugreg(child, 2, data) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg2 = data; ret = 0; break; case offsetof(struct user, u_debugreg[3]): if (data >= TASK_SIZE_OF(child) - dsize) break; + if (enable_debugreg(child, 3, data) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg3 = data; ret = 0; break; case offsetof(struct user, u_debugreg[6]): - if (data >> 32) + if (data >> 32) break; + if (enable_debugreg(child, 6, data) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg6 = data; ret = 0; break; case offsetof(struct user, u_debugreg[7]): /* See arch/i386/kernel/ptrace.c for an explanation of * this awkward check.*/ - data &= ~DR_CONTROL_RESERVED; - for(i=0; i<4; i++) - if ((0x5454 >> ((data >> (16 + 4*i)) & 0xf)) & 1) + data &= ~DR_CONTROL_RESERVED; + for(i=0; i<4; i++) + if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1) break; if (i == 4) { + if (enable_debugreg(child, 7, data) < 0) { + ret = -EBUSY; + break; + } child->thread.debugreg7 = data; - ret = 0; - } - break; + ret = 0; + } + break; } break; } Index: 2.6.14-nlkd/arch/x86_64/kernel/setup64.c =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/kernel/setup64.c 2005-11-04 16:19:33.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/kernel/setup64.c 2005-11-04 16:19:33.000000000 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,}; @@ -289,12 +290,12 @@ void __cpuinit cpu_init (void) * Clear all 6 debug registers: */ - set_debug(0UL, 0); - set_debug(0UL, 1); - set_debug(0UL, 2); - set_debug(0UL, 3); - set_debug(0UL, 6); - set_debug(0UL, 7); + set_debugreg(0UL, 0); + set_debugreg(0UL, 1); + set_debugreg(0UL, 2); + set_debugreg(0UL, 3); + set_debugreg(0UL, 6); + set_debugreg(0UL, 7); fpu_init(); } Index: 2.6.14-nlkd/arch/x86_64/kernel/signal.c =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/kernel/signal.c 2005-11-09 11:12:50.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/kernel/signal.c 2005-11-04 16:19:33.000000000 +0100 @@ -29,6 +29,7 @@ #include #include #include +#include /* #define DEBUG_SIG 1 */ @@ -439,8 +440,8 @@ int do_signal(struct pt_regs *regs, sigs * have been cleared if the watchpoint triggered * inside the kernel. */ - if (current->thread.debugreg7) - set_debugreg(current->thread.debugreg7, 7); + if (unlikely(current->thread.debugreg7)) + restore_debugreg(); /* Whee! Actually deliver the signal. */ return handle_signal(signr, &info, &ka, oldset, regs); Index: 2.6.14-nlkd/arch/x86_64/kernel/suspend.c =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/kernel/suspend.c 2005-11-09 11:12:50.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/kernel/suspend.c 2005-11-04 17:52:58.000000000 +0100 @@ -13,6 +13,7 @@ #include #include #include +#include struct saved_context saved_context; Index: 2.6.14-nlkd/arch/x86_64/kernel/traps.c =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/kernel/traps.c 2005-11-09 11:19:36.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/kernel/traps.c 2005-11-07 09:33:53.000000000 +0100 @@ -784,7 +784,7 @@ asmlinkage void __kprobes do_debug(struc info.si_addr = (void __user *)regs->rip; force_sig_info(SIGTRAP, &info, tsk); clear_dr7: - set_debugreg(0UL, 7); + disable_debugreg(regs, 7); return; clear_TF_reenable: Index: 2.6.14-nlkd/arch/x86_64/kernel/vmlinux.lds.S =================================================================== --- 2.6.14-nlkd.orig/arch/x86_64/kernel/vmlinux.lds.S 2005-11-04 16:19:33.000000000 +0100 +++ 2.6.14-nlkd/arch/x86_64/kernel/vmlinux.lds.S 2005-11-04 16:19:33.000000000 +0100 @@ -144,6 +144,12 @@ SECTIONS __setup_start = .; .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) } __setup_end = .; +#ifdef CONFIG_NLKD + . = ALIGN(8); + __start_nlkd_ext = .; + .nlkd.ext : AT(ADDR(.nlkd.ext) - LOAD_OFFSET) { *(.nlkd.ext) } + __stop_nlkd_ext = .; +#endif __initcall_start = .; .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { *(.initcall1.init) Index: 2.6.14-nlkd/include/asm-x86_64/debugreg.h =================================================================== --- 2.6.14-nlkd.orig/include/asm-x86_64/debugreg.h 2005-11-09 11:12:50.000000000 +0100 +++ 2.6.14-nlkd/include/asm-x86_64/debugreg.h 2005-11-04 16:19:34.000000000 +0100 @@ -62,4 +62,54 @@ #define DR_LOCAL_SLOWDOWN (0x100) /* Local slow the pipeline */ #define DR_GLOBAL_SLOWDOWN (0x200) /* Global slow the pipeline */ +#ifdef CONFIG_NLKD + +# include + +struct pt_regs; +struct task_struct; + +# ifdef CONFIG_CDE +# define MAYBE_INDIR(x) x +# define set_debugreg(val, reg) ((void)(val), (void)(reg)) +# else +# define MAYBE_INDIR(x) (*x) +extern void (*set_debugreg)(uintptr_t value, nuint_t regnum); +# endif + +extern int MAYBE_INDIR(enable_debugreg)(struct task_struct *, nuint_t regnum, uintptr_t value); +extern int MAYBE_INDIR(disable_debugreg)(struct pt_regs *, nuint_t regnum); +extern int MAYBE_INDIR(restore_debugreg)(void); + +# undef MAYBE_INDIR + +#else + +# define set_debugreg(value, register) \ + __asm__("movq %0,%%db" #register \ + : /* no output */ \ + :"r" (value)) +# define enable_debugreg(task, regnum, value) ({ \ + (void)(task); \ + (void)(regnum); \ + (void)(value); \ + 0; \ + }) +# define disable_debugreg(regs, regnum) ({ \ + (void)(regs); \ + (void)(regnum); \ + set_debugreg(0UL, 7); \ + 0; \ + }) +# define restore_debugreg() ({ \ + set_debugreg(current->thread.debugreg7, 7); \ + 0; \ + }) + +#endif /* CONFIG_NLKD */ + +#define get_debugreg(var, register) \ + __asm__("movq %%db" #register ", %0" \ + :"=r" (var)) + #endif Index: 2.6.14-nlkd/include/asm-x86_64/processor.h =================================================================== --- 2.6.14-nlkd.orig/include/asm-x86_64/processor.h 2005-11-07 10:36:06.000000000 +0100 +++ 2.6.14-nlkd/include/asm-x86_64/processor.h 2005-11-07 10:36:06.000000000 +0100 @@ -271,9 +271,22 @@ struct thread_struct { #define DEBUG_STACK 4 #define MCE_STACK 5 #define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ + +#ifndef CONFIG_NLKD #define EXCEPTION_STACK_ORDER 0 +#else +#define EXCEPTION_STACK_ORDER 1 +#endif #define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER) + +#ifndef CONFIG_NLKD #define DEBUG_STACK_ORDER EXCEPTION_STACK_ORDER +#else +/* debug and breakpoint exceptions may nest 4 levels deep (minimum + requirement is 3 levels if handling exceptions from the debugger + should be possible, else 2 levels) */ +#define DEBUG_STACK_ORDER (EXCEPTION_STACK_ORDER + 2) +#endif #define DEBUG_STKSZ (PAGE_SIZE << DEBUG_STACK_ORDER) #define start_thread(regs,new_rip,new_rsp) do { \ @@ -288,14 +301,6 @@ struct thread_struct { set_fs(USER_DS); \ } while(0) -#define get_debugreg(var, register) \ - __asm__("movq %%db" #register ", %0" \ - :"=r" (var)) -#define set_debugreg(value, register) \ - __asm__("movq %0,%%db" #register \ - : /* no output */ \ - :"r" (value)) - struct task_struct; struct mm_struct; Index: 2.6.14-nlkd/include/asm-x86_64/suspend.h =================================================================== --- 2.6.14-nlkd.orig/include/asm-x86_64/suspend.h 2005-11-09 11:12:50.000000000 +0100 +++ 2.6.14-nlkd/include/asm-x86_64/suspend.h 2005-11-04 16:19:34.000000000 +0100 @@ -39,9 +39,7 @@ extern unsigned long saved_context_r12, extern unsigned long saved_context_eflags; #define loaddebug(thread,register) \ - __asm__("movq %0,%%db" #register \ - : /* no output */ \ - :"r" ((thread)->debugreg##register)) + set_debugreg((thread)->debugreg##register, register) extern void fix_processor_context(void); Index: 2.6.14-nlkd/include/asm-x86_64/system.h =================================================================== --- 2.6.14-nlkd.orig/include/asm-x86_64/system.h 2005-11-09 11:12:50.000000000 +0100 +++ 2.6.14-nlkd/include/asm-x86_64/system.h 2005-11-04 16:19:34.000000000 +0100 @@ -70,12 +70,6 @@ extern void load_gs_index(unsigned); ".previous" \ : :"r" (value), "r" (0)) -#define set_debug(value,register) \ - __asm__("movq %0,%%db" #register \ - : /* no output */ \ - :"r" ((unsigned long) value)) - - #ifdef __KERNEL__ struct alt_instr { __u8 *instr; /* original instruction */