mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
380 lines
8.1 KiB
NASM
380 lines
8.1 KiB
NASM
|
|
;
|
|
; Parameters
|
|
; X64 - 64 bit target
|
|
; LEGACY_A20 - use slow A20 Gate
|
|
; CHARACTER_TO_SHOW - character to display
|
|
; FORCE_TEXT_MODE - switch to 80x25 mono mode
|
|
;
|
|
|
|
%ifdef LEGACY_A20
|
|
DELAY_PORT: equ 0xed ; Port to use for 1uS delay
|
|
KBD_CONTROL_PORT: equ 0x60 ; 8042 control port
|
|
KBD_STATUS_PORT: equ 0x64 ; 8042 status port
|
|
WRITE_DATA_PORT_CMD: equ 0xd1 ; 8042 command to write the data port
|
|
ENABLE_A20_CMD: equ 0xdf ; 8042 command to enable A20
|
|
%else
|
|
FAST_ENABLE_A20_PORT: equ 0x92
|
|
FAST_ENABLE_A20_MASK: equ 2
|
|
%endif
|
|
BASE_ADR_16: equ 0x0200
|
|
SIZE_TO_STACK_16: equ 0x0fe0 - BASE_ADR_16
|
|
IA32_EFER: equ 0xC0000080
|
|
|
|
%assign GDT_DESC_SIZE 8
|
|
%macro GDT_DESC 2
|
|
dw 0xFFFF, 0
|
|
db 0, %1, %2, 0
|
|
%endmacro
|
|
|
|
%ifdef X64
|
|
%assign IDT_DESC_SIZE 16
|
|
%macro IDT_DESC 0
|
|
dw 0, SYS_CODE64_SEL
|
|
db 0, 0x8e
|
|
dw 0
|
|
dd 0, 0
|
|
%endmacro
|
|
%else
|
|
%assign IDT_DESC_SIZE 8
|
|
%macro IDT_DESC 0
|
|
dw 0, SYS_CODE_SEL
|
|
db 0, 0x8e
|
|
dw 0
|
|
%endmacro
|
|
%endif
|
|
|
|
%ifdef X64
|
|
section .pagezero start=0
|
|
times BASE_ADR_16 db 0
|
|
|
|
%ifndef PAGE_TABLE
|
|
%error "PAGE_TABLE is not defined!"
|
|
%endif
|
|
%endif
|
|
|
|
bits 16
|
|
|
|
section .text start=BASE_ADR_16
|
|
|
|
global _start
|
|
_start:
|
|
jmp .SkipLabel
|
|
%ifdef X64
|
|
db 'DUETX64 ' ; Bootloader Label
|
|
%else
|
|
db 'DUETIA32 ' ; Bootloader Label
|
|
%endif
|
|
.SkipLabel:
|
|
mov ax, cs
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov ss, ax
|
|
mov sp, MyStack
|
|
|
|
;
|
|
; Retrieve Bios Memory Map
|
|
;
|
|
xor ebx, ebx
|
|
lea edi, [MemoryMap]
|
|
.MemMapLoop:
|
|
mov eax, 0xe820
|
|
mov ecx, 20
|
|
mov edx, 0x534d4150 ; SMAP
|
|
int 0x15
|
|
jc .MemMapDone
|
|
add di, 20
|
|
test ebx, ebx
|
|
jnz .MemMapLoop
|
|
.MemMapDone:
|
|
sub di, MemoryMap ; Get the address of the memory map
|
|
mov [MemoryMapSize], edi ; Save the size of the memory map
|
|
|
|
;
|
|
; Rebase Self
|
|
;
|
|
xor ebx, ebx
|
|
mov bx, cs
|
|
shl ebx, 4
|
|
add [gdtr + 2], ebx
|
|
add [idtr + 2], ebx
|
|
add [.JumpTo32BitProtectedMode], ebx
|
|
%ifdef X64
|
|
add [.JumpToLongMode], ebx
|
|
%endif
|
|
|
|
;
|
|
; Enable A20 Gate
|
|
;
|
|
mov ax, 0x2401
|
|
int 0x15
|
|
jnc .A20GateEnabled
|
|
|
|
;
|
|
; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually.
|
|
;
|
|
|
|
%ifdef LEGACY_A20
|
|
;
|
|
; Legacy A20gate
|
|
;
|
|
call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller
|
|
jnz .Timeout8042 ; Jump if the 8042 timed out
|
|
out DELAY_PORT, ax ; Delay 1 uS
|
|
mov al, WRITE_DATA_PORT_CMD ; 8042 cmd to write output port
|
|
out KBD_STATUS_PORT, al ; Send command to the 8042
|
|
call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller
|
|
jnz .Timeout8042 ; Jump if the 8042 timed out
|
|
mov al, ENABLE_A20_CMD ; gate address bit 20 on
|
|
out KBD_CONTROL_PORT,al ; Send command to thre 8042
|
|
call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller
|
|
mov cx, 25 ; Delay 25 uS for the command to complete on the 8042
|
|
.Delay25uS:
|
|
out DELAY_PORT, ax ; Delay 1 uS
|
|
loop .Delay25uS
|
|
.Timeout8042:
|
|
|
|
%else
|
|
;
|
|
; WIKI - fast A20gate
|
|
;
|
|
in al, FAST_ENABLE_A20_PORT
|
|
or al, FAST_ENABLE_A20_MASK
|
|
out FAST_ENABLE_A20_PORT, al
|
|
|
|
%endif
|
|
|
|
.A20GateEnabled:
|
|
|
|
%ifdef FORCE_TEXT_MODE
|
|
;
|
|
; Switch to 80x25 mono text mode (2)
|
|
;
|
|
mov ax, 2
|
|
int 0x10
|
|
%endif
|
|
|
|
%ifdef CHARACTER_TO_SHOW
|
|
|
|
;
|
|
; Display CHARACTER_TO_SHOW
|
|
;
|
|
mov bx, 0x000F
|
|
mov ax, 0x0E00 | (CHARACTER_TO_SHOW & 255)
|
|
int 0x10
|
|
|
|
%endif
|
|
|
|
%ifndef X64
|
|
mov bx, LINEAR_SEL ; Flat data descriptor
|
|
%endif
|
|
|
|
;
|
|
; DISABLE INTERRUPTS - Entering Protected Mode
|
|
;
|
|
cli
|
|
|
|
;
|
|
; load GDT
|
|
;
|
|
lgdt [gdtr]
|
|
|
|
%ifndef X64
|
|
;
|
|
; load IDT
|
|
;
|
|
lidt [idtr]
|
|
%endif
|
|
|
|
;
|
|
; Enable Protected Mode (set CR0.PE=1)
|
|
;
|
|
mov eax, cr0
|
|
or al, 1
|
|
mov cr0, eax
|
|
|
|
.JumpTo32BitProtectedMode: equ $ + 2
|
|
%ifndef X64
|
|
jmp dword LINEAR_CODE_SEL:(BlockSignature + 2)
|
|
%else
|
|
jmp dword LINEAR_CODE_SEL:.In32BitProtectedMode
|
|
.In32BitProtectedMode:
|
|
|
|
bits 32
|
|
;
|
|
; Entering Long Mode
|
|
;
|
|
mov ax, LINEAR_SEL
|
|
mov ds, eax
|
|
mov es, eax
|
|
mov ss, eax
|
|
; WARNING: esp invalid here
|
|
|
|
;
|
|
; Enable the 64-bit page-translation-table entries by
|
|
; setting CR4.PAE=1 (this is _required_ before activating
|
|
; long mode). Paging is not enabled until after long mode
|
|
; is enabled.
|
|
;
|
|
mov eax, cr4
|
|
or al, 0x20
|
|
mov cr4, eax
|
|
|
|
;
|
|
; This is the Trapolean Page Tables that are guarenteed
|
|
; under 4GB.
|
|
;
|
|
; Address Map:
|
|
; 10000 ~ 12000 - efildr (loaded)
|
|
; 20000 ~ 21000 - start64.com
|
|
; 21000 ~ 22000 - efi64.com
|
|
; 22000 ~ 90000 - efildr
|
|
; 90000 ~ 96000 - 4G pagetable (will be reload later)
|
|
;
|
|
mov eax, PAGE_TABLE
|
|
mov cr3, eax
|
|
|
|
;
|
|
; Enable long mode (set EFER.LME=1).
|
|
;
|
|
mov ecx, IA32_EFER
|
|
rdmsr
|
|
or ax, 0x100
|
|
wrmsr
|
|
|
|
;
|
|
; Enable Paging to activate long mode (set CR0.PG=1)
|
|
;
|
|
mov eax, cr0
|
|
bts eax, 31
|
|
mov cr0, eax
|
|
|
|
.JumpToLongMode: equ $ + 1
|
|
jmp SYS_CODE64_SEL:.InLongMode
|
|
.InLongMode:
|
|
|
|
bits 64
|
|
|
|
mov ax, SYS_DATA_SEL
|
|
mov ds, eax
|
|
mov es, eax
|
|
mov ss, eax
|
|
lea rsp, [REL MyStack]
|
|
|
|
;
|
|
; load IDT
|
|
;
|
|
lidt [REL idtr]
|
|
|
|
jmp BlockSignature + 2
|
|
|
|
%endif
|
|
|
|
bits 16
|
|
|
|
%ifdef LEGACY_A20
|
|
Empty8042InputBuffer:
|
|
xor cx, cx
|
|
.Empty8042Loop:
|
|
out DELAY_PORT, ax ; Delay 1us
|
|
in al, KBD_STATUS_PORT ; Read the 8042 Status Port
|
|
and al, 2 ; Check the Input Buffer Full Flag
|
|
loopnz .Empty8042Loop ; Loop until the input buffer is empty or a timout of 65536 uS
|
|
ret
|
|
%endif
|
|
|
|
;
|
|
; Data
|
|
;
|
|
|
|
align 2, db 0
|
|
|
|
gdtr:
|
|
dw GDT_END - GDT_BASE - 1
|
|
dd GDT_BASE
|
|
|
|
;
|
|
; global descriptor table (GDT)
|
|
;
|
|
|
|
align GDT_DESC_SIZE, db 0
|
|
|
|
GDT_BASE:
|
|
NULL_SEL: equ $ - GDT_BASE
|
|
times GDT_DESC_SIZE db 0
|
|
LINEAR_SEL: equ $ - GDT_BASE
|
|
GDT_DESC 0x92, 0xCF
|
|
LINEAR_CODE_SEL: equ $ - GDT_BASE
|
|
GDT_DESC 0x9A, 0xCF
|
|
SYS_DATA_SEL: equ $ - GDT_BASE
|
|
GDT_DESC 0x92, 0xCF
|
|
SYS_CODE_SEL: equ $ - GDT_BASE
|
|
GDT_DESC 0x9A, 0xCF
|
|
times GDT_DESC_SIZE db 0
|
|
%ifdef X64
|
|
SYS_DATA64_SEL: equ $ - GDT_BASE
|
|
GDT_DESC 0x92, 0xCF
|
|
SYS_CODE64_SEL: equ $ - GDT_BASE
|
|
GDT_DESC 0x9A, 0xAF
|
|
%else
|
|
times GDT_DESC_SIZE db 0
|
|
%endif
|
|
times GDT_DESC_SIZE db 0
|
|
GDT_END:
|
|
|
|
align 2, db 0
|
|
|
|
idtr:
|
|
dw IDT_END - IDT_BASE - 1
|
|
dd IDT_BASE
|
|
%ifdef X64
|
|
dd 0
|
|
%endif
|
|
|
|
;
|
|
; interrupt descriptor table (IDT)
|
|
;
|
|
;
|
|
; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
|
|
; mappings. This implementation only uses the system timer and all other
|
|
; IRQs will remain masked.
|
|
;
|
|
|
|
align IDT_DESC_SIZE, db 0
|
|
|
|
IDT_BASE:
|
|
%rep 20 ; Exceptions 0 - 19
|
|
IDT_DESC
|
|
%endrep
|
|
times 84 * IDT_DESC_SIZE db 0
|
|
%rep 16 ; Interrupts IRQ0 - IRQ15 mapped to vectors 0x68 - 0x77
|
|
IDT_DESC
|
|
%endrep
|
|
times IDT_DESC_SIZE db 0 ; padding
|
|
IDT_END:
|
|
|
|
align 4, db 0
|
|
|
|
MemoryMapSize:
|
|
dd 0
|
|
MemoryMap:
|
|
|
|
times SIZE_TO_STACK_16 - $ + $$ db 0
|
|
|
|
MyStack:
|
|
; below is the pieces of the IVT that is used to redirect INT 68h - 6fh
|
|
; back to INT 08h - 0fh when in real mode... It is 'org'ed to a
|
|
; known low address (20f00) so it can be set up by PlMapIrqToVect in
|
|
; 8259.c
|
|
|
|
%assign i 8
|
|
%rep 8
|
|
int i
|
|
iret
|
|
%assign i i+1
|
|
%endrep
|
|
|
|
times 0x1e - $ + MyStack db 0
|
|
BlockSignature:
|
|
dw 0xaa55
|