Blame docs/doc/A20/A20.html

Packit Service 50ad14
<html>
Packit Service 50ad14
<head>
Packit Service 50ad14
<title>A20 - a pain from the past</title>
Packit Service 50ad14
</head>
Packit Service 50ad14
<body>
Packit Service 50ad14

A20 - a pain from the past

Packit Service 50ad14
Packit Service 50ad14
Everybody hates the CapsLock key, but keyboard manufacturers continue
Packit Service 50ad14
producing keyboards with CapsLock - it could be that someone wants it.
Packit Service 50ad14

Packit Service 50ad14
With A20 it is similar but worse. Really nobody wants it, but it
Packit Service 50ad14
continues to haunt us.
Packit Service 50ad14

Packit Service 50ad14

History

Packit Service 50ad14
The 8088 in the original PC had only 20 address lines, good for 1 MB.
Packit Service 50ad14
The maximum address FFFF:FFFF addresses 0x10ffef, and this would silently
Packit Service 50ad14
wrap to 0x0ffef.
Packit Service 50ad14
When the 286 (with 24 address lines) was introduced, it had a real mode
Packit Service 50ad14
that was intended to be 100% compatible with the 8088. However, it failed
Packit Service 50ad14
to do this address truncation (a bug), and people found that there existed
Packit Service 50ad14
programs that actually depended on this truncation.
Packit Service 50ad14
Trying to achieve perfect compatibility, IBM invented a switch
Packit Service 50ad14
to enable/disable the 0x100000 address bit.
Packit Service 50ad14
Since the 8042 keyboard controller happened to have a spare pin,
Packit Service 50ad14
that was used to control the AND gate that disables this address bit.
Packit Service 50ad14
The signal is called A20, and if it is zero, bit 20 of all addresses
Packit Service 50ad14
is cleared.
Packit Service 50ad14
Packit Service 50ad14

Present

Packit Service 50ad14
Why do we have to worry about this nonsense?
Packit Service 50ad14
Because by default the A20 address line is disabled at boot time,
Packit Service 50ad14
so the operating system has to find out how to enable it, and that
Packit Service 50ad14
may be nontrivial since the details depend on the chipset used.
Packit Service 50ad14
Packit Service 50ad14

Classical A20 control, via the keyboard controller

Packit Service 50ad14
The output port of the keyboard controller has a number of functions.
Packit Service 50ad14

Packit Service 50ad14
Bit 0 is used to reset the CPU (go to real mode) - a reset happens
Packit Service 50ad14
when bit 0 is 0.
Packit Service 50ad14

Packit Service 50ad14
Bit 1 is used to control A20 - it is enabled when bit 1 is 1,
Packit Service 50ad14
disabled when bit 1 is 0.
Packit Service 50ad14

Packit Service 50ad14
One sets the output port of the keyboard controller by first writing
Packit Service 50ad14
0xd1 to port 0x64, and the the desired value of the output port
Packit Service 50ad14
to port 0x60. One usually sees the values 0xdd and 0xdf used to
Packit Service 50ad14
disable/enable A20. Thus:
Packit Service 50ad14
Packit Service 50ad14
        call    empty_8042
Packit Service 50ad14
        mov     al,#0xd1                ! command write
Packit Service 50ad14
        out     #0x64,al
Packit Service 50ad14
        call    empty_8042
Packit Service 50ad14
        mov     al,#0xdf                ! A20 on
Packit Service 50ad14
        out     #0x60,al
Packit Service 50ad14
        call    empty_8042
Packit Service 50ad14
Packit Service 50ad14
where <tt>empty_8042</tt> has to wait for the kbd to finish
Packit Service 50ad14
handling input, say
Packit Service 50ad14
Packit Service 50ad14
empty_8042:
Packit Service 50ad14
        call    delay
Packit Service 50ad14
        in      al,#0x64
Packit Service 50ad14
        test    al,#2
Packit Service 50ad14
        jnz     empty_8042
Packit Service 50ad14
        ret
Packit Service 50ad14
Packit Service 50ad14
Packit Service 50ad14

Variation

Packit Service 50ad14
The HP Vectra accepts a shortcut, where writing
Packit Service 50ad14
0xdd or 0xdf to port 0x64 will disable/enable A20.
Packit Service 50ad14
Packit Service 50ad14
! For the HP Vectra
Packit Service 50ad14
        call    empty_8042
Packit Service 50ad14
        jnz     err
Packit Service 50ad14
        mov     al,#0xdf
Packit Service 50ad14
        out     #0x64,al
Packit Service 50ad14
        call    empty_8042
Packit Service 50ad14
        jnz     err
Packit Service 50ad14
        mov     al,#0xdf        ! Do it again
Packit Service 50ad14
        out     #0x64,al
Packit Service 50ad14
        call    empty_8042
Packit Service 50ad14
        jnz     err
Packit Service 50ad14
! Success
Packit Service 50ad14
Packit Service 50ad14
(HIMEM.SYS in DOS 5.0 incorrectly identifies some computers as HP Vectra -
Packit Service 50ad14
this may cause a hang at boot. Fixed in DOS5.0a.)
Packit Service 50ad14
Packit Service 50ad14

A20 control via System Control Port A

Packit Service 50ad14
Some operating systems use the switching off and on of A20 as part
Packit Service 50ad14
of the standard procedure to switch between real (16-bit) and protected
Packit Service 50ad14
mode. Since the keyboard microcontroller is slow, it was desirable to
Packit Service 50ad14
avoid it, and a Fast Gate A20 Option was introduced, where I/O port
Packit Service 50ad14
0x92 (System Control Port A) is used to handle A20, circumventing
Packit Service 50ad14
the keyboard controller.
Packit Service 50ad14

Packit Service 50ad14
Thus, MCA, EISA and other systems can also control A20 via port 0x92.
Packit Service 50ad14
This port has a number of functions, and the details depend on
Packit Service 50ad14
the manufacturer. Bits 0,1,3,6,7 seem to have the same meaning
Packit Service 50ad14
everywhere this port is implemented.
Packit Service 50ad14

Packit Service 50ad14
Bit 0 (w): writing 1 to this bit causes a
Packit Service 50ad14
fast reset (used to switch back to real mode; for MCA this took 13.4 ms).
Packit Service 50ad14

Packit Service 50ad14
Bit 1 (rw): 0: disable A20, 1: enable A20.
Packit Service 50ad14

Packit Service 50ad14
Bit 3 (rw?): 0/1: power-on password bytes (stored in CMOS bytes 0x38-0x3f
Packit Service 50ad14
or 0x36-0x3f) accessible/inaccessible. This bit can be written to only
Packit Service 50ad14
when it is 0.
Packit Service 50ad14

Packit Service 50ad14
Bits 6-7 (rw): 00: hard disk activity LED off,
Packit Service 50ad14
01,10,11: hard disk activity LED on.
Packit Service 50ad14

Packit Service 50ad14
Bits 2,4,5 are unused or have varying meanings.
Packit Service 50ad14
(On MCA bit 4 (r): 1: watchdog timeout occurred.)
Packit Service 50ad14

Packit Service 50ad14

Using 0x92 may be necessary

Packit Service 50ad14
Sometimes (especially on embedded systems, maybe also on some
Packit Service 50ad14
"legacy-free" systems) no keyboard controller is present,
Packit Service 50ad14
and it may be necessary to use 0x92.
Packit Service 50ad14
Often however, the chip will catch accesses to ports 0x64 and 0x60
Packit Service 50ad14
and simulate the expected behaviour, also when no keyboard controller
Packit Service 50ad14
is present. Sometimes, this snooping behaviour must be enabled first.
Packit Service 50ad14
Packit Service 50ad14

Using 0x92 may be dangerous

Packit Service 50ad14
Gianluca Anzolin <g.anzolin@inwind.it> reports:
Packit Service 50ad14
I have an Olivetti M4 (P166) with TRIDENT 9660 video card integrated
Packit Service 50ad14
on the mainboard. Linux boots well, but after LILO has loaded the kernel,
Packit Service 50ad14
the screen becomes black and remains black ever after. Removing
Packit Service 50ad14
Packit Service 50ad14
        inb     $0x92, %al                      #
Packit Service 50ad14
        orb     $02, %al                        # "fast A20" version
Packit Service 50ad14
        outb    %al, $0x92                      # some chips have only this
Packit Service 50ad14
Packit Service 50ad14
from <tt>setup.S</tt> solved this. Apparently on his machine
Packit Service 50ad14
writing to some of these bits is dangerous and does something
Packit Service 50ad14
to the on-board video card (disable it? lspci shows it only when
Packit Service 50ad14
0x92 is not touched).
Packit Service 50ad14
Similar things are reported by others:
Packit Service 50ad14
Packit Service 50ad14
I am trying to install Linux on an old Olivetti pc M4 Modulo P75 but
Packit Service 50ad14
I am quickly stopped. I always got the same display problem very soon
Packit Service 50ad14
during the installation.The display is not updated anymore.
Packit Service 50ad14
The embedded display adapter is a "Trident 9xxx PCI".
Packit Service 50ad14
Packit Service 50ad14
and
Packit Service 50ad14
Packit Service 50ad14
I have a strange problem with an old Olivetti M4 (pentium 75)
Packit Service 50ad14
machine. I buy for a very cheap price 5 of these, but when I
Packit Service 50ad14
boot the machine the screen goes blank. The (embedded on MoBo)
Packit Service 50ad14
video chip is a Trident TGUI9780.
Packit Service 50ad14
Packit Service 50ad14

Packit Service 50ad14
Petr Vandrovec <vandrove@vc.cvut.cz> suggests to do the write
Packit Service 50ad14
only when it is really necessary:
Packit Service 50ad14
Packit Service 50ad14
        inb     $0x92, %al                      #
Packit Service 50ad14
+       testb   $02, %al
Packit Service 50ad14
+       jnz     no92
Packit Service 50ad14
        orb     $02, %al                        # "fast A20" version
Packit Service 50ad14
        outb    %al, $0x92                      # some chips have only this
Packit Service 50ad14
+no92:
Packit Service 50ad14
Packit Service 50ad14
Since bit 0 sometimes is write-only, and writing a one there
Packit Service 50ad14
causes a reset, it must be a good idea to add the line
Packit Service 50ad14
Packit Service 50ad14
        andb    $0xfe, %al
Packit Service 50ad14
Packit Service 50ad14
before the <tt>outb</tt>.
Packit Service 50ad14
Packit Service 50ad14

Using only 0x92 may be dangerous

Packit Service 50ad14
Kai Germaschewski reports that he gets a spontaneous kernel reboot
Packit Service 50ad14
(on a Sony PCG-Z600NE) after suspend/resume when A20 was enabled
Packit Service 50ad14
using 0x92 but not via the keyboard controller. Apparently state
Packit Service 50ad14
set via keyboard controller is correctly saved and restored, but
Packit Service 50ad14
state set via 0x92 is not.
Packit Service 50ad14
Packit Service 50ad14

Port 0x92 may have to be enabled

Packit Service 50ad14
Various SMSC super I/O chips will emulate the keyboard controller,
Packit Service 50ad14
but emulate port 0x92 only when that has been enabled.
Packit Service 50ad14
Packit Service 50ad14

CMOS indicating the presence of a Fast A20 Gate

Packit Service 50ad14
Depending on the BIOS, the possibility of using a fast A20 switch
Packit Service 50ad14
may be visible in the CMOS. For example, some AMI BIOSes have
Packit Service 50ad14
in CMOS location 0x2d a byte with contents
Packit Service 50ad14
Packit Service 50ad14
     System Operational Flags
Packit Service 50ad14
     Bit 7 = 1: Weitek math coprocessor present
Packit Service 50ad14
     Bit 6 = 1: Floppy drive seek at boot disabled
Packit Service 50ad14
     Bit 5 = 1: System boot sequence A:,C: (otherwise C:,A:)
Packit Service 50ad14
     Bit 4 = 1: System boot CPU speed high
Packit Service 50ad14
     Bit 3 = 1: External cache enabled
Packit Service 50ad14
     Bit 2 = 1: Internal cache enabled
Packit Service 50ad14
     Bit 1 = 1: Fast gate A20 operation enabled
Packit Service 50ad14
     Bit 0 = 1: Turbo switch function enabled
Packit Service 50ad14
Packit Service 50ad14
Of course, this does not help at all.
Packit Service 50ad14
Packit Service 50ad14

FreeBSD

Packit Service 50ad14
FreeBSD does
Packit Service 50ad14
Packit Service 50ad14
/*
Packit Service 50ad14
 * Gate A20 for high memory
Packit Service 50ad14
 */
Packit Service 50ad14
void
Packit Service 50ad14
gateA20(void)
Packit Service 50ad14
{
Packit Service 50ad14
#ifdef PC98
Packit Service 50ad14
        outb(0xf2, 0x00);
Packit Service 50ad14
        outb(0xf6, 0x02);
Packit Service 50ad14
#else
Packit Service 50ad14
#ifdef  IBM_L40
Packit Service 50ad14
        outb(0x92, 0x2);
Packit Service 50ad14
#else   IBM_L40
Packit Service 50ad14
        while (inb(K_STATUS) & K_IBUF_FUL);
Packit Service 50ad14
        while (inb(K_STATUS) & K_OBUF_FUL)
Packit Service 50ad14
                (void)inb(K_RDWR);
Packit Service 50ad14
Packit Service 50ad14
        outb(K_CMD, KC_CMD_WOUT);
Packit Service 50ad14
        while (inb(K_STATUS) & K_IBUF_FUL);
Packit Service 50ad14
        outb(K_RDWR, KB_A20);
Packit Service 50ad14
        while (inb(K_STATUS) & K_IBUF_FUL);
Packit Service 50ad14
#endif  IBM_L40
Packit Service 50ad14
#endif
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
that is, uses 0x92 only for a IBM_L40 (whatever that may be).
Packit Service 50ad14
The FreeBSD handbook describes PC98 as
Packit Service 50ad14
"an alternative development branch of PC hardware, popular in Japan"
Packit Service 50ad14
and "the NEC PC98 platform".
Packit Service 50ad14

Packit Service 50ad14
Packit Service 50ad14

Minix and HIMEM.ASM

Packit Service 50ad14
Here is a patch fragment for minix.
Packit Service 50ad14
It contains the interesting part
Packit Service 50ad14
Packit Service 50ad14
!       movb    al, #0xff       ! Pulse output port
Packit Service 50ad14
!       outb    0x64
Packit Service 50ad14
!       call    kb_wait         ! Wait for the A20 line to settle down
Packit Service 50ad14
Packit Service 50ad14
from some old HIMEM.ASM source (that one still can find on the net).
Packit Service 50ad14
I have seen no other places where command 0xff is described as
Packit Service 50ad14
doing something useful.
Packit Service 50ad14
Packit Service 50ad14

Access of 0xee

Packit Service 50ad14
On some systems reading ioport 0xee enables A20, and writing it
Packit Service 50ad14
disables A20. (Or, sometimes, this action only occurs when ioport
Packit Service 50ad14
0xee is enabled.) And similar things hold for ioport 0xef and
Packit Service 50ad14
reset (a write causes a reset).
Packit Service 50ad14

Packit Service 50ad14
The i386SL/i486SL documents say
Packit Service 50ad14
Packit Service 50ad14
The following ports are visible only when enabled,
Packit Service 50ad14
Any writes to these ports cause the action named.
Packit Service 50ad14
Name of Register     Address   Default Value  Where placed    Size
Packit Service 50ad14
FAST CPU RESET         EFh          N/A         82360SL         8
Packit Service 50ad14
FAST A20 GATE          EEh          N/A         82360SL         8  
Packit Service 50ad14
Packit Service 50ad14

Packit Service 50ad14
The AMD Elan SC400 docs
Packit Service 50ad14
(21032.pdf) say:
Packit Service 50ad14
Packit Service 50ad14
Register EEh can be used to cause the same type of masking of the CPU
Packit Service 50ad14
A20 signal that was historically performed by an external SCP (System
Packit Service 50ad14
Control Processor) in a PC/AT Compatible system, but much faster. This
Packit Service 50ad14
control defaults to not forcing the propagation of A20:
Packit Service 50ad14
Dummy Read = Returns FFh, and forces the A20 signal to propagate.
Packit Service 50ad14
Dummy Write = Deasserts the forcing of the propagation of the A20 signal
Packit Service 50ad14
via this particular control, data value written is N/A.
Packit Service 50ad14
For software compatibility and other reasons, there are several sources
Packit Service 50ad14
of GateA20 control. These controls are effectively ORed together with
Packit Service 50ad14
the output of the OR gate driving the Enhanced Am486 microprocessor
Packit Service 50ad14
A20M pin. Therefore, A20 will propagate if ANY of the independent sources
Packit Service 50ad14
are forcing A20 to propagate.
Packit Service 50ad14
Packit Service 50ad14
Packit Service 50ad14

Other ports

Packit Service 50ad14
It is rumoured that systems exist that use bit 2 of ioport 0x65
Packit Service 50ad14
or bit 0 of ioport 0x1f8 for A20 control (0: disabled, 1: enabled).
Packit Service 50ad14
Don't know what systems that might be.
Packit Service 50ad14
The AT&T 6300+ needs a write of 0x90 to port 0x3f20 to enable
Packit Service 50ad14
(and a write of 0x0 to disable) A20.
Packit Service 50ad14
Packit Service 50ad14

Disabling A20

Packit Service 50ad14
It may be necessary to do both the keyboard controller write and
Packit Service 50ad14
the 0x92 write (and the 0xee write) to disable A20.
Packit Service 50ad14
Packit Service 50ad14

A20 and reset

Packit Service 50ad14
If (in protected mode) A20 is disabled, the odd megabytes are inaccessible.
Packit Service 50ad14
After a reset, execution begins at top-of-memory:
Packit Service 50ad14
0xfffff0 on the 286 and 0xfffffff0 on 386 and later.
Packit Service 50ad14
With disabled A20 this becomes 0xeffff0 or 0xffeffff0
Packit Service 50ad14
and the machine will probably crash, having no memory mapped there.
Packit Service 50ad14
Packit Service 50ad14

A20 and cache

Packit Service 50ad14
One tests A20 by writing something to an address with bit 0x100000 set,
Packit Service 50ad14
and seeing whether the corresponding location in low memory changes.
Packit Service 50ad14
However, this plan may be thwarted by the cache that remembers the
Packit Service 50ad14
old value and doesn't know about A20.
Packit Service 50ad14

Packit Service 50ad14
Packit Service 50ad14
Neutrino describes the following function <tt>x86_enable_a20()</tt>:
Packit Service 50ad14
Packit Service 50ad14
Enable address line A20, which is often disabled on many PCs on reset.
Packit Service 50ad14
It first checks if address line A20 is enabled and if so returns 0.
Packit Service 50ad14
Otherwise, it sets bit 0x02 in port 0x92, which is used by many systems
Packit Service 50ad14
as a fast A20 enable. It again checks to see if A20 is enabled and if so
Packit Service 50ad14
returns 0. Otherwise, it uses the keyboard microcontroller to enable A20
Packit Service 50ad14
as defined by the old PC/AT standard. It again checks to see if A20 is
Packit Service 50ad14
enabled and if so returns 0. Otherwise, it returns -1. 
Packit Service 50ad14
If cpu is a 486 or greater, it issues a <tt>wbinvd</tt> opcode
Packit Service 50ad14
to invalidate the cache when doing a read/write test of memory to see
Packit Service 50ad14
if A20 is enabled.
Packit Service 50ad14
In the rare case where setting bit 0x02 in port 0x92 may affect
Packit Service 50ad14
other hardware, you can skip this by setting <tt>only_keyboard</tt> to 1.
Packit Service 50ad14
In this case, it will attempt to use only the keyboard microcontroller.
Packit Service 50ad14
Packit Service 50ad14
hpa comments:
Packit Service 50ad14
Packit Service 50ad14
As far as I know the only machines which have the cache
Packit Service 50ad14
problem are i386 boxen, but the i386 doesn't have WBINVD.  The i486
Packit Service 50ad14
has a pin on the CPU for A20, which takes effect inside the L1 cache,
Packit Service 50ad14
and so it shouldn't have any A20 cache issues.
Packit Service 50ad14
Packit Service 50ad14

Packit Service 50ad14
Jens Maurer
Packit Service 50ad14
reported
Packit Service 50ad14
in 1996 on boot problems with a bzImage kernel:
Packit Service 50ad14
Packit Service 50ad14
On the Toshiba laptop, the first two bytes at 0x100000 are incorrect and
Packit Service 50ad14
identical to those from address 0x000000 (which was an alias for
Packit Service 50ad14
0x100000 before the A20 gate enable). At a second read from 0x100000
Packit Service 50ad14
immediately afterwards, the correct memory content is returned.
Packit Service 50ad14
Asus P55TP5XE boards (Triton I chipset) show quite the same
Packit Service 50ad14
problem, but there, only the first byte is incorrect and booting
Packit Service 50ad14
bzImage kernels works fine.
Packit Service 50ad14
To me, this looks like some buffer or cache coherency problem
Packit Service 50ad14
although I think that caches are organized in at least 16 byte cache lines.
Packit Service 50ad14
...
Packit Service 50ad14
This exact same problem reportedly also exists on Fujitsu 555T
Packit Service 50ad14
(report from Andrea Caltroni) laptop and Compudyne Pentium 60
Packit Service 50ad14
(report from David Kerr) desktop computers.
Packit Service 50ad14
Packit Service 50ad14
He gives a patch, and adds
Packit Service 50ad14
"Unfortunately, Philip Hands reports that the above patch makes some people
Packit Service 50ad14
with other non-laptop computers unable to boot."
Packit Service 50ad14

Packit Service 50ad14
Using zImage instead of bzImage avoids the problem (since zImage
Packit Service 50ad14
is not loaded high).
Packit Service 50ad14
Debian has distributed special Tecra boot floppies for a while.
Packit Service 50ad14
Later it was found out that these laptops just have an incredibly
Packit Service 50ad14
slow keyboard controller and that all is fine with a larger timeout.
Packit Service 50ad14
Packit Service 50ad14

BIOS

Packit Service 50ad14
If it is difficult, maybe impossible, to write a routine that
Packit Service 50ad14
will enable A20 on all PCs, one might ask the BIOS to do so.
Packit Service 50ad14
Many recent BIOS versions implement INT15 AX=240x functions,
Packit Service 50ad14
as follows:
Packit Service 50ad14
Packit Service 50ad14
INT 15 AX=2400 disable A20
Packit Service 50ad14
INT 15 AX=2401 enable A20
Packit Service 50ad14
INT 15 AX=2402 query status A20
Packit Service 50ad14
INT 15 AX=2403 query A20 support (kbd or port 92)
Packit Service 50ad14
Packit Service 50ad14
Return:
Packit Service 50ad14
  If successful: CF clear, AH = 00h
Packit Service 50ad14
  On error: CF set, AH = status
Packit Service 50ad14
  Status: 01h keyboard controller is in secure mode
Packit Service 50ad14
          86h function not supported
Packit Service 50ad14
  For AX=2402 the status (0: disabled, 1: enabled) is returned in AL
Packit Service 50ad14
  For AX=2403 the status (bit 0: kbd, bit 1: port 92) is returned in BX
Packit Service 50ad14
Packit Service 50ad14
Packit Service 50ad14
</body>
Packit Service 50ad14
</html>