summaryrefslogtreecommitdiff
path: root/arch/i386
diff options
context:
space:
mode:
authorZachary Amsden <zach@vmware.com>2007-02-13 12:26:21 (GMT)
committerAndi Kleen <andi@basil.nowhere.org>2007-02-13 12:26:21 (GMT)
commit7b3552024380f306a6c50d5105d18d9d4258fa4e (patch)
tree904a408768b216be7f759b4a190809f851a914d5 /arch/i386
parentbbab4f3bb7f528d2b8ccb5de9ae5f6ff3fb29684 (diff)
downloadlinux-7b3552024380f306a6c50d5105d18d9d4258fa4e.tar.xz
[PATCH] i386: Profile pc badness
Profile_pc was broken when using paravirtualization because the assumption the kernel was running at CPL 0 was violated, causing bad logic to read a random value off the stack. The only way to be in kernel lock functions is to be in kernel code, so validate that assumption explicitly by checking the CS value. We don't want to be fooled by BIOS / APM segments and try to read those stacks, so only match KERNEL_CS. I moved some stuff in segment.h to make it prettier. Signed-off-by: Zachary Amsden <zach@vmware.com> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/time.c10
1 files changed, 4 insertions, 6 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 9603cca..a4f67a6 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -131,15 +131,13 @@ unsigned long profile_pc(struct pt_regs *regs)
unsigned long pc = instruction_pointer(regs);
#ifdef CONFIG_SMP
- if (!user_mode_vm(regs) && in_lock_functions(pc)) {
+ if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->xcs) &&
+ in_lock_functions(pc)) {
#ifdef CONFIG_FRAME_POINTER
return *(unsigned long *)(regs->ebp + 4);
#else
- unsigned long *sp;
- if ((regs->xcs & 3) == 0)
- sp = (unsigned long *)&regs->esp;
- else
- sp = (unsigned long *)regs->esp;
+ unsigned long *sp = (unsigned long *)&regs->esp;
+
/* Return address is either directly at stack pointer
or above a saved eflags. Eflags has bits 22-31 zero,
kernel addresses don't. */