为什么有时候使能A20需要关闭中断?

Why do we need to disable interrupts when enabling A20 sometimes?

在 OSDev wiki for enabling the A20 line 的一些代码片段中,我们有 cli 中断命令。在其他一些地方我们没有。

例如当通过旧的键盘控制器方法设置 A20 行时,整个代码被 clisti 组合包围。我可以想象这一定会发生,因为我们通过端口使用键盘通信,键盘中断也可能更改端口上的数据。但这是真的吗?我只是猜到了...

enable_A20:
    cli

    call    a20wait
    mov     al,0xAD
    out     0x64,al

    call    a20wait
    mov     al,0xD0
    out     0x64,al

    call    a20wait2
    in      al,0x60
    push    eax

    call    a20wait
    mov     al,0xD1
    out     0x64,al

    call    a20wait
    pop     eax
    or      al,2
    out     0x60,al

    call    a20wait
    mov     al,0xAE
    out     0x64,al

    call    a20wait
    sti
    ret

a20wait:
    in      al,0x64
    test    al,2
    jnz     a20wait
    ret


a20wait2:
    in      al,0x64
    test    al,1
    jz      a20wait2
    ret

然后在测试A20线的代码中(如果它已经激活),中断被禁用,但从未被启用。我想不启用它们是一个错误?在这种情况下,我可以想象我们必须禁用中断,因为中断可能会跳转到我们在这段代码中修改的内存位置,然后一切都会崩溃?

check_a20:
pushf
push ds
push es
push di
push si
cli

xor ax, ax ; ax = 0
mov es, ax

not ax ; ax = 0xFFFF
mov ds, ax

mov di, 0x0500
mov si, 0x0510

mov al, byte [es:di]
push ax

mov al, byte [ds:si]
push ax

mov byte [es:di], 0x00
mov byte [ds:si], 0xFF

cmp byte [es:di], 0xFF

pop ax
mov byte [ds:si], al

pop ax
mov byte [es:di], al

mov ax, 0
je check_a20__exit

mov ax, 1

check_a20__exit:
pop si
pop di
pop es
pop ds
popf

ret

另一方面,快速 A20 门的代码片段不包含任何中断禁用。但我们也与端口通信(读和写)。因此,如果我对键盘控制器的猜测是正确的,那么在我们读取 0x92 端口之后和写回它之前,某些中断是否也会改变它的状态?所以基本上我们会覆盖中断处理程序想要更改的内容。

fast_a20_gate:
in al, 0x92
test al, 2
jnz after
or al, 2
and al, 0xFE
out 0x92, al
after:

是否有任何经验法则可以轻松决定何时必须 cli 中断,何时不需要?目前我完全迷失在这个决定中,只能复制我所看到的。

当您与键盘控制器交谈时,您肯定希望将整个命令作为一个不间断的序列发送给它。所以你必须阻止任何人打扰(!)你。

fast_a20_gate 没有这个问题。它不是一个序列,而只是一个命令——实际上是一个位。如果有人碰巧干扰并翻转了位,您最终还是会设置它。