Fix A20 by copying others' implementation

The implementation of the A20 wraparound check was off in some way,
which is why the new implementation was copied from osdev.org, just
using minor modifications to the label naming.
This commit is contained in:
Eric-Paul Ickhorn 2024-08-06 13:25:42 +02:00
parent 5ba30e5f8b
commit 65db388f00
Signed by: epickh
GPG Key ID: 1358818BAA38B104
1 changed files with 37 additions and 84 deletions

View File

@ -1,95 +1,48 @@
; A20 Wraparound check as gotten from osdev.org
check_a20_wraparound:
.prolog:
push dword esi
sub esp, 64
mov esi, esp
pushf
push ds
push es
push di
push si
; EAX is used for the return value,
; so it doesn't have to be preserved.
mov [esi + (64 - 8)], ebx
mov [esi + (64 - 12)], edi
xor ax, ax ; ax = 0
mov es, ax
.test_a20:
; Save the values which are going to be overwritten
mov edi, 0x0800
mov eax, [edi]
mov edi, 0x00100800
mov ebx, [edi]
not ax ; ax = 0xFFFF
mov ds, ax
; Write to two locations which, if A20 wraps around,
; will both be written to by the second statement.
; Write 0 to 0x08000 to avoid the unlikely case that
; those bytes are there coincidentally and A20 is on.
mov edi, 0x0800
mov [edi], dword 0x00000000
mov edi, 0x00100800
mov [edi], dword 0xffaa00dd
mov di, 0x0500
mov si, 0x0510
; Check the lower address (which should NOT contain)
; this value for the value. If it does contain it, the
; memory space wraps around to 0 every 2^19 bytes.
cmp [0x0800], dword 0xffaa00dd
je .return_a20_not_enabled ; If the value at 0x0800
; was written to instead
; (or at the same time) of
; writing to 0x100800,
; the A20 wasn't enabled.
; Reset the values at the addresses to which the test
; values were written znd return that A20 is enabled.
mov edi, 0x0800
mov [edi], eax
mov edi, 0x00100800
mov [edi], ebx
mov al, byte [es:di]
push ax
.return_a20_enabled:
mov al, byte [ds:si]
push ax
mov eax, 1
mov byte [es:di], 0x00
mov byte [ds:si], 0xFF
; Restore the one used register which
; doesn't contain the return value.
mov ebx, [esi + (64 - 8)]
cmp byte [es:di], 0xFF
pop ax
mov byte [ds:si], al
pop ax
mov byte [es:di], al
mov ax, 0
je .exit
mov ax, 1
.exit:
pop si
pop di
pop es
pop ds
popf
add esp, 64
pop dword esi
ret
.return_a20_not_enabled:
; It's only necessary to write to one of the addresses
; as both of them are equal either way.
mov edi, 0x0800
mov [edi], eax
mov eax, 0
; Restore the one used register which
; doesn't contain the return value.
mov ebx, [esi + (64 - 12)]
mov edi, [esi + (64 - 8)]
add esp, 64
pop dword esi
ret
enable_a20_through_keyboard_controller:
.prolog:
push dword esi
sub esp, 64
mov esi, esp
mov [esi + (64 - 8)], ebx
mov [esi + (64 - 12)], ecx
mov [esi + (64 - 16)], edx
mov [esi + (64 - 20)], edi
.epilog:
mov ebx, [esi + (64 - 8)]
mov ecx, [esi + (64 - 12)]
mov edx, [esi + (64 - 16)]
mov edi, [esi + (64 - 20)]
add esp, 64
pop dword esi
ret