部分转载,不能说明,谅解!
操作系统又实模式进入保护模式之前要打开
A20
地址线。
那么什么是
A20
地址线呢?经过一番查证理解如下:
在
8086
、
8088
中,有
20
跟地址线。所以寻址范围是
2^20 = 1M
,但
8086/8088
是
16
位的地址模式,即只能表示
FFFFH
(
64K
)的范围。为了能访问
1M
的内存采取了分段的模式。
16
位段基址:
16
位偏移。
0XFFFF:0XFFFF
达到了
0X10FFEF
但是
8086/8088
的内存不可能超过
1MB
,所以当时的程序超过
1MB
时会自动回卷。
但是到了
80286
地址线达到
24
跟。而
386
达到
32
根。芯片也达到
32-bit
。寻址能力达到
4GB
。但是为了向后兼容
IBM
采用了一个控制方法。用键盘控制器上的一个剩余的控制线来控制(注意是键盘控制器上的控制线,而不是地址线的第
20
跟)。即
A20
控制线。当
A20
控制线打开时可以使用
20-31
的地址线。而当
A20
关闭时
20-31
的地址线全部为
0.
所以,如果 A20 被禁止,可访问的内存只能是奇数段( 2N+1 ) M ,只有当 A20 被打开的时候才能访问连续的内存。
所以,如果 A20 被禁止,可访问的内存只能是奇数段( 2N+1 ) M ,只有当 A20 被打开的时候才能访问连续的内存。
只有
A20
打开才能进入保护模式。
下面讨论一下如何打开 A20 地址线:
从理论上讲,打开 A20 Gate 的方法是通过设置 8042 芯片输出端口( 64h )的 2nd-bit ,但事实上,当你向 8042 芯片输出端口进行写操作的时候,在键盘缓冲区中,或许还有别的数据尚未处理,因此你必须首先处理这些数据。
所以,激活 A20 地址线的流程为:
1. 关闭 中 断 ;
2. 等待 8042 Input buffer 为 空;
3. 发 送禁止 键盘 操作命令;
4. 等待 8042 Input buffer 为 空;
5. 发 送 读 取 8042 Output Port 命令;
6. 等待 8042 Output buffer 有 数 据;
7. 读 取 8042 Output buffer , 并 保存得到的字 节 ;
8. 等待 8042 Input buffer 为 空;
9. 发 送 Write 8042 Output Port 命令到 8042 Input buffer ;
10. 等待 8042 Input buffer 为 空;
11. 将从 8042 Output Port 得到的字 节 的第 2 位置 1 (或 清 0 ),然后 写 入 8042 Input buffer ;
12. 等待,直到 8042 Input buffer 为 空 为 止;
13. 发 送允 许键盘 操作命令到 8042 Input buffer ;
14. 打 开 中 断 。
下面讨论一下如何打开 A20 地址线:
从理论上讲,打开 A20 Gate 的方法是通过设置 8042 芯片输出端口( 64h )的 2nd-bit ,但事实上,当你向 8042 芯片输出端口进行写操作的时候,在键盘缓冲区中,或许还有别的数据尚未处理,因此你必须首先处理这些数据。
所以,激活 A20 地址线的流程为:
1. 关闭 中 断 ;
2. 等待 8042 Input buffer 为 空;
3. 发 送禁止 键盘 操作命令;
4. 等待 8042 Input buffer 为 空;
5. 发 送 读 取 8042 Output Port 命令;
6. 等待 8042 Output buffer 有 数 据;
7. 读 取 8042 Output buffer , 并 保存得到的字 节 ;
8. 等待 8042 Input buffer 为 空;
9. 发 送 Write 8042 Output Port 命令到 8042 Input buffer ;
10. 等待 8042 Input buffer 为 空;
11. 将从 8042 Output Port 得到的字 节 的第 2 位置 1 (或 清 0 ),然后 写 入 8042 Input buffer ;
12. 等待,直到 8042 Input buffer 为 空 为 止;
13. 发 送允 许键盘 操作命令到 8042 Input buffer ;
14. 打 开 中 断 。
下面是完成打
开
A20 Gate
的代
码
:
A20Enable:
cli ;1. 关闭 中 断
call WaitInbufEmpty ;2. 等待 8042 Input buffer 为 空;
mov al, 0adh
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
cli ;1. 关闭 中 断
call WaitInbufEmpty ;2. 等待 8042 Input buffer 为 空;
mov al, 0adh
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
jnz WaitInbufEmpty
ret
mov dx, 64h
in al, dx ; 读 取 Status Register
test al, 02h
jnz WaitInbufEmpty
ret
WaitOutbufFull:
mov dx, 64h
in al, dx
test al, 01 ; 读 取 Status Register
jz WaitOutbufFull
ret
mov dx, 64h
in al, dx
test al, 01 ; 读 取 Status Register
jz WaitOutbufFull
ret
后来,由于感觉使用
8042
控制
A20
运行太慢了(确实,那么长的代码,中间还要若干次的
wait
),所以后来又出现了所谓的
Fast A20
,实际上,现在的大多数机器都是
Fast A20
,
Fast A20
使用
92h
端口控制
A20
,同时
BIOS
里提供了一个软中断来控制
A20
:
入口:
ah=24h
al=0
关闭
A20
1
打开
A20
2
读取
A20
状态
int 15h
返回:如果
BIOS
支持此功能,
CF=0
,否则
CF=1
CF=0
时,
AX
返回当前
A20
状态,
1=
打开,
0=
关闭
像
8042
中的
Output Port
中的定义一样,
92h
端口的
bit 1
控制着
A20
,为
1
时打开,为
0
时关闭,从
92h
中读一个
byte
可以看
a20
的当前状态,所以对
92h
的操作如下:
读
A20
状态
mov dx, 92h
in al, dx
如果
al
的
bit 1
为
1
表示
a20
打开,否则为
0
打开
A20
mov dx, 92h
mov al, 02
out dx, al
关闭
A20
mov dx, 92h
mov al, 0
out dx, al