Re: Laptops (APM) & 0040 crashes

Stephen.Rothwell@nec.com.au
Mon, 09 Feb 1998 01:06:08 +1100


Hi John,

John Goerzen <jgoerzen@southwind.net> writes:
>
> I really prefer to work in Linux but I'm leaving FreeBSD on there for
> the moment since I have no better option right now. Anyway, it seems
> that FreeBSD is somehow getting around this problem. What I don't
> know is HOW they are getting around it. I am not a kernel hacker so I
> unfortunately won't be much use analyzing their code, but I can try and
> find their APM code and mail it to anybody interested.

OK, I wouldn't want to leave you stranded on FreeBSD :-) Can you try
the following patch for me. It is against 2.0.33. I can only say that
it doesn't stop my APM enabled desktop from running - I don't have a
machine with an APM BIOS with the 0x40 access bug.

> > OK, there is not much work going on with the APM driver for various
> > reasons - the biggy being that APM is now defunct :-( There is a new
>
> Hmm, weird. AFAIK, all current laptops still use APM.

What I should have said is that M$ and Intel have made up another
standard for power management. APM is still used by everyone,
but ACPI(?) is on the horizon.

> > API for doing power management that I know nothing about (yet). Also
> > there have not been any major revisions of teh APM BIOS specifiation anyway.
>
> It seems, though, that some support for certain "buggy" BIOSes might be
> warranted. (Like is present for CMS640, etc.) I much perfer
> my Debian to FreeBSD :-)

Try the patch - we will see if we can help you back into the "real" world.

> > I think the only solution is to complain to IBM and get it fixed.
> > There may already be an updated BIOS available (I don't know).
>
> I have looked at their webpage and they apparently do have a BIOS
> update. Looking at their changelog, they do not say that they have
> dealt with an issue like this, but it is possible that they did and
> just didn't mention it. I will flash the image this afternoon and let
> everyone know how it works.
>
> Even if it works, I would still say that it might be beneficial to
> adopt whatever workaround FreeBSD is using for this bug. From my
> limited understanding of it, it may prove useful for desktop machines
> with APM support as well.

I had a quick look at teh FreeBSD code, but couldn't see any difference.
Maybe they do just what I am trying, but somewhere else.

Cheers,
Stephen

--
Stephen Rothwell                    Stephen.Rothwell@canb.auug.org.au
------------------------------------------------------------------------
diff -ruN linux-2.0.33/arch/i386/kernel/head.S linux.test/arch/i386/kernel/head.S
--- linux-2.0.33/arch/i386/kernel/head.S	Sun Feb  8 12:26:59 1998
+++ linux.test/arch/i386/kernel/head.S	Sun Feb  8 14:07:13 1998
@@ -12,7 +12,6 @@
 #include <linux/tasks.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
-#include <linux/config.h>
 
 #define CL_MAGIC_ADDR	0x90020
 #define CL_MAGIC	0xA33F
@@ -386,11 +385,7 @@
 	ALIGN
 .word 0
 gdt_descr:
-#ifdef CONFIG_APM
-	.word (11+2*NR_TASKS)*8-1
-#else
-	.word (8+2*NR_TASKS)*8-1
-#endif
+	.word (12+2*NR_TASKS)*8-1
 	.long 0xc0000000+SYMBOL_NAME(gdt)
 
 /*
@@ -406,9 +401,8 @@
 	.quad 0x00cbf2000000ffff	/* 0x2b user   3GB data at 0x00000000 */
 	.quad 0x0000000000000000	/* not used */
 	.quad 0x0000000000000000	/* not used */
+	.quad 0x00c0920000000000	/* 0x40 APM set up for bad BIOS's */
+	.quad 0x00c09a0000000000	/* 0x48 APM CS    code */
+	.quad 0x00809a0000000000	/* 0x50 APM CS 16 code (16 bit) */
+	.quad 0x00c0920000000000	/* 0x58 APM DS    data */
 	.fill 2*NR_TASKS,8,0		/* space for LDT's and TSS's etc */
-#ifdef CONFIG_APM
-	.quad 0x00c09a0000000000	/* APM CS    code */
-	.quad 0x00809a0000000000	/* APM CS 16 code (16 bit) */
-	.quad 0x00c0920000000000	/* APM DS    data */
-#endif
diff -ruN linux-2.0.33/drivers/char/apm_bios.c linux.test/drivers/char/apm_bios.c
--- linux-2.0.33/drivers/char/apm_bios.c	Wed May 15 16:06:55 1996
+++ linux.test/drivers/char/apm_bios.c	Sun Feb  8 14:24:32 1998
@@ -26,6 +26,7 @@
  * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
  *    Version 1.0 and 1.1
  * May 1996, Version 1.2
+ * Feb 1998, Version 1.3
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
@@ -40,6 +41,7 @@
  *         is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
  *         <jtoth@princeton.edu>); improve interaction between
  *         screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
