A20总线

什么是A20总线

1981年8月,IBM公司最初推出的个人计算机IBM PC使用的CPU是Intel8088。在该微机中地址线只有20根(A0 – A19)。在当时,内存RAM只有几百KB或不到1MB时,20根地址线已足够用来寻址这些内存。

在8086/8088中,有20根地址总线,所以可以访问的地址是2^20=1M,但由于8086/8088是16位地址模式,能够表示的地址范围是0-64K,所以为了在8086/8088下能够访问1M内存,Intel采取了分段的模式:16位段基地址:16位偏移。其绝对地址计算方法为:16位基地址左移4位+16位偏移=20位地址。

通过上述分段模式,能够表示的最大内存为:FFFFh:FFFFh=FFFF0h+FFFFh=10FFEFh=1M+64K-16Bytes(1M多余出来的部分被称做高端内存区HMA)。可是在8086/8088中,当程序给出超过1M(100000H-10FFEFH)的地址时,系统并不认为其访问越界而产生异常,而是自动从重新0开始计算,环绕到0FFEFh,也就是说系统计算实际地址的时候是按照对1M求模的方式进行的,这种技术被称为wrap-around。

1985年,当IBM公司引入AT机时,使用的是Intel 80286 CPU,具有24根地址线(A0-A23),最高可寻址16MB,并且有一个与8088完全兼容的实模式运行方式。然而,在寻址值超过1MB时它却不能象8088那样实现地址寻址的环绕。

但是当时已经有一些程序是利用这种地址环绕机制进行工作的。为了实现完全的兼容性,IBM公司发明了使用一个开关(逻辑门)来开启或禁止100000h地址比特位。由于在当时的8042键盘控制器上恰好有空闲的端口引脚(输出端口P2,引脚P21),于是便使用了该引脚来作为与门控制这个地址比特位。该信号即被称为A20门。如果A20为零,则比特20及以上地址都被清除。从而实现了兼容性。毕竟A20Gate和键盘操作没有任何关系,在许多新型PC上存在着一种通过芯片来直接控制A20 Gate的BIOS功能。从性能上,这种方法比通过键盘控制器来控制A20Gate要稍微高一点。

当A20被禁止时:程序员给出100000H~10FFEFH间的地址,80286和8086/8088 的系统表现是一致的,即按照对1M求模的方式进行寻址,满足系统升级的兼容性问题;

当A20被开启时:程序员给出的100000H~10FFEFH间的地址,80286是访问的真实地址,而8086/8088是始终是按照对1M求模的方式进行的(这里注意,是始终)。

实模式就是, 为了实现系统升级的兼容性,如80286的系统表现(包括80286以后的CPU)要与8086/8088 的系统表现一致,就需要80286 CPU访问100000H-10FFEFH之间的地址的时候, 按照对1M求模的方式进行, 无论A20地址线开启关闭与否, 这种内存访问情况 称为实模式。

保护模式就是, 以A20地址线开启为前提,80286 CPU访问100000H-10FFEFH之间的地址的时候, 是访问真实的内存地址,不是求模访问,如访问100001H,就是真真切切地 访问 0x 100001H,而不是求模的 0x000001H 地址, 这种内存访问情况称为保护模式;

如果A20Gate被禁止:对于80286来说,其地址为24bit,其地址表示为EFFFFF;对于80386极其随后的32-bit芯片来说,其地址表示为FFEFFFFF。这种表示的意思是如果A20Gate被禁止,则其第20-bit在CPU做地址访问的时候是无效的,永远只能被作为0;如果A20 Gate被打开:则其第20-bit是有效的,其值既可以是0,又可以是1。

所以,在保护模式下,如果A20 Gate被打开,则可以访问的内存则是连续的;如果A20Gate被禁止,则可以访问的内存只能是偶数段,因为是20位(从0始)总为零,所23~20位只能是0000、0010、0100、0110、1000、1010、1100、1110对应十六进制为0、2、4、6、8、A、C、E。对应的十六进制地址段是000000-0FFFFF,200000-2FFFFF,400000-4FFFFF…。

A20地址线并不是打开保护模式的关键,只是在保护模式下,不打开A20地址线,你将无法访问到所有的内存。

A20总线启动流程

 1. 禁止中断;

 2. 等待,直到8042 Inputbuffer为空为止;

 3. 发送禁止键盘操作命令到8042Input buffer;

 4. 等待,直到8042 Inputbuffer为空为止;

 5. 发送读取8042 OutputPort命令;

 6. 等待,直到8042 Outputbuffer有数据为止;

 7. 读取8042 Outputbuffer,并保存得到的字节;

 8. 等待,直到8042 Inputbuffer为空为止;

 9. 发送Write 8042Output Port命令到8042 Input buffer;

 10. 等待,直到8042 Inputbuffer为空为止;

 11. 将从8042 OutputPort得到的字节的第2位置1(OR 2),然后写入8042 Input buffer;

 12. 等待,直到8042 Inputbuffer为空为止;

 13. 发送允许键盘操作命令到8042Input buffer;

 14. 打开中断。