[patch] Re: [2.1.117] GPF in APM while using WINE

MOLNAR Ingo (mingo@chiara.csoma.elte.hu)
Mon, 24 Aug 1998 15:30:15 +0200 (CEST)


On Mon, 24 Aug 1998, Marcus Meissner wrote:

> [<C0181164>] do_apm_timer

[...]

> [<C0109D20>] ret_from_intr
> [<C0108A0B>] __switch_to+0x73

> Common to all the GPFs is, that I was running programs under WINE at the
> time of the crash. (When not running WINE, the same configuration hums
> along happily for days.)

hm, the problem is that the APM bottom half runs during context switching.
When the bh is executed at a point where we have already switched the LDT,
but have not yet saved the segments, it can cause a crash by
saving/restoring illegal segment registers.

there are several solutions to this problem:

- disable interrupts during switch_to()

- disallow segment manipulation of any kind during interrupts (ie.
changes to APM)

- make the switch_to() code safe wrt segment saves without
disabling IRQs, by zeroing out segment registers. (zeroing
segment registers takes exactly 1 cycle on my PII)

i've implemented this last one [attached], does it fix your crashes? The
best way you can speed up the crash further is to define HZ as 1000 or
10000 in asm/param.h.

is there any other place in the kernel where segment registers might hold
invalid contents?

-- mingo

--- linux/arch/i386/kernel/process.c.orig Mon Aug 24 15:01:52 1998
+++ linux/arch/i386/kernel/process.c Mon Aug 24 15:19:03 1998
@@ -727,10 +727,6 @@
gdt_table[next->tss.tr >> 3].b &= 0xfffffdff;
asm volatile("ltr %0": :"g" (*(unsigned short *)&next->tss.tr));

- /* Re-load LDT if necessary */
- if (next->mm->segments != prev->mm->segments)
- asm volatile("lldt %0": :"g" (*(unsigned short *)&next->tss.ldt));
-
/* Re-load page tables */
if (next->tss.cr3 != prev->tss.cr3)
asm volatile("movl %0,%%cr3": :"r" (next->tss.cr3));
@@ -742,6 +738,17 @@
*/
asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->tss.fs));
asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->tss.gs));
+
+ /* Re-load LDT if necessary */
+ if (next->mm->segments != prev->mm->segments) {
+ /*
+ * careful, we always want to have valid segments.
+ * not only APM but hw-vendor SMM features matter too
+ */
+ asm volatile("movl %0, %%fs"::"r"(0));
+ asm volatile("movl %0, %%gs"::"r"(0));
+ asm volatile("lldt %0": :"g" (*(unsigned short *)&next->tss.ldt));
+ }

loadsegment(fs,next->tss.fs);
loadsegment(gs,next->tss.gs);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html