;; ;; enableA20.s (adapted from Visopsys OS-loader) ;; ;; Copyright (c) 2000, J. Andrew McLaughlin ;; You're free to use this code in any manner you like, as long as this ;; notice is included (and you give credit where it is due), and as long ;; as you understand and accept that it comes with NO WARRANTY OF ANY KIND. ;; Contact me at jamesamc@yahoo.com about any bugs or problems. ;; enableA20: ;; This subroutine will enable the A20 address line in the keyboard ;; controller. Takes no arguments. Returns 0 in eax on success, ;; -1 on failure. Written for use in 16-bit code, see lines marked ;; with 32-BIT for use in 32-bit code. pusha ;; Make sure interrupts are disabled cli ;; Keep a counter so that we can make up to 5 attempts to turn ;; on A20 if necessary mov cx, 5 .startAttempt1: ;; Wait for the controller to be ready for a command .commandWait1: xor ax, ax in al, 0x64 bt ax, 1 jc .commandWait1 ;; Tell the controller we want to read the current status. ;; Send the command 0xD0: read output port. mov al, 0xD0 out 0x64, al ;; Wait for the controller to be ready with a byte of data .dataWait1: xor ax, ax in al, 0x64 bt ax, 0 jnc .dataWait1 ;; Read the current port status from port 0x60 xor ax, ax in al, 0x60 ;; Save the current value of (E)ax ;; push ax ; 16-BIT push eax ; 32-BIT ;; Wait for the controller to be ready for a command .commandWait2: in al, 0x64 bt ax, 1 jc .commandWait2 ;; Tell the controller we want to write the status byte again mov al, 0D1h out 0x64, al ;; Wait for the controller to be ready for the data .commandWait3: xor ax, ax in al, 0x64 bt ax, 1 jc .commandWait3 ;; Write the new value to port 0x60. Remember we saved the old ;; value on the stack ;;pop ax ; 16-BIT pop eax ; 32-BIT ;; Turn on the A20 enable bit or al, 0b00000010 out 0x60, al ;; Finally, we will attempt to read back the A20 status ;; to ensure it was enabled. ;; Wait for the controller to be ready for a command .commandWait4: xor ax, ax in al, 0x64 bt ax, 1 jc .commandWait4 ;; Send the command 0xD0: read output port. mov al, 0xD0 out 0x64, al ;; Wait for the controller to be ready with a byte of data .dataWait2: xor ax, ax in al, 0x64 bt ax, 0 jnc .dataWait2 ;; Read the current port status from port 0x60 xor ax, ax in al, 0x60 ;; Is A20 enabled? bt ax, 1 ;; Check the result. If carry is on, A20 is on. jc .success ;; Should we retry the operation? If the counter value in Ecx ;; has not reached zero, we will retry loop .startAttempt1 ;; Well, our initial attempt to set A20 has failed. Now we will ;; try a backup method (which is supposedly not supported on many ;; chipsets, but which seems to be the only method that works on ;; other chipsets). ;; Keep a counter so that we can make up to 5 attempts to turn ;; on A20 if necessary mov cx, 5 .startAttempt2: ;; Wait for the keyboard to be ready for another command .commandWait6: xor ax, ax in al, 0x64 bt ax, 1 jc .commandWait6 ;; Tell the controller we want to turn on A20 mov al, 0xDF out 0x64, al ;; Again, we will attempt to read back the A20 status ;; to ensure it was enabled. ;; Wait for the controller to be ready for a command .commandWait7: xor ax, ax in al, 0x64 bt ax, 1 jc .commandWait7 ;; Send the command 0xD0: read output port. mov al, 0xD0 out 0x64, al ;; Wait for the controller to be ready with a byte of data .dataWait3: xor ax, ax in al, 0x64 bt ax, 0 jnc .dataWait3 ;; Read the current port status from port 0x60 xor ax, ax in al, 0x60 ;; Is A20 enabled? bt ax, 1 ;; Check the result. If carry is on, A20 is on, but we might warn ;; that we had to use this alternate method jc .warn ;; Should we retry the operation? If the counter value in Ecx ;; has not reached zero, we will retry loop .startAttempt2 ;; OK, we weren't able to set the A20 address line. Do you want ;; to put an error message here? jmp .fail .warn: ;; Here you may or may not want to print a warning message about ;; the fact that we had to use the nonstandard alternate enabling ;; method .success: ;sti ; Note: When this is uncommented, shit breaks. Probably because the CPU ; throws a fault or a trap without the IDT being loaded, so it triple ; faults and resets. Or maybe not, who knows popa xor eax, eax ret .fail: ; sti popa mov eax, -1 ret