From 121e13165b1a5f9e12ef76761cc68722caef5522 Mon Sep 17 00:00:00 2001 From: pantonshire Date: Tue, 15 Oct 2024 10:51:31 +0100 Subject: [PATCH] enable a20 in stage 2 prelude --- boot1/asm/prelude.s | 122 +++++++++++++++++++++++++++++++++++++++++++- justfile | 1 - 2 files changed, 120 insertions(+), 3 deletions(-) diff --git a/boot1/asm/prelude.s b/boot1/asm/prelude.s index 7200f9a..c4388d4 100644 --- a/boot1/asm/prelude.s +++ b/boot1/asm/prelude.s @@ -206,10 +206,128 @@ panic_simple: %endif -; TODO: -; - Make sure A20 is enabled before the switch to protected mode +; Check whether the A20 line is enabled. Writes to the boot sector identifier. +; Arguments: none +; Return: +; - ax: 0 if A20 disabled, nonzero if A20 enabled +; Clobber: none +test_a20: + push bp + mov bp, sp + push gs + + ; Restore the boot sector identifier in case it was overwritten by anything. + mov word [0x7dfe], 0xaa55 + + mov ax, 0xffff + mov gs, ax + xor ax, ax + + ; If the word at 0x107dfe (1 MiB after the boot sector identifier) is different to the boot + ; sector identifier, than A20 must be enabled. + cmp word gs:[0x7e0e], 0xaa55 + setne al + jne .return + + ; Even if A20 was enabled, the two words may have been equal by chance, so we temporarily swap + ; the boot sector identifier bytes and test again. + ror word [0x7dfe], 8 + cmp word gs:[0x7e0e], 0x55aa + setne al + ror word [0x7dfe], 8 + jmp .return + +.return: + pop gs + pop bp + ret + + +; Wait for the Intel 8042 input buffer to become empty, so we can write. +; Arguments: none +; Return: none +; Clobber: al +intel_8042_wait_write: +.loop: + ; Read the 8042 status register. + in al, INTEL_8042_IN_STATUS + ; Input buffer status flag set means the input buffer is full, so loop in this case. + test al, INTEL_8042_STATUS_MASK_IBUF + jnz .loop + ret + + +; Wait for the Intel 8042 output buffer to become filled, so we can read. +; Arguments: none +; Return: none +; Clobber: al +intel_8042_wait_read: +.loop: + ; Read the 8042 status register. + in al, INTEL_8042_IN_STATUS + ; Output buffer status flag unset means output buffer is empty, so loop in this case. + test al, INTEL_8042_STATUS_MASK_OBUF + jz .loop + ret + + +; Try to enable A20 using the Intel 8042 PS/2 keyboard controller. +; Arguments: none +; Return: none +; Clobber: ax, cx, dx +enable_a20_intel_8042: + ; Temporarily disable the keyboard. + call intel_8042_wait_write + mov al, INTEL_8042_CMD_PS2_1_DISABLE + out INTEL_8042_OUT_CMD, al + + ; Read the controller output port. + call intel_8042_wait_write + mov al, INTEL_8042_CMD_CONTROLLER_OUT_PORT_READ + out INTEL_8042_OUT_CMD, al + call intel_8042_wait_read + in al, INTEL_8042_IO_DATA + + ; The second bit is "A20 enabled", so set it. + mov cl, al + or cl, 2 + + ; Write the modified byte back to the controller output port. + call intel_8042_wait_write + mov al, INTEL_8042_CMD_CONTROLLER_OUT_PORT_WRITE + out INTEL_8042_OUT_CMD, al + call intel_8042_wait_write + mov al, cl + out INTEL_8042_IO_DATA, al + + ; Re-enable the keyboard. + call intel_8042_wait_write + mov al, INTEL_8042_CMD_PS2_1_ENABLE + out INTEL_8042_OUT_CMD, al + + ; Wait for writes to finish. + call intel_8042_wait_write + + ret + prelude_main: + call test_a20 + test al, al + jnz .a20_enabled + + ; Try to enable A20 using the Intel 8042 PS/2 keyboard controller. + call enable_a20_intel_8042 + call test_a20 + test al, al + jnz .a20_enabled + + ; TODO: try other methods first before we panic: + ; - [ ] BIOS interrupt + ; - [ ] Fast A20 enable + jmp panic_simple + +.a20_enabled: mov ax, 0x0003 int 0x10 diff --git a/justfile b/justfile index ea5f3f4..48d813e 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,6 @@ run: qemu-system-x86_64 \ -monitor stdio \ - -d int \ -no-reboot \ -bios seabios/out/bios.bin \ -m 512M \