linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Boottime allocated GDTs and doublefault handler
@ 2004-12-20  0:48 Zwane Mwaikambo
  2004-12-20  2:28 ` Linus Torvalds
  0 siblings, 1 reply; 5+ messages in thread
From: Zwane Mwaikambo @ 2004-12-20  0:48 UTC (permalink / raw)
  To: Linux Kernel; +Cc: Linus Torvalds

GDTs on SMP tend to be above the current ptr_ok limits since they are 
boottime allocated. How does the following new arbitrary limit look?

Signed-off-by: Zwane Mwaikambo <zwane@fsmlabs.com>

Index: linux-2.6.10-rc3-mm1/arch/i386/kernel/doublefault.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.10-rc3-mm1/arch/i386/kernel/doublefault.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 doublefault.c
--- linux-2.6.10-rc3-mm1/arch/i386/kernel/doublefault.c	13 Dec 2004 14:26:45 -0000	1.1.1.1
+++ linux-2.6.10-rc3-mm1/arch/i386/kernel/doublefault.c	20 Dec 2004 00:21:31 -0000
@@ -13,7 +13,7 @@
 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
 
-#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x1000000)
+#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x2000000)
 
 static void doublefault_fn(void)
 {

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Boottime allocated GDTs and doublefault handler
  2004-12-20  0:48 [PATCH] Boottime allocated GDTs and doublefault handler Zwane Mwaikambo
@ 2004-12-20  2:28 ` Linus Torvalds
  2004-12-20  7:21   ` Zwane Mwaikambo
  0 siblings, 1 reply; 5+ messages in thread
From: Linus Torvalds @ 2004-12-20  2:28 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Linux Kernel



On Sun, 19 Dec 2004, Zwane Mwaikambo wrote:
>
> GDTs on SMP tend to be above the current ptr_ok limits since they are 
> boottime allocated. How does the following new arbitrary limit look?

Ugh. That "ptr_ok()" macro was a total hack to get it working in the first 
place, we really shouldn't do that.

How about just making it a small function that actually walks the page 
tables (looking at %cr3 to find the base - at doublefault time it's not 
sane to try to depend on much anything else than raw register/memory 
state)?

It's not much of an issue for the gdt/tss checks, since those are very 
unlikely to be wrong anyway, but if we want to make the code print out any 
other information (like the old stack contents, and process info), then a 
"ptr_ok()" thing that actually is dependable would be a lot more useful..

Hint hint..

		Linus

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Boottime allocated GDTs and doublefault handler
  2004-12-20  2:28 ` Linus Torvalds
@ 2004-12-20  7:21   ` Zwane Mwaikambo
  2004-12-20 15:12     ` Zwane Mwaikambo
  0 siblings, 1 reply; 5+ messages in thread
From: Zwane Mwaikambo @ 2004-12-20  7:21 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel

Hi Linus,

On Sun, 19 Dec 2004, Linus Torvalds wrote:

> It's not much of an issue for the gdt/tss checks, since those are very 
> unlikely to be wrong anyway, but if we want to make the code print out any 
> other information (like the old stack contents, and process info), then a 
> "ptr_ok()" thing that actually is dependable would be a lot more useful..
> 
> Hint hint..

Ok =), i've added the page table walker and some basic code to fish out 
'current' and dump a few words of its stack. Sorry about the noise in the 
patch but the nested if()s were beginning to go too far.

 arch/i386/kernel/doublefault.c |   85 +++++++++++++++++++++++++++++++----------
 arch/i386/kernel/traps.c       |    6 --
 include/asm-i386/thread_info.h |    6 ++
 3 files changed, 71 insertions(+), 26 deletions(-)

===== arch/i386/kernel/doublefault.c 1.4 vs edited =====
--- 1.4/arch/i386/kernel/doublefault.c	2004-08-24 03:08:41 -06:00
+++ edited/arch/i386/kernel/doublefault.c	2004-12-20 00:04:50 -07:00
@@ -13,37 +13,82 @@
 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
 