+ *    1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
  *
  * Reference:
  *
@@ -160,8 +162,8 @@
 #define APM_NOINTS
 
 /*
- * Define to make the APM BIOS calls zero all data segment registers (do
- * that if an incorrect BIOS implementation will cause a kernel panic if it
+ * Define to make the APM BIOS calls zero all data segment registers (so
+ * that an incorrect BIOS implementation will cause a kernel panic if it
  * tries to write to arbitrary memory).
  */
 #define APM_ZERO_SEGS
@@ -339,7 +341,7 @@
 
 static struct timer_list	apm_timer;
 
-static char			driver_version[] = "1.2";/* no spaces */
+static char			driver_version[] = "1.3";	/* no spaces */
 
 #ifdef APM_DEBUG
 static char *	apm_event_name[] = {
@@ -1107,6 +1109,16 @@
 		printk(" cseg len %x, dseg len %x",
 		       apm_bios_info.cseg_len, apm_bios_info.dseg_len);
 	printk("\n");
+
+	/*
+	 * Set up a segment that references the real mode segment 0x40
+	 * that extends up to the end of page zero (that we have reserved).
+	 * This is for buggy BIOS's that refer to (real mode) segment 0x40
+	 * even though they are called in protected mode.
+	 */
+	set_base(gdt[APM_40 >> 3],
+		 0xc0000000 + ((unsigned long)0x40 << 4));
+	set_limit(gdt[APM_40 >> 3], 4096 - (0x40 << 4));
 
 	apm_bios_entry.offset = apm_bios_info.offset;
 	apm_bios_entry.segment = APM_CS;
diff -ruN linux-2.0.33/include/asm-i386/system.h linux.test/include/asm-i386/system.h
--- linux-2.0.33/include/asm-i386/system.h	Mon Aug 19 22:00:11 1996
+++ linux.test/include/asm-i386/system.h	Sun Feb  8 13:54:28 1998
@@ -11,13 +11,18 @@
  *   3 - kernel data segment
  *   4 - user code segment
  *   5 - user data segment
- * ...
- *   8 - TSS #0
- *   9 - LDT #0
- *  10 - TSS #1
- *  11 - LDT #1
+ *   6 - not used
+ *   7 - not used
+ *   8 - APM BIOS support
+ *   9 - APM BIOS support
+ *  10 - APM BIOS support
+ *  11 - APM BIOS support
+ *  12 - TSS #0
+ *  13 - LDT #0
+ *  14 - TSS #1
+ *  15 - LDT #1
  */
-#define FIRST_TSS_ENTRY 8
+#define FIRST_TSS_ENTRY 12
 #define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
 #define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
 #define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
diff -ruN linux-2.0.33/include/linux/apm_bios.h linux.test/include/linux/apm_bios.h
--- linux-2.0.33/include/linux/apm_bios.h	Sun Feb  8 12:31:21 1998
+++ linux.test/include/linux/apm_bios.h	Sun Feb  8 14:08:19 1998
@@ -22,10 +22,8 @@
 
 #ifdef __KERNEL__
 
-#include <linux/tasks.h>	/* for NR_TASKS */
-#include <linux/sched.h>	/* for _TSS */
-
-#define APM_CS		_TSS(NR_TASKS)
+#define APM_40		0x40
+#define APM_CS		(APM_40 + 8)
 #define APM_CS_16	(APM_CS + 8)
 #define APM_DS		(APM_CS_16 + 8)
 
------------------------------------------------------------------------
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu