With A20 it is similar but worse. Really nobody wants it, but it continues to haunt us.
call empty_8042 mov al,#0xd1 ! command write out #0x64,al call empty_8042 mov al,#0xdf ! A20 on out #0x60,al call empty_8042where empty_8042 has to wait for the kbd to finish handling input, say
empty_8042: call delay in al,#0x64 test al,#2 jnz empty_8042 ret
! For the HP Vectra call empty_8042 jnz err mov al,#0xdf out #0x64,al call empty_8042 jnz err mov al,#0xdf ! Do it again out #0x64,al call empty_8042 jnz err ! Success(HIMEM.SYS in DOS 5.0 incorrectly identifies some computers as HP Vectra - this may cause a hang at boot. Fixed in DOS5.0a.)
Thus, MCA, EISA and other systems can also control A20 via port 0x92.
This port has a number of functions, and the details depend on
the manufacturer. Bits 0,1,3,6,7 seem to have the same meaning
everywhere this port is implemented.
Bit 0 (w): writing 1 to this bit causes a
fast reset (used to switch back to real mode; for MCA this took 13.4 ms).
Bit 1 (rw): 0: disable A20, 1: enable A20.
Bit 3 (rw?): 0/1: power-on password bytes (stored in CMOS bytes 0x38-0x3f
or 0x36-0x3f) accessible/inaccessible. This bit can be written to only
when it is 0.
Bits 6-7 (rw): 00: hard disk activity LED off,
01,10,11: hard disk activity LED on.
Bits 2,4,5 are unused or have varying meanings.
(On MCA bit 4 (r): 1: watchdog timeout occurred.)
inb $0x92, %al # orb $02, %al # "fast A20" version outb %al, $0x92 # some chips have only thisfrom setup.S solved this. Apparently on his machine writing to some of these bits is dangerous and does something to the on-board video card (disable it?).
Petr Vandrovec
The i386SL/i486SL documents say
The AMD Elan SC400 docs
(21032.pdf) say:
Register EEh can be used to cause the same type of masking of the CPU
A20 signal that was historically performed by an external SCP (System
Control Processor) in a PC/AT Compatible system, but much faster. This
control defaults to not forcing the propagation of A20:
Dummy Read = Returns FFh, and forces the A20 signal to propagate.
Dummy Write = Deasserts the forcing of the propagation of the A20 signal
via this particular control, data value written is N/A.
For software compatibility and other reasons, there are several sources
of GateA20 control. These controls are effectively ORed together with
the output of the OR gate driving the Enhanced Am486 microprocessor
A20M pin. Therefore, A20 will propagate if ANY of the independent sources
are forcing A20 to propagate.
Neutrino describes the following function x86_enable_a20():
Enable address line A20, which is often disabled on many PCs on reset.
It first checks if address line A20 is enabled and if so returns 0.
Otherwise, it sets bit 0x02 in port 0x92, which is used by many systems
as a fast A20 enable. It again checks to see if A20 is enabled and if so
returns 0. Otherwise, it uses the keyboard microcontroller to enable A20
as defined by the old PC/AT standard. It again checks to see if A20 is
enabled and if so returns 0. Otherwise, it returns -1.
If cpu is a 486 or greater, it issues a wbinvd opcode
to invalidate the cache when doing a read/write test of memory to see
if A20 is enabled.
In the rare case where setting bit 0x02 in port 0x92 may affect
other hardware, you can skip this by setting only_keyboard to 1.
In this case, it will attempt to use only the keyboard microcontroller.
hpa comments: As far as I know the only machines which have the cache
problem are i386 boxen, but the i386 doesn't have WBINVD. The i486
has a pin on the CPU for A20, which takes effect inside the L1 cache,
and so it shouldn't have any A20 cache issues.
inb $0x92, %al #
+ testb $02, %al
+ jnz no92
orb $02, %al # "fast A20" version
outb %al, $0x92 # some chips have only this
+no92:
Since bit 0 sometimes is write-only, and writing a one there
causes a reset, it must be a good idea to add the line
andb $0xfe, %al
before the outb.
FreeBSD
FreeBSD does
/*
* Gate A20 for high memory
*/
void
gateA20(void)
{
#ifdef IBM_L40
outb(0x92, 0x2);
#else IBM_L40
while (inb(K_STATUS) & K_IBUF_FUL);
while (inb(K_STATUS) & K_OBUF_FUL)
(void)inb(K_RDWR);
outb(K_CMD, KC_CMD_WOUT);
while (inb(K_STATUS) & K_IBUF_FUL);
outb(K_RDWR, KB_A20);
while (inb(K_STATUS) & K_IBUF_FUL);
#endif IBM_L40
}
that is, uses 0x92 only for a IBM_L40 (whatever that may be).
Minix and HIMEM.ASM
Here is a patch fragment for minix.
It contains the interesting part
! movb al, #0xff ! Pulse output port
! outb 0x64
! call kb_wait ! Wait for the A20 line to settle down
from some old HIMEM.ASM source (that one still can find on the net).
I have seen no other places where command 0xff is described as
doing something useful.
Access of 0xee
On some systems reading ioport 0xee enables A20, and writing it
disables A20. (Or, sometimes, this action only occurs when ioport
0xee is enabled.) And similar things hold for ioport 0xef and
reset (a write causes a reset).
The following ports are visible only when enabled,
Any writes to these ports cause the action named.
Name of Register Address Default Value Where placed Size
FAST CPU RESET EFh N/A 82360SL 8
FAST A20 GATE EEh N/A 82360SL 8
Other ports
It is rumoured that systems exist that use bit 2 of ioport 0x65
or bit 0 of ioport 0x1f8 for A20 control (0: disabled, 1: enabled).
Don't know what systems that might be.
The AT&T 6300+ needs a write of 0x90 to port 0x3f20 to enable
(and a write of 0x0 to disable) A20.
Disabling A20
It may be necessary to do both the keyboard controller write and
the 0x92 write (and the 0xee write) to disable A20.
A20 and reset
If (in protected mode) A20 is disabled, the odd megabytes are inaccessible.
After a reset, execution begins at top-of-memory:
0xfffff0 on the 286 and 0xfffffff0 on 386 and later.
With disabled A20 this becomes 0xeffff0 or 0xffeffff0
and the machine will probably crash, having no memory mapped there.
A20 and cache
One tests A20 by writing something to an address with bit 0x100000 set,
and seeing whether the corresponding location in low memory changes.
However, this plan may be thwarted by the cache that remembers the
old value and doesn't know about A20.