ucore_os_docs/lab1/lab1_appendix_a20.md

6.6 KiB
Raw Permalink Blame History

附录“关于A20 Gate”

【参考“关于A20 Gate” http://hengch.blog.163.com/blog/static/107800672009013104623747/

【参考“百度文库 激活A20地址线详解” http://wenku.baidu.com/view/d6efe68fcc22bcd126ff0c00.html】

Intel早期的8086 CPU提供了20根地址线,可寻址空间范围即0~2^20(00000H~FFFFFH)的 1MB内存空间。但8086的数据处理位宽位16位无法直接寻址1MB内存空间所以8086提供了段地址加偏移地址的地址转换机制。PC机的寻址结构是segment:offsetsegment和offset都是16位的寄存器最大值是0ffffh换算成物理地址的计算方法是把segment左移4位再加上offset所以segment:offset所能表达的寻址空间最大应为0ffff0h + 0ffffh = 10ffefh前面的0ffffh是segment=0ffffh并向左移动4位的结果后面的0ffffh是可能的最大offset这个计算出的10ffefh是多大呢大约是1088KB就是说segment:offset的地址表示能力超过了20位地址线的物理寻址能力。所以当寻址到超过1MB的内存时会发生“回卷”不会发生异常。但下一代的基于Intel 80286 CPU的PC AT计算机系统提供了24根地址线这样CPU的寻址范围变为 2^24=16M,同时也提供了保护模式可以访问到1MB以上的内存了此时如果遇到“寻址超过1MB”的情况系统不会再“回卷”了这就造成了向下不兼容。为了保持完全的向下兼容性IBM决定在PC AT计算机系统上加个硬件逻辑来模仿以上的回绕特征于是出现了A20 Gate。他们的方法就是把A20地址线控制和键盘控制器的一个输出进行AND操作这样来控制A20地址线的打开使能和关闭屏蔽\禁止。一开始时A20地址线控制是被屏蔽的总为0直到系统软件通过一定的IO操作去打开它参看bootasm.S。很显然在实模式下要访问高端内存区这个开关必须打开在保护模式下由于使用32位地址线如果A20恒等于0那么系统只能访问奇数兆的内存即只能访问0--1M、2-3M、4-5M......,这样无法有效访问所有可用内存。所以在保护模式下,这个开关也必须打开。

在保护模式下为了使能所有地址位的寻址能力需要打开A20地址线控制即需要通过向键盘控制器8042发送一个命令来完成。键盘控制器8042将会将它的的某个输出引脚的输出置高电平作为 A20 地址线控制的输入。一旦设置成功之后,内存将不会再被绕回(memory wrapping),这样我们就可以寻址整个 286 的 16M 内存,或者是寻址 80386级别机器的所有 4G 内存了。

键盘控制器8042的逻辑结构图如下所示。从软件的角度来看如何控制8042呢早期的PC机控制键盘有一个单独的单片机8042现如今这个芯片已经给集成到了其它大片子中但其功能和使用方法还是一样当PC机刚刚出现A20 Gate的时候估计为节省硬件设计成本工程师使用这个8042键盘控制器来控制A20 Gate但A20 Gate与键盘管理没有一点关系。下面先从软件的角度简单介绍一下8042这个芯片。

键盘控制器8042的逻辑结构图 图13 键盘控制器8042的逻辑结构图

8042键盘控制器的IO端口是0x600x6f实际上IBM PC/AT使用的只有0x60和0x64两个端口0x61、0x62和0x63用于与XT兼容目的。8042通过这些端口给键盘控制器或键盘发送命令或读取状态。输出端口P2用于特定目的。位0P20引脚用于实现CPU复位操作位1P21引脚用户控制A20信号线的开启与否。系统向输入缓冲端口0x64写入一个字节即发送一个键盘控制器命令。可以带一个参数。参数是通过0x60端口发送的。 命令的返回值也从端口 0x60去读。8042有4个寄存器

  • 1个8-bit长的Input bufferWrite-Only
  • 1个8-bit长的Output buffer Read-Only
  • 1个8-bit长的Status RegisterRead-Only
  • 1个8-bit长的Control RegisterRead/Write。

有两个端口地址60h和64h有关对它们的读写操作描述如下

  • 读60h端口读output buffer
  • 写60h端口写input buffer
  • 读64h端口读Status Register
  • 操作Control Register首先要向64h端口写一个命令20h为读命令60h为写命令然后根据命令从60h端口读出Control Register的数据或者向60h端口写入Control Register的数据64h端口还可以接受许多其它的命令

Status Register的定义要用bit 0和bit 1

bitmeaning
0output register (60h) 中有数据
1input register (60h/64h) 有数据
2系统标志上电复位后被置为0
3data in input register is command (1) or data (0)
41=keyboard enabled, 0=keyboard disabled (via switch)
51=transmit timeout (data transmit not complete)
61=receive timeout (data transmit not complete)
71=even parity rec'd, 0=odd parity rec'd (should be odd)

除了这些资源外8042还有3个内部端口Input Port、Outport Port和Test Port这三个端口的操作都是通过向64h发送命令然后在60h进行读写的方式完成其中本文要操作的A20 Gate被定义在Output Port的bit 1上所以有必要对Outport Port的操作及端口定义做一个说明。

  • 读Output Port向64h发送0d0h命令然后从60h读取Output Port的内容
  • 写Output Port向64h发送0d1h命令然后向60h写入Output Port的数据
  • 禁止键盘操作命令向64h发送0adh
  • 打开键盘操作命令向64h发送0aeh

有了这些命令和知识就可以实现操作A20 Gate来从实模式切换到保护模式了。 理论上讲我们只要操作8042芯片的输出端口64h的bit 1就可以控制A20 Gate但实际上当你准备向8042的输入缓冲区里写数据时可能里面还有其它数据没有处理所以我们要首先禁止键盘操作同时等待数据缓冲区中没有数据以后才能真正地去操作8042打开或者关闭A20 Gate。打开A20 Gate的具体步骤大致如下参考bootasm.S

  1. 等待8042 Input buffer为空
  2. 发送Write 8042 Output Port P2命令到8042 Input buffer
  3. 等待8042 Input buffer为空
  4. 将8042 Output PortP2得到字节的第2位置1然后写入8042 Input buffer