Move A20 handler out of bootsector and into stage 2

This commit is contained in:
mintsuki 2020-10-15 11:35:49 +02:00
parent 1d7cc0eeca
commit de0f0da1c6
9 changed files with 114 additions and 235 deletions

View File

@ -1,126 +0,0 @@
a20_check:
; *************************************************
; Checks if the A20 address line is enabled
; *************************************************
; OUT:
; Carry if disabled, cleared if enabled
push ax ; Save registers
push bx
push es
push fs
xor ax, ax ; Set ES segment to zero
mov es, ax
not ax ; Set FS segment to 0xFFFF
mov fs, ax
mov ax, word [es:0x7DFE] ; Check using boot signature
cmp word [fs:0x7E0E], ax ; If A20 is disabled, this should be the
; same address as the boot signature
je .change_values ; If they are equal, check again with another value
.enabled:
clc ; A20 is enabled, clear carry flag
jmp .done
.change_values:
mov word [es:0x7DFE], 0x1234 ; Change the value of 0000:7DFE to 0x1234
cmp word [fs:0x7E0E], 0x1234 ; Is FFFF:7E0E changed as well?
jne .enabled ; If it is, A20 is enabled
stc ; Otherwise set carry
.done:
mov word [es:0x7DFE], ax ; Restore boot signature
pop fs ; Restore registers
pop es
pop bx
pop ax
ret ; Exit routine
enable_a20:
; ********************************************
; Tries to enable the A20 address line
; ********************************************
; OUT:
; Carry cleared if success, set if fail
push eax ; Save registers
call a20_check ; Check if a20 is already enabled
jnc .done ; If it is, we are done
mov ax, 0x2401 ; Use BIOS to try to enable a20
int 0x15
call a20_check ; Check again to see if BIOS succeeded
jnc .done ; If it has, we are done
.keyboard_method:
cli ; Disable interrupts
call .a20wait ; Use the keyboard controller to try and
mov al, 0xAD ; open the A20 gate
out 0x64, al
call .a20wait
mov al, 0xD0
out 0x64, al
call .a20wait2
in al, 0x60
push eax
call .a20wait
mov al, 0xD1
out 0x64, al
call .a20wait
pop eax
or al, 2
out 0x60, al
call .a20wait
mov al, 0xAE
out 0x64, al
call .a20wait
sti ; Enable interrupts back
jmp .keyboard_done
.a20wait:
in al, 0x64
test al, 2
jnz .a20wait
ret
.a20wait2:
in al, 0x64
test al, 1
jz .a20wait2
ret
.keyboard_done:
call a20_check ; Check for success
; Now just quit the routine, forwarding the carry flag to the caller
.done:
pop eax
ret

View File

@ -41,96 +41,38 @@ start:
mov dl, 0x80
.continue:
mov si, LoadingMsg
call simple_print
; ****************** Load stage 1.5 ******************
; Make sure int 13h extensions are supported
mov ah, 0x41
mov bx, 0x55aa
int 0x13
jc err_reading_disk
jc err
cmp bx, 0xaa55
jne err_reading_disk
jne err
; If int 13h extensions are supported, then we are definitely running on
; a 386+. We have no idea whether the upper 16 bits of esp are cleared, so
; make sure that is the case now.
mov esp, 0x7c00
mov eax, dword [stage15_sector]
mov bx, 0x7e00
mov cx, 1
call read_sectors
jc err_reading_disk
jmp 0x7e00
err_reading_disk:
mov si, ErrReadDiskMsg
call simple_print
jmp halt
err_enabling_a20:
mov si, ErrEnableA20Msg
call simple_print
jmp halt
halt:
hlt
jmp halt
; Data
LoadingMsg db 0x0D, 0x0A, 'Limine', 0x0D, 0x0A, 0x0A, 0x00
ErrReadDiskMsg db 0x0D, 0x0A, 'Disk err', 0x00
ErrEnableA20Msg db 0x0D, 0x0A, 'A20 err', 0x00
times 0xda-($-$$) db 0
times 6 db 0
; Includes
%include 'simple_print.inc'
%include 'disk.inc'
times 0x1b0-($-$$) db 0
stage15_sector: dd 1
times 0x1b8-($-$$) db 0
times 510-($-$$) db 0
dw 0xaa55
; ********************* Stage 1.5 *********************
stage15:
push es
push 0x7000
pop es
mov eax, dword [stage15_sector]
inc eax
mov eax, dword [stage2_sector]
xor bx, bx
mov cx, 62
mov cx, 63
call read_sectors
pop es
jc err_reading_disk
call enable_a20
jc err_enabling_a20
jc err
call load_gdt
cli
mov eax, cr0
or al, 1
bts ax, 0
mov cr0, eax
jmp 0x18:.pmode
jmp 0x18:.mode32
bits 32
.pmode:
.mode32:
mov ax, 0x20
mov ds, ax
mov es, ax
@ -142,16 +84,34 @@ stage15:
push edx
push stage2.size
push (stage2 - 0x8000) + 0x70000
push (stage2 - decompressor) + 0x70000
call 0x70000
bits 16
%include 'a20_enabler.inc'
err:
hlt
jmp err
times 0xda-($-$$) db 0
times 6 db 0
; Includes
%include 'disk.inc'
%include 'gdt.inc'
times 1024-($-$$) db 0
times 0x1b0-($-$$) db 0
stage2_sector: dd 1
times 0x1b8-($-$$) db 0
times 510-($-$$) db 0
dw 0xaa55
; ********************* Stage 2 *********************
decompressor:
incbin '../decompressor/decompressor.bin'
align 16