-#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x1000000)
+static int ptr_ok(unsigned long vaddr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t pte;
+
+	__asm__ __volatile__("movl %%cr3, %0" : "=r"(pgd));
+	pgd = __va(pgd);
+	pgd += pgd_index(vaddr);
+	pmd = pmd_offset(pgd, vaddr);
+	if (pmd_none(*pmd))
+		return 0;
+	else if (pmd_large(*pmd))
+		return 1;
+
+	pte = *pte_offset_kernel(pmd, vaddr);
+	if (!pte_present(pte) || PageHighMem(pte_page(pte)))
+		return 0;
+
+	return 1;
+}
 
 static void doublefault_fn(void)
 {
 	struct Xgt_desc_struct gdt_desc = {0, 0};
-	unsigned long gdt, tss;
+	struct tss_struct *t;
+	struct thread_info *ti;
+	struct task_struct *tsk;
+	unsigned long gdt, tss, *esp;
+	int r = 0;
 
 	__asm__ __volatile__("sgdt %0": "=m" (gdt_desc): :"memory");
 	gdt = gdt_desc.address;
 
 	printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
 
-	if (ptr_ok(gdt)) {
-		gdt += GDT_ENTRY_TSS << 3;
-		tss = *(u16 *)(gdt+2);
-		tss += *(u8 *)(gdt+4) << 16;
-		tss += *(u8 *)(gdt+7) << 24;
-		printk("double fault, tss at %08lx\n", tss);
-
-		if (ptr_ok(tss)) {
-			struct tss_struct *t = (struct tss_struct *)tss;
-
-			printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp);
-
-			printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
-				t->eax, t->ebx, t->ecx, t->edx);
-			printk("esi = %08lx, edi = %08lx\n",
-				t->esi, t->edi);
-		}
-	}
+	if (!ptr_ok(gdt))
+		goto done;
+
+	gdt += GDT_ENTRY_TSS << 3;
+	tss = *(u16 *)(gdt+2);
+	tss += *(u8 *)(gdt+4) << 16;
+	tss += *(u8 *)(gdt+7) << 24;
+	printk("double fault, tss at %08lx\n", tss);
+
+	if (!ptr_ok(tss))
+		goto done;
+
+	t = (struct tss_struct *)tss;
+	printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp);
+	printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
+		t->eax, t->ebx, t->ecx, t->edx);
+	printk("esi = %08lx, edi = %08lx\n",
+		t->esi, t->edi);
+
+	if (!ptr_ok(t->esp))
+		goto done;
+
+	ti = (struct thread_info *)(t->esp & ~(THREAD_SIZE - 1));
+	tsk = ti->task;
+	if (!ptr_ok((unsigned long)tsk))
+		goto done;
+
+	esp = (unsigned long *)t->esp;
+	printk("task: %p (%s) stack:\n", tsk, tsk->comm);
+#if 0
+	show_stack(tsk, esp);
+#else
+	while (ptr_ok((unsigned long)esp) && valid_stack_ptr(ti, esp)) {
+		printk("%08lx ", *esp++);
+		if (!(++r % 8))
+			printk("\n");
+        }
+#endif
 
+done:
 	for (;;) /* nothing */;
 }
 
===== arch/i386/kernel/traps.c 1.91 vs edited =====
--- 1.91/arch/i386/kernel/traps.c	2004-11-23 17:47:27 -07:00
+++ edited/arch/i386/kernel/traps.c	2004-12-20 00:04:38 -07:00
@@ -105,12 +105,6 @@ int register_die_notifier(struct notifie
 	return err;
 }
 
