You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
2.6 KiB
ArmAsm

[bits 16]
%include "fn.s"
%include "ps2.s"
%macro mov_out 3
mov %1, %3
out %2, %1
%endmacro
; Check whether the A20 line is enabled. Writes to the boot sector identifier.
; Arguments: none
; Return:
; - ax: 0 if A20 disabled, nonzero if A20 enabled
; Clobber: none
test_a20:
push bp
mov bp, sp
push gs
; Restore the boot sector identifier in case it was overwritten by anything.
mov word [0x7dfe], 0xaa55
mov ax, 0xffff
mov gs, ax
xor ax, ax
; If the word at 0x107dfe (1 MiB after the boot sector identifier) is different to the boot
; sector identifier, than A20 must be enabled.
cmp word gs:[0x7e0e], 0xaa55
setne al
jne .return
; Even if A20 was enabled, the two words may have been equal by chance, so we temporarily swap
; the boot sector identifier bytes and test again.
ror word [0x7dfe], 8
cmp word gs:[0x7e0e], 0x55aa
setne al
ror word [0x7dfe], 8
jmp .return
.return:
pop gs
pop bp
ret
global test_a20
; Try to enable A20 using the Intel 8042 PS/2 keyboard controller.
; Arguments: none
; Return: none
; Clobber: ax, cx, dx
enable_a20_intel_8042:
; Temporarily disable the keyboard.
call intel_8042_wait_write
mov_out al, INTEL_8042_OUT_CMD, INTEL_8042_CMD_PS2_1_DISABLE
; Read the controller output port.
call intel_8042_wait_write
mov_out al, INTEL_8042_OUT_CMD, INTEL_8042_CMD_CONTROLLER_OUT_PORT_READ
call intel_8042_wait_read
in al, INTEL_8042_IO_DATA
; The second bit is "A20 enabled", so set it.
mov cl, al
or cl, 2
; Write the modified byte back to the controller output port.
call intel_8042_wait_write
mov_out al, INTEL_8042_OUT_CMD, INTEL_8042_CMD_CONTROLLER_OUT_PORT_WRITE
call intel_8042_wait_write
mov_out al, INTEL_8042_IO_DATA, cl
; Re-enable the keyboard.
call intel_8042_wait_write
mov_out al, INTEL_8042_OUT_CMD, INTEL_8042_CMD_PS2_1_ENABLE
; Wait for writes to finish.
call intel_8042_wait_write
ret
global enable_a20_intel_8042
; Wait for the Intel 8042 input buffer to become empty, so we can write.
; Arguments: none
; Return: none
; Clobber: al
intel_8042_wait_write:
.loop:
; Read the 8042 status register.
in al, INTEL_8042_IN_STATUS
; Input buffer status flag set means the input buffer is full, so loop in this case.
test al, INTEL_8042_STATUS_MASK_IBUF
jnz .loop
ret
; Wait for the Intel 8042 output buffer to become filled, so we can read.
; Arguments: none
; Return: none
; Clobber: al
intel_8042_wait_read:
.loop:
; Read the 8042 status register.
in al, INTEL_8042_IN_STATUS
; Output buffer status flag unset means output buffer is empty, so loop in this case.
test al, INTEL_8042_STATUS_MASK_OBUF
jz .loop
ret