View File

@ -1,22 +0,0 @@
; **************************************
; Prints a string using the BIOS
; **************************************
; IN:
; SI = points to a 0x00 terminated string
simple_print:
push ax
push si
; int 0x10, function 0x0e (print character)
mov ah, 0x0e
.loop:
lodsb
test al, al
jz .done
int 0x10
jmp .loop
.done:
pop si
pop ax
ret

Binary file not shown.

View File

@ -6,6 +6,7 @@
#include <lib/part.h>
#include <lib/config.h>
#include <sys/e820.h>
#include <sys/a20.h>
#include <lib/print.h>
#include <fs/file.h>
#include <lib/elf.h>
@ -24,6 +25,9 @@ void entry(int boot_drive) {
print("Limine " LIMINE_VERSION "\n\n");
if (!a20_enable())
panic("Could not enable A20 line");
print("Boot drive: %x\n", boot_drive);
// Look for config file.

54
stage2/sys/a20.c Normal file
View File

@ -0,0 +1,54 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <sys/a20.h>
#include <sys/cpu.h>
#include <lib/real.h>
bool a20_check(void) {
if (mminw(0x7dfe) != mminw(0x7dfe + 0x100000))
return true;
mmoutw(0x7dfe, ~mminw(0x7dfe));
if (mminw(0x7dfe) != mminw(0x7dfe + 0x100000))
return true;
return false;
}
// Keyboard controller method code below taken from:
// https://wiki.osdev.org/A20_Line
bool a20_enable(void) {
if (a20_check())
return true;
// BIOS method
struct rm_regs r = {0};
r.eax = 0x2401;
rm_int(0x15, &r, &r);
if (a20_check())
return true;
// Keyboard controller method
while (inb(0x64) & 2);
outb(0x64, 0xad);
while (inb(0x64) & 2);
outb(0x64, 0xd0);
while (!(inb(0x64) & 1));
uint8_t b = inb(0x60);
while (inb(0x64) & 2);
outb(0x64, 0xd1);
while (inb(0x64) & 2);
outb(0x60, b | 2);
while (inb(0x64) & 2);
outb(0x64, 0xae);
while (inb(0x64) & 2);
if (a20_check())
return true;
return false;
}

9
stage2/sys/a20.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __SYS__A20_H__
#define __SYS__A20_H__
#include <stdbool.h>
bool a20_check(void);
bool a20_enable(void);
#endif

View File

@ -55,81 +55,81 @@ static inline uint32_t ind(uint16_t port) {
return value;
}
static inline void mmoutb(void *addr, uint8_t value) {
static inline void mmoutb(uintptr_t addr, uint8_t value) {
asm volatile (
"mov %0, %1"
: "=m" (BYTE_PTR(addr))
: "g" (value)
: "ir" (value)
: "memory"
);
}
static inline void mmoutw(void *addr, uint16_t value) {
static inline void mmoutw(uintptr_t addr, uint16_t value) {
asm volatile (
"mov %0, %1"
: "=m" (WORD_PTR(addr))
: "g" (value)
: "ir" (value)
: "memory"
);
}
static inline void mmoutd(void *addr, uint32_t value) {
static inline void mmoutd(uintptr_t addr, uint32_t value) {
asm volatile (
"mov %0, %1"
: "=m" (DWORD_PTR(addr))
: "g" (value)
: "ir" (value)
: "memory"
);
}
static inline void mmoutq(void *addr, uint64_t value) {
static inline void mmoutq(uintptr_t addr, uint64_t value) {
asm volatile (
"mov %0, %1"
: "=m" (QWORD_PTR(addr))
: "g" (value)
: "ir" (value)
: "memory"
);
}
static inline uint8_t mminb(void *addr) {
static inline uint8_t mminb(uintptr_t addr) {
uint8_t ret;
asm volatile (
"mov %0, %1"
: "=r" (ret)
: "g" (BYTE_PTR(addr))
: "m" (BYTE_PTR(addr))
: "memory"
);
return ret;
}
static inline uint16_t mminw(void *addr) {
static inline uint16_t mminw(uintptr_t addr) {
uint16_t ret;
asm volatile (
"mov %0, %1"
: "=r" (ret)
: "g" (WORD_PTR(addr))
: "m" (WORD_PTR(addr))
: "memory"
);
return ret;
}
static inline uint32_t mmind(void *addr) {
static inline uint32_t mmind(uintptr_t addr) {
uint32_t ret;
asm volatile (
"mov %0, %1"
: "=r" (ret)
: "g" (DWORD_PTR(addr))
: "m" (DWORD_PTR(addr))
: "memory"
);
return ret;
}
static inline uint64_t mminq(void *addr) {
static inline uint64_t mminq(uintptr_t addr) {
uint64_t ret;
asm volatile (
"mov %0, %1"
: "=r" (ret)
: "g" (QWORD_PTR(addr))
: "m" (QWORD_PTR(addr))
: "memory"
);
return ret;

View File

@ -16,12 +16,12 @@ struct dmar {
uint32_t lapic_read(uint32_t reg) {
size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
return mmind((void *)(lapic_mmio_base + reg));
return mmind(lapic_mmio_base + reg);
}
void lapic_write(uint32_t reg, uint32_t data) {
size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
mmoutd((void *)(lapic_mmio_base + reg), data);
mmoutd(lapic_mmio_base + reg, data);
}
bool x2apic_check(void) {