[MBR] Add A20 line

This commit is contained in:
John Stefanelli 2022-09-30 13:41:19 -04:00
parent 1f88f01c33
commit e14c9e8b53
Signed by: jstefanelli
GPG key ID: 60EDE2437640D2AA

View file

@ -93,11 +93,106 @@ print_loop:
RET ; return
; function check_a20: get status of address line 20 (21st bit of any address)
; Returns:
; AX=0 if A20 off, AX=1 if A20 on
check_a20:
PUSHF ; save FLAGS
PUSH DS ; save DS
PUSH ES ; save ES
PUSH DI ; save DI
PUSH SI ; save SI
CLI ; disable interrupts
XOR AX, AX ; AX = 0
MOV ES, AX ; ES = 0
NOT AX ; AX = 0xFFFF
MOV DS, AX ; DS = 0xFFFF
MOV DI, 0x0500 ; DI = 0x0500
MOV SI, 0x0510 ; SI = 0x0510
MOV AL, [ES:DI] ; AL = Memory[0x0500]
PUSH AX ; save original value at Memory[0x500]
MOV AL, [DS:SI] ; AL = Memory[0xFFFF:0x0510]
PUSH AX ; save original value at Memory[0xFFFF:0x0510]
MOV BYTE [ES:DI], 0x00 ; Memory[0x0500] = 0x00
MOV BYTE [DS:SI], 0xFF ; Memory[0xFFFF:0x0510] = 0xFF
CMP BYTE [ES:DI], 0xFF ; Compare Memory[0x0500] to 0xFF
; if the bytes match, the memory is wrapping around
; therefore, the A20 line is disabled
POP AX ; Restore memory at [0xFFFF:0x0510]
MOV [DS:SI], AL ; ^^^^
POP AX ; Restore memory at [0x0500]
MOV [ES:DI], AL ; ^^^^
MOV AX, 0 ; AX (return value) = 0 (A20 disabled)
JE check_a20_exit ; If the last CMP was equal (A20 disabled), exit
MOV AX, 1 ; AX (return value) = 1 (A20 enabled)
check_a20_exit:
POP SI ; restore SI
POP DI ; restore DI
POP ES ; restore ES
POP DS ; restore DS
POPF ; restore FLAGS
RET ; return
enable_a20:
CALL a20_wait ; wait for keyboard controller
MOV AL, 0xAD ; 0xAD = disable keyboard
OUT 0x64, AL ; send command 0xAD to keyboard controller
CALL a20_wait ; wait for keyboard controller
MOV AL, 0xD0 ; 0xD0 = read from input
OUT 0x64, AL ; send command 0xD0
CALL a20_wait2 ; wait for keyboard input
IN AL, 0x60 ; read input from keyboard controller
PUSH AX ; save input
CALL a20_wait ; wait for keybaord controller
MOV AL, 0xD1 ; 0xD1 = write to output
OUT 0x64, AL ; send command 0xD1
CALL a20_wait ; wait for keyboard controller
POP AX ; restore input value
OR AL, 2 ; enable bit 1
OUT 0x60, AL ; send output to keyboard
CALL a20_wait ; wait for keyboard controller
MOV AL, 0xAE ; 0xAE = enable keyboard
OUT 0x64, AL ; send command 0xAE
RET
a20_wait:
IN AL, 0x64 ; read status of keyboard controller
TEST AL, 2 ; read bit 1 of status
JNZ a20_wait ; if not zero, keyboard controller isn't ready. Retry
RET ; return
a20_wait2:
IN AL, 0x64 ; read status of keyboard controller
TEST AL, 1 ; read bit 0 of status
JZ a20_wait2 ; if zero, input isn't ready
RET ; return
entry:
; Set up stack and segments
MOV AX, 0 ; set up stack segment
MOV SS, AX ; ^^^
MOV SP, 0x7C00 ; set up stack pointer (0x6c00-x7BFF)
MOV SP, 0x7C00 ; set up stack pointer (0x6c00-0x7BFF)
; Sp HAS TO be set in the instruction after settings SS
; as setting SS disables interrupts for the next instruction
; Not doing this may cause an interrupt to use an old SP and new SS
@ -106,8 +201,13 @@ entry:
MOV FS, AX ; ^^^
MOV GS, AX ; ^^^
PUSH DX ; save drive number (DL)
; Load drive parameters
MOV AX, 4800h ; load AH=48h, AL=0h
MOV SI, disk_info_packet ; load address of Disk_Info_Packet
INT 13H ; INT 14h AH=48h: get drive parameters
PUSH DX ; save drive number (DL)
; Print message
MOV AX, msg ; load address of msg
@ -116,17 +216,31 @@ entry:
PUSH AX ; push parameter 'size of string'
CALL print ; call function 'print'
over:
JMP over ; loop forever
SUB SP, 4 ; clear previous call parameters
CALL check_a20 ; call check_a20. Result in Ax
CMP AX, 0 ; compare AX to 0 (0 = A20 disabled)
JNE after_a20 ; if AX != 0, a20 is enabled, skip enabling it
CALL enable_a20 ; enable A20 line via keyboard controller
CALL check_a20 ; check status of A20 line (again)
CMP AX, 0 ; compare AX to 0 (0 = A20 disabled)
JNE after_a20 ; if AX != 0, a20 is enabled
MOV AX, a20_msg ; load address of 'a20_msg'
PUSH AX ; push parameter 'address of string'
MOV AX, 6 ; load size of 'a20_msg'
PUSH AX ; push parameter 'size of string'
CALL print ; print 'a20_msg'
JMP endless_loop ; loop endlessly
; Load drive parameters
MOV AX, 4800h ; load AH=48h, AL=0h
MOV SI, disk_info_packet ; load address of Disk_Info_Packet
INT 13H ; INT 14h AH=48h: get drive parameters
after_a20:
endless_loop:
JMP endless_loop ; loop endlessly
section .data
disk_info_packet:
@ -150,4 +264,5 @@ build_settings_magic_0 dd 0x49494949
build_settings_bytes dw 0x0
build_settings_magic_1 dd 0x49494949
msg db "OS3_BOOT_OK!"
msg db "OS3_BOOT_OK!"
a20_msg db "NO_A20"