;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Enable_A20: ; Enables A20 gate using:the BIOS, keyboard controller, or Fast A20 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pushad ;Preserve registers pushfd ;Preserve EFLAGS because we might disable interrupts mov ax,0x2402 ;INT 15h AX=2402h: Query A20 status int 0x15 ;Check to see if A20 gate is enabled jc A20_No_BIOS ;Error? Don't use BIOS to enable gate test al,1 ;Test Bit 0 of AL je A20_Enabled ;A20 gate already enabled mov ax,0x2401 ;INT 15h AX=2401h: Enable A20 gate int 0x15 ;Use BIOS to enable A20 gate jc A20_No_BIOS ;Error? Don't use BIOS to enable gate or ah,ah ;Test AH jnz A20_No_BIOS ;Non-zero? A20 gate may not be enabled A20_Enabled: popfd ;Restore EFLAGS popad ;Restore registers ret ;Return A20_No_BIOS: mov ax,0x2403 ;INT 15h AX=2403h: Query A20 support int 0x15 ;Call BIOS to find out how the A20 gate can be enabled jc A20_KBD ;Error? Assume that keyboard controller is the only option test bx,1 ;Bit 0:Keyboard controller supported je A20_KBD ;BIOS indicates that keyboard controller is supported test bx,2 ;Bit 1:Fast A20 supported je FAST_A20 ;BIOS indicated that Fast A20 is supported call Check_A20 ;Test A20 gate manually jc A20_Enabled ;A20 gate already enabled A20_Fail: lea si,[A20_ERROR] ;"Unable to enable A20 gate!" call PrintString call A20_OUT_Wait ;Print string cli ;Disable interrupts hlt ;Halt machine FAST_A20: in al,0x92 ;Read System Control Port A test al,2 ;Test Fast A20 bit jnz A20_Fail ;Bit already set, failed to enable A20 gate or al,2 ;Set Bit 1:Enable Fast A20 and al,0xFE ;Always clear Bit 0 so that machine does not reboot out 0x92,al ;Write to port 92h call Check_A20 ;Check A20 gate jc A20_Enabled ;Success? cli ;No? something must have gone wrong hlt ;Clear interrupts and halt machine A20_KBD: cli ;Disable interrupts mov cx,50 ;Number of attempts to enable gate Use_KBD: call A20_OUT_Wait ;Wait for keyboard mov al,0xAD ;Disable Keyboard out 0x64,al ;Wait for Keyboard mov al,0xD0 ;Read Controller Output Port out 0x64,al call A20_IN_Wait ;Wait for Keyboard in al,0x60 ;Read Data Port push ax ;Save call A20_OUT_Wait ;Wait for Keyboard mov al,0xD1 ;Write Controller Output Port out 0x64,al call A20_OUT_Wait ;Wait for Keyboard pop ax ;Get port data back or al,10b ;Bit 1: Enable A20 gate out 0x60,al ;Write to data port call A20_OUT_Wait ;Wait for Keyboard mov al,0xAE ;Enable Keyboard out 0x64,al call A20_OUT_Wait ;Wait for Keyboard call Check_A20 ;Verify that gate is enabled jc A20_Enabled ;Yes? Return loop Use_KBD ;No? Keep trying jmp A20_Fail ;Could not enable gate after 50 tries A20_OUT_Wait: in al,0x64 ;Read status register test al,10b ;Is port ready? jnz A20_OUT_Wait ;Nope, wait ret ;Yep, continue A20_IN_Wait: in al,0x64 ;Read status register test al,1b ;Is port ready? jz A20_IN_Wait ;Nope, wait ret ;Yep, continue ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Check_A20: ; Test if A20 gate is enabled by comaparing the value in FFFF:7E0E ; with the VBR boot signature at 0000:7DFE ; Out: Carry flag set if A20 gate is enabled ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pushad ;Preserve registers push es mov ax, 0xFFFF mov es, ax ;Extra segment:FFFF cmp WORD [es:0x7DFE + 16], 0xAAFF ;See if boot signature is wrapped at FFFF:7E0E (Meaning FFFF:7E0E = 0:7DFE) stc ; Assume we didn't wrap, yes A20 jne .End clc ; We did wrap, no A20 .End: pop es popad ret A20_ERROR db "Unable to enable A20 gate!",0