Move A20 handler out of bootsector and into stage 2
This commit is contained in:
parent
1d7cc0eeca
commit
de0f0da1c6
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
BIN
limine.bin
BIN
limine.bin
Binary file not shown.
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __SYS__A20_H__
|
||||
#define __SYS__A20_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool a20_check(void);
|
||||
bool a20_enable(void);
|
||||
|
||||
#endif
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue