我阅读了本教程。在教程中,作者介绍了 A20 以及启用它的不同方法。当他写到“快速 A20 方法”时,他说这是通过设置端口 0x92 中的第二位来完成的。这是他给出的示例,其中有一段代码执行此操作:
mov al, 2 ; set bit 2 (enable a20)
out 0x92, al
现在,假设我想取消设置第二位并禁用 A20,我该怎么做?
您正在寻找的指令是
AND
。如果您使用 AND
指令并将除第 2 位之外的所有位设置为 1,则您将有效地将该位设置为 0。
举个例子,
AL = 0101'1010b 0101'1000b
BL = 1111'1101b 1111'1101b
AND AL, BL
AL = 0101'1000b 0101'1000b
或者,如果您想要翻转一位而不管其当前值如何,只需执行
XOR
,将除您想要翻转的一位之外的所有位设置为 0。
AL = 0101'1010b 0101'1000b
BL = 0000'0010b 0000'0010b
XOR AL, BL
AL = 0101'1000b 0101'1010b
此外,为了将来参考,如果您想强制某个位为 1,请使用
OR
指令。
AL = 0101'1000b 0101'1010b
BL = 0000'0010b 0000'0010b
OR AL, BL
AL = 0101'1010b 0101'1010b
顺便说一句,我注意到您正在学习 Brokenthorn 操作系统开发教程。我建议坚持使用教程中解释的键盘控制器方法,因为它适用于更多硬件,并且在许多情况下使用起来更安全。我已经贴在下面了,大家可以看看。
EnableA20:
PUSH AX
CLI
CALL .WaitA
MOV AL, 0xAD ; CMD: Disable PS/2 Port 1
OUT 0x64, AL
CALL .WaitA
MOV AL, 0xD0 ; CMD: Read Controller Output Port
OUT 0x64, AL
CALL .WaitB
IN AL, 0x60 ; READ: Controller Output Port
PUSH AX
CALL .WaitA
MOV AL, 0xD1 ; CMD: Write Controller Output Port
OUT 0x64, AL
CALL .WaitA
POP AX
OR AL, 0x02 ; WRITE: Controller Output Port
OUT 0x60, AL
CALL .WaitA
MOV AL, 0xAE ; CMD: Enable PS/2 Port 1
OUT 0x64, AL
CALL .WaitA
STI
POP AX
RET
.WaitA:
IN AL, 0x64
TEST AL, 0x02 ; Check Input Buffer Status
JNZ .WaitA
RET
.WaitB:
In AL, 0x64
TEST AL, 0x02 ; Check Output Buffer Status
JZ .WaitB
RET
要改为禁用 A20 线,请将注释为
OR
的行上的 WRITE
指令替换为 AND
,并将这些位反转以读取 0xFD。 (要切换位,请使用 XOR
)。
Adrian Collado的贡献中有一点不太清楚。
Brokenthorn 中的示例有一个小错误。 0x92 处有不止一位。将所有其他设置为零可能会导致不必要的副作用。
首先,您应该读取字节,设置该单个位并写回:
in al, 0x92
or al, 0x02
out 0x92, al
重置位非常相似:
in al, 0x92
and al, 0xFD
out 0x92, al