-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
-{
-	return	p > (void *)tinfo &&
-		p < (void *)tinfo + THREAD_SIZE - 3;
-}
-
 static inline unsigned long print_context_stack(struct thread_info *tinfo,
 				unsigned long *stack, unsigned long ebp)
 {
===== include/asm-i386/thread_info.h 1.23 vs edited =====
--- 1.23/include/asm-i386/thread_info.h	2004-11-19 00:03:11 -07:00
+++ edited/include/asm-i386/thread_info.h	2004-12-20 00:09:19 -07:00
@@ -95,6 +95,12 @@ static inline struct thread_info *curren
 /* how to get the current stack pointer from C */
 register unsigned long current_stack_pointer asm("esp") __attribute_used__;
 
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+{
+        return  p > (void *)tinfo &&
+                p < (void *)tinfo + THREAD_SIZE - 3;
+}
+
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
 #define alloc_thread_info(tsk)					\

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Boottime allocated GDTs and doublefault handler
  2004-12-20  7:21   ` Zwane Mwaikambo
@ 2004-12-20 15:12     ` Zwane Mwaikambo
  2005-01-09  4:55       ` Zwane Mwaikambo
  0 siblings, 1 reply; 5+ messages in thread
From: Zwane Mwaikambo @ 2004-12-20 15:12 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel

On Mon, 20 Dec 2004, Zwane Mwaikambo wrote:

> Ok =), i've added the page table walker and some basic code to fish out 
> 'current' and dump a few words of its stack. Sorry about the noise in the 
> patch but the nested if()s were beginning to go too far.

William Irwin pointed out my faulty highmem page check;

 arch/i386/kernel/doublefault.c |   89 +++++++++++++++++++++++++++++++----------
 arch/i386/kernel/traps.c       |    6 --
 include/asm-i386/thread_info.h |    6 ++
 3 files changed, 75 insertions(+), 26 deletions(-)

===== arch/i386/kernel/doublefault.c 1.4 vs edited =====
--- 1.4/arch/i386/kernel/doublefault.c	2004-08-24 03:08:41 -06:00
+++ edited/arch/i386/kernel/doublefault.c	2004-12-20 08:08:40 -07:00
@@ -3,6 +3,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/highmem.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -13,37 +14,85 @@
 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
 
-#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x1000000)
+static int ptr_ok(unsigned long vaddr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t pte;
+
+	__asm__ __volatile__("movl %%cr3, %0" : "=r"(pgd));
+	pgd = __va(pgd);
+	pgd += pgd_index(vaddr);
+	pmd = pmd_offset(pgd, vaddr);
+	if (pmd_none(*pmd))
+		return 0;
+	else if (pmd_large(*pmd))
+		return 1;
+#ifdef CONFIG_HIGHMEM
+	else if ((pmd_val(*pmd) >> PAGE_SHIFT) > page_to_pfn(highmem_start_page))
+		return 0;
+#endif
+	pte = *pte_offset_kernel(pmd, vaddr);
+	if (!pte_present(pte))
+		return 0;
+
+	return 1;
+}
 
 static void doublefault_fn(void)
 {
 	struct Xgt_desc_struct gdt_desc = {0, 0};
-	unsigned long gdt, tss;
+	struct tss_struct *t;
+	struct thread_info *ti;
+	struct task_struct *tsk;
+	unsigned long gdt, tss, *esp;
+	int r = 0;
 
 	__asm__ __volatile__("sgdt %0": "=m" (gdt_desc): :"memory");
 	gdt = gdt_desc.address;
 
 	printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
 
-	if (ptr_ok(gdt)) {
-		gdt += GDT_ENTRY_TSS << 3;
-		tss = *(u16 *)(gdt+2);
-		tss += *(u8 *)(gdt+4) << 16;
-		tss += *(u8 *)(gdt+7) << 24;
-		printk("double fault, tss at %08lx\n", tss);
-
-		if (ptr_ok(tss)) {
-			struct tss_struct *t = (struct tss_struct *)tss;
-
-			printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp);
-
-			printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
-				t->eax, t->ebx, t->ecx, t->edx);
-			printk("esi = %08lx, edi = %08lx\n",
-				t->esi, t->edi);
-		}
-	}
+	if (!ptr_ok(gdt))
+		goto done;
+
+	gdt += GDT_ENTRY_TSS << 3;
+	tss = *(u16 *)(gdt+2);
+	tss += *(u8 *)(gdt+4) << 16;
+	tss += *(u8 *)(gdt+7) << 24;
+	printk("double fault, tss at %08lx\n", tss);
+
+	if (!ptr_ok(tss))
+		goto done;
+
+	t = (struct tss_struct *)tss;
+	printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp);
+	printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
+		t->eax, t->ebx, t->ecx, t->edx);
+	printk("esi = %08lx, edi = %08lx\n",
+		t->esi, t->edi);
+
+	if (!ptr_ok(t->esp))
+		goto done;
+
+	ti = (struct thread_info *)(t->esp & ~(THREAD_SIZE - 1));
+	tsk = ti->task;
+	if (!ptr_ok((unsigned long)tsk))
+		goto done;
+
+	esp = (unsigned long *)t->esp;
+	printk("task: %p (%s) stack:\n", tsk, tsk->comm);
+#if 0
+	show_stack(tsk, esp);
+#else
+	while (ptr_ok((unsigned long)esp) && valid_stack_ptr(ti, esp)) {
+		printk("%08lx ", *esp++);
+		if (!(++r % 8))
+			printk("\n");
+        }
+#endif
 
+done:
 	for (;;) /* nothing */;
 }
 
===== arch/i386/kernel/traps.c 1.91 vs edited =====
--- 1.91/arch/i386/kernel/traps.c	2004-11-23 17:47:27 -07:00
+++ edited/arch/i386/kernel/traps.c	2004-12-20 00:04:38 -07:00
@@ -105,12 +105,6 @@ int register_die_notifier(struct notifie
 	return err;
 }
 
-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
-{
-	return	p > (void *)tinfo &&
-		p < (void *)tinfo + THREAD_SIZE - 3;
-}
-
 static inline unsigned long print_context_stack(struct thread_info *tinfo,
 				unsigned long *stack, unsigned long ebp)
 {
===== include/asm-i386/thread_info.h 1.23 vs edited =====
--- 1.23/include/asm-i386/thread_info.h	2004-11-19 00:03:11 -07:00
+++ edited/include/asm-i386/thread_info.h	2004-12-20 00:09:19 -07:00
@@ -95,6 +95,12 @@ static inline struct thread_info *curren
 /* how to get the current stack pointer from C */
 register unsigned long current_stack_pointer asm("esp") __attribute_used__;
 
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+{
+        return  p > (void *)tinfo &&
+                p < (void *)tinfo + THREAD_SIZE - 3;
+}
+
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
 #define alloc_thread_info(tsk)					\

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Boottime allocated GDTs and doublefault handler
  2004-12-20 15:12     ` Zwane Mwaikambo
@ 2005-01-09  4:55       ` Zwane Mwaikambo
  0 siblings, 0 replies; 5+ messages in thread
From: Zwane Mwaikambo @ 2005-01-09  4:55 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel

On Mon, 20 Dec 2004, Zwane Mwaikambo wrote:

> On Mon, 20 Dec 2004, Zwane Mwaikambo wrote:
> 
> > Ok =), i've added the page table walker and some basic code to fish out 
> > 'current' and dump a few words of its stack. Sorry about the noise in the 
> > patch but the nested if()s were beginning to go too far.

Ok was this patch that offensive? ;) I've been trying to work in the task 
killing code, but it looks like there might be trickery required to switch 
back to the interrupted task.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2005-01-09  4:55 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-12-20  0:48 [PATCH] Boottime allocated GDTs and doublefault handler Zwane Mwaikambo
2004-12-20  2:28 ` Linus Torvalds
2004-12-20  7:21   ` Zwane Mwaikambo
2004-12-20 15:12     ` Zwane Mwaikambo
2005-01-09  4:55       ` Zwane Mwaikambo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).