linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "H. Peter Anvin" <hpa@zytor.com>
To: linux-kernel@vger.kernel.org
Subject: The latest instance in the A20 farce
Date: 6 Dec 2000 15:55:15 -0800	[thread overview]
Message-ID: <90mjl3$988$1@cesium.transmeta.com> (raw)

Okay, here is yet another A20 patch (against test12-pre6) this time
for people to try out.  This patch uses the following algorithm for
enabling A20:

1. Try the BIOS call.  If it works, we're cool.
2. Try the KBC (using Linus' lowered timeouts.)
3. If the KBC doesn't work, or is very slow, flip port 92.

After 3 it sits into the same infinite loop waiting for A20 to become
enabled (necessary on for example some Toshiba notebooks which have an
extremely slow response to A20.)

The main differences between this patch and test12-pre6:

- Trying the BIOS first of all.  This should reduce the risk of the
  BIOS getting confused while doing a suspend.  This also gives even
  less of an excuse for any nonstandard arrangement -- if you didn't
  implement the standard KBC *and* you didn't provide the BIOS call,
  you have a seriously broken piece of hardware.

- If the KBC responds quickly enough (within about 10000 cycles), we
  don't ever touch the fast A20 gate.  This is a difference from
  previous code, where the fast A20 gate was toggled immediately after
  the KBC, even if the KBC responded instantly.

- I had to move the A20 code somewhat earlier in setup.S in order for
  the BIOS to still be available.

Please try it out and let me know as soon as possible...

	-hpa


--- arch/i386/boot/setup.S.12p6	Wed Dec  6 12:49:07 2000
+++ arch/i386/boot/setup.S	Wed Dec  6 15:25:01 2000
@@ -532,6 +532,70 @@
 	movl	%cs:code32_start, %eax
 	movl	%eax, %cs:code32
 
+# Make sure interrupts really are disabled here...
+	cli
+
+#
+# That was painless, now we enable A20, which definitely isn't.
+#
+# First, we try the BIOS (INT 15:2401).
+# Second, try the keyboard controller with a timeout.
+# Third, try the "fast A20 gate" manually.
+#
+# The "fast A20 gate" is dangerous to use manually, because of
+# system and BIOS bugs -- some manufacturers have used it as an
+# extra GPIO pin(!!!!) and some BIOSes fail to save/restore it
+# on Suspend/Wakeup.
+#
+	movw	$0x2401,%ax			# BIOS: Enable A20
+	stc
+	int	$0x15
+	jc	a20_no_bios			# CF=0 if success
+	testb	%ah,%ah				# AH=0 if success
+	jnz	a20_no_bios
+
+	# BIOS reported success, verify that it really did work
+	call	a20_test
+	jnz	a20_done
+
+a20_no_bios:					# Try the KBC next...
+	call	empty_8042
+
+	movb	$0xD1, %al			# command write
+	outb	%al, $0x64
+	call	empty_8042
+
+	movb	$0xDF, %al			# A20 on
+	outb	%al, $0x60
+	call	empty_8042
+#
+# If A20 is enabled here, don't touch port 92
+#
+	call	a20_test
+	jnz	a20_done
+	
+#
+# Either the KBC is really slow, or we need to use fast A20.  Flip
+# fast A20 and then sit in a loop and spin waiting for A20 to come alive.
+#
+# You must preserve the other bits here. Otherwise embarrasing things
+# like laptops powering off on boot happen. Corrected version by Kira
+# Brown from Linux 2.2
+#
+	inb	$0x92, %al			# System Control Port A
+	orb	$02, %al			# Fast A20 enable
+	outb	%al, $0x92
+
+# Wait until a20 really *is* enabled; it can take a fair amount of
+# time on certain systems; Toshiba Tecras are known to have this
+# problem.
+
+a20_wait:
+	call	a20_test
+	jz	a20_wait
+	
+a20_done:	# A20 verified enabled here
+
 # Now we move the system to its rightful place ... but we check if we have a
 # big-kernel. In that case we *must* not move it ...
 	testb	$LOADED_HIGH, %cs:loadflags
@@ -581,6 +645,7 @@
 # We also then need to move the params behind it (commandline)
 # Because we would overwrite the code on the current IP, we move
 # it in two steps, jumping high after the first one.
+
 	movw	%cs, %ax
 	cmpw	$SETUPSEG, %ax
 	je	end_move_self
@@ -621,6 +686,9 @@
 	movw	%ax, %ds
 	movw	%dx, %ss
 end_move_self:					# now we are at the right place
+
+# Set up IDT/GDT for protected-mode use.
+
 	lidt	idt_48				# load idt with 0,0
 	xorl	%eax, %eax			# Compute gdt_base
 	movw	%ds, %ax			# (Convert %ds:gdt to a linear ptr)
@@ -630,41 +698,6 @@
 	lgdt	gdt_48				# load gdt with whatever is
 						# appropriate
 
-# that was painless, now we enable a20
-	call	empty_8042
-
-	movb	$0xD1, %al			# command write
-	outb	%al, $0x64
-	call	empty_8042
-
-	movb	$0xDF, %al			# A20 on
-	outb	%al, $0x60
-	call	empty_8042
-
-#
-#	You must preserve the other bits here. Otherwise embarrasing things
-#	like laptops powering off on boot happen. Corrected version by Kira
-#	Brown from Linux 2.2
-#
-	inb	$0x92, %al			# 
-	orb	$02, %al			# "fast A20" version
-	outb	%al, $0x92			# some chips have only this
-
-# wait until a20 really *is* enabled; it can take a fair amount of
-# time on certain systems; Toshiba Tecras are known to have this
-# problem.  The memory location used here (0x200) is the int 0x80
-# vector, which should be safe to use.
-
-	xorw	%ax, %ax			# segment 0x0000
-	movw	%ax, %fs
-	decw	%ax				# segment 0xffff (HMA)
-	movw	%ax, %gs
-a20_wait:
-	incw	%ax				# unused memory location <0xfff0
-	movw	%ax, %fs:(0x200)		# we use the "int 0x80" vector
-	cmpw	%gs:(0x210), %ax		# and its corresponding HMA addr
-	je	a20_wait			# loop until no longer aliased
-
 # make sure any possible coprocessor is properly reset..
 	xorw	%ax, %ax
 	outb	%al, $0xf0
@@ -859,6 +892,36 @@
 	popl	%ecx
 	ret
 
+# Wait for the A20 gate to become enabled.  Time out reasonably quickly;
+# return with ZF=0 is A20 now live; ZF=1 if A20 still masked.
+# The test location, memory address 0x200, is the INT 0x80 vector which
+# should be safe to use.
+
+a20_test:
+	pushw	%fs
+	pushw	%gs
+	pushw	%ax
+	pushw	%cx
+	xorw	%ax,%ax				# Low 64K
+	movw	%ax,%fs
+	decw	%ax				# HMA = segment 0xFFFF
+	movw	%ax,%gs
+	movw	%fs:(0x200),%ax
+	pushw	%ax				# Paranoia
+	movw	$0x1000,%cx			# Loop counter
+a20_loop:
+	incw	%ax
+	movw	%ax,%fs:(0x200)
+	cmpw	%ax,%gs:(0x210)			# Aliased?
+	loope	a20_loop			# If so, continue
+	# ZF=0 if no alias, ZF=1 if timeout
+	popw	%fs:(0x200)
+	popw	%cx
+	popw	%ax
+	popw	%gs
+	popw	%fs
+	ret
+	
 # Read the cmos clock. Return the seconds in al
 gettime:
 	pushw	%cx
-- 
<hpa@transmeta.com> at work, <hpa@zytor.com> in private!
"Unix gives you enough rope to shoot yourself in the foot."
http://www.zytor.com/~hpa/puzzle.txt
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

             reply	other threads:[~2000-12-07  0:27 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-12-06 23:55 H. Peter Anvin [this message]
2001-01-10 23:56 The latest instance in the A20 farce Dunlap, Randy
2001-01-11  0:09 ` H. Peter Anvin
2001-01-11 10:32   ` Olaf Titz
2001-01-15 17:24   ` Maciej W. Rozycki
2001-01-15 17:44     ` H. Peter Anvin
2001-01-15 19:30       ` Albert D. Cahalan
2001-01-15 20:00         ` H. Peter Anvin
2001-01-18 12:21           ` Gerhard Mack
2001-01-11  1:43 Dunlap, Randy
2001-01-11  1:59 ` H. Peter Anvin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='90mjl3$988$1@cesium.transmeta.com' \
    --to=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).