diff --git a/mbr/mbr.asm b/mbr/mbr.asm index 410391e..9f8855e 100644 --- a/mbr/mbr.asm +++ b/mbr/mbr.asm @@ -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!" \ No newline at end of file +msg db "OS3_BOOT_OK!" +a20_msg db "NO_A20" \ No newline at end of file