在PC及其兼容机的第20根地址线比较特殊,计算机系统中一般安排一个“门”控制该地址线是否有效。为了访问1M以上的存储单元,应该打开A20"门"。这种设置与实模式下只使用低端1M字节存储空间有关,与处理器是否工作在实方式还是保护方式无关,即是关掉A20,也可以进入保护模式。----《80x86汇编语言程序设计》
(一)在实模式下
实模式下的A20与访问高端内存有关(100000H-10FFEFH,传说这是个bug),在8086时,有20根地址线,所以可以访问2^20=1M,但是由于寻址模式是16位地址模式,所以能够表示的地址范围是0-64k,为了访问1M地址,有了分段的模式:16位基地址左移4位+16位偏移=20位地址。
(二)在保护模式下
,从它的名字就可以看出来,其实它就是对于20-bit(从0开始数)的特殊处理(也就是对第21根地址线的处理)。如果A20 Gate被禁止,对于80286来说,其地址为24bit,其地址表示为EFFFFF;对于80386极其随后的32-bit芯片来说,其地址表示为FFEFFFFF。这种表示的意思是如果A20 Gate被禁止,则其第20-bit在CPU做地址访问的时候是无效的,永远只能被作为0;如果A20 Gate被打开,则其第20-bit是有效的,其值既可以是0,又可以是1。
所以,在保护模式下,如果A20 Gate被禁止,则可以访问的内存只能是奇数1M段,即1M,3M,5M…,也就是00000-FFFFF, 200000-2FFFFF,300000-3FFFFF…。如果A20 Gate被打开,则可以访问的内存则是连续的。
(三)A20的开关
(1) 操作 i8042
The output port of the keyboard controller has a number of functions.
Bit 0 is used to reset the CPU (go to real mode) - a reset happens when bit 0 is 0.
Bit 1is used to control A20 - it is enabled when bit 1 is 1, disabled when bit 1 is 0.
这个方法是通过设置8042芯片输出端口的2nd-bit,但是实际上当你向8042输出端口操作时候,可能在键盘缓冲区里还有别的数据需要处理,所以你首先要处理其他数据:
1.禁止中断;
2.等待,直到8042 Input buffer为空为止;
3.发送禁止键盘操作命令到8042 Input buffer;
4.等待,直到8042 Input buffer为空为止;
5.发送读取8042 Output Port命令;
6.等待,直到8042 Output buffer有数据为止;
7.读取8042 Output buffer,并保存得到的字节;
8.等待,直到8042Input buffer为空为止;
9.发送Write 8042 Output Port命令到8042 Input buffer;
10.等待,直到8042Input buffer为空为止;
11.将从8042 Output Port得到的字节的第2位置1(OR 2),然后写入8042 Input buffer;
12.等待,直到8042Input buffer为空为止;
13.发送允许键盘操作命令到8042Input buffer;
14.打开中断。
参考代码:
A20Enable:
cli ;1.关闭中断
call WaitInbufEmpty ;2.等待8042 Input buffer为空;
mov al, 0adh ;向64h端口发送命令ADH(禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。)
mov dx, 64h
out dx, al ;3.发送禁止键盘操作命令
call WaitInbufEmpty ;4.等待8042 Input buffer为空;
mov al, 0d0h
mov dx, 64h
out dx, al ;5.发送读取8042 Output Port命令;
call WaitOutbufFull ;6.等待8042 Output buffer有数据;
mov dx, 60h
in al, dx ;7.读取8042 Output buffer
push ax ;保存读取的数据
call WaitInbufEmpty ;8.等待8042 Input buffer为空;
mov al, 0d1h
mov dx, 64h
out dx, al ;9.发送写 8042 Output Port命令
call WaitInbufEmpty ;10.等待8042 Input buffer为空
pop ax
or al, 02h ;11.将从8042 Output Port得到的字节的bit 1置1
mov dx, 60h
out dx, al ;写入Output Port
call WaitInbufEmpty ;12.等待8042 Input buffer为空
mov al, 0aeh
mov dx, 64h
out dx, al ;13.发送允许键盘操作命令
sti ;开中断
ret
WaitInbufEmpty:
mov dx, 64h
in al, dx ;读取Status Register
test al, 02h ;测试第2bit是否为1,1表示还有数据在缓冲区
jnz WaitInbufEmpty ;zf=0,运算结果非0,即逻辑与为1
ret
WaitOutbufFull:
mov dx, 64h
in al, dx
test al, 01 ;读取Status Register
jz WaitOutbufFull
ret
(2) 操作 System Control Port A,这种最常见。
MCA, EISA and other systems can also control A20 via port 0x92.
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.)
参考代码:
ENABLEA20 PROC
;OPEN A20
PUSH AX
IN AL,92H ;读取A20状态
OR AL,2 ;把第2bit置1
OUT 92H,AL ;把状态结果发送给端口92h
POP AX
RET
ENABLEA20 ENDP
;
DISABLEA20 PROC
;CLOSED A20
PUSH AX
IN AL,92H
AND AL,0FDH ;0FDH=NOT 20H
POP AX
RET
DISABLEA20 ENDP
(3) BIOS INT 0x15 AX : 2400
这个在 CMU 计算机系台柱 Ralf Brown 泰斗的 Interrupt List 里有详细的介绍 —— “INT 15 2400 - SYSTEM - later PS/2s - DISABLE A20 GATE”
参考代码:
入口:ah=24h
al=0 关闭A20
1 打开A20
2 读取A20状态
int 15h
返回:如果BIOS支持此功能,CF=0,否则CF=1
CF=0时,AX返回当前A20状态,1=打开,0=关闭
(4) AMI BIOS (不通用)
Bit 7 = 1: Weitek math coprocessor present
Bit 6 = 1: Floppy drive seek at boot disabled
Bit 5 = 1: System boot sequence A:,C: (otherwise C:,A:)
Bit 4 = 1: System boot CPU speed high
Bit 3 = 1: External cache enabled
Bit 2 = 1: Internal cache enabled
Bit 1= 1: Fastgate A20operation enabled
Bit 0 = 1: Turbo switch function enabled