Nightloader/i386/loader/src-asm/memory/gdt.asm

207 lines
4.5 KiB
NASM
Executable File

GDT_MEMORY_AREA equ 0x20000
GDT_ENTRIES_CAPACITY equ 8
GDT_ENTRY_SIZE equ 8
db "gdt_set_segment"
; [Furthest from EBP]
; 3. Bool (Lowest Address) Task State Segment (1) or Code/Data (0)
; Bool (Second-Lowest) Executable (1) or Not (0)
; Bool (Second-Highest) Stack (1) or Heap (0) Page
; Bool (Highest Address) Readable AND Writeable (1) or only what's necessary (0)
; 2. U32 Number of pages
; 1. Ptr32 Base address
; 0. U32 Index of Segment (0 is not allowed)
; [Nearest to EBP]
gdt_set_segment:
.prolog:
push dword esi
sub esp, 64
mov esi, esp
mov [esi + (64 - 4)], eax
mov [esi + (64 - 8)], ebx
mov [esi + (64 - 12)], ecx
mov [esi + (64 - 16)], edx
mov [esi + (64 - 20)], edi
.get_work_address:
mov eax, [ebp - 4]
mov edx, GDT_ENTRY_SIZE
mul edx
mov [esi], eax
.prepare_flags_and_access_byte:
; Access Privilege
; [Highest]
; 7. Present Bit (Is in RAM: 1, is swapped out: 0)
; 5+6. Descriptor Privilege Level (Kernel: 00, User; 11)
; 4. Descriptor Type (0: System Segment, 1: Code or Data Segment)
; 3. Is Executable? (Yes: 1, No: 0)
; 2. Grows Up (Heap) / Grows Down (Stack: 0, Heap, 1)
; 1. Secondary Access Bit (whether Read or Write is possible
; even when it isn't strictly necessary for the segment type)
; 0. Dirty Bit (Was Accessed: 1, Still Clean: 0)
; [Lowest]
xor al, al
cmp [ebp - 16], byte 0
je .after_task_segment_bit_setter
or al, (1 << 4)
.after_task_segment_bit_setter:
cmp [ebp - 15], byte 0
je .after_executable_bit_setter
or al, (1 << 3)
.after_executable_bit_setter:
cmp [ebp - 13], byte 0
je .after_direction_bit_setter
or al, (1 << 2)
.after_direction_bit_setter:
cmp [ebp - 12], byte 0
je .after_read_write_bit_setter
or al, (1 << 1)
.after_read_write_bit_setter:
; Flags
; [Highest]
; 3. Address and Size Granularity (Bytes: 0, Pages: 1)
; 2. 16-Bit or 32-Bit selector (0: 16-Bit, 1: 32-Bit)
; 1. Long Mode / 64-Bit (
; 0. Reserved, should be 0
; [Lowest]
mov ah, (0b00001100 << 4)
; OR the uppermost 4 bits of the Limit into the
; appropriate position in the byte of the flags.
mov ecx, [ebp - 12]
shr ecx, 16
and ecx, 0b00001111
or al, cl
; Store the Access Byte and the Flags into the entry.
mov ebx, [esi]
mov [ebx + 5], al ; Access Byte
mov [ebx + 6], ah ; Flags + Limit
mov eax, [ebp - 8]
mov [ebx + 2], ax
shr eax, 16
mov [ebx + 3], al
mov [ebx + 7], ah
mov ax, [ebp - 12]
mov [ebx], ax
.epilog:
mov ebx, [esi + (64 - 8)]
mov ecx, [esi + (64 - 12)]
mov edx, [esi + (64 - 16)]
mov edi, [esi + (64 - 20)]
add esp, 64
pop dword esi
ret
db "load_flat_gdt"
; [Furthest from EBP]
; 0. 4B Return address
; [Nearest to EBP]
load_flat_gdt:
.prolog:
push dword esi
sub esp, 64
mov esi, esp
mov [esi + (64 - 8)], ebx
mov [esi + (64 - 12)], ecx
mov [esi + (64 - 16)], edx
mov [esi + (64 - 20)], edi
mov eax, [ebp - 4]
mov [esi + 20], eax
.create_gdt:
push ebp
mov ebp, esp
push dword (GDT_MEMORY_AREA)
push dword (GDT_ENTRIES_CAPACITY * GDT_ENTRY_SIZE)
push dword 0
call mem_set
mov esp, ebp
pop ebp
; Code Segment
push ebp
mov ebp, esp
push dword 1
push dword 0xa00
push dword 0xfffff
push byte 1
push byte 0
push byte 1
push byte 0
call gdt_set_segment
mov esp, ebp
pop ebp
; Stack Segment
push ebp
mov ebp, esp
push dword 2
push dword 0
push dword 0xfffff
push byte 1
push byte 1
push byte 0
push byte 0
call gdt_set_segment
mov esp, ebp
pop ebp
; Data Segment
push ebp
mov ebp, esp
push dword 3
push dword 0
push dword 0xfffff
push byte 1
push byte 0
push byte 1
push byte 0
call gdt_set_segment
mov esp, ebp
pop ebp
; Write the GDT Descriptor
cli
mov [esi + 10], dword GDT_MEMORY_AREA
mov [esi + 8], word 31
mov eax, esi
add ebx, 8
lgdt [ebx]
sti
mov ax, (3 << 4)
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ax, (2 << 4)
mov ss, ax
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword (1 << 4):.epilog
.epilog:
mov ebx, [esi + (64 - 8)]
mov ecx, [esi + (64 - 12)]
mov edx, [esi + (64 - 16)]
mov edi, [esi + (64 - 20)]
mov esi, [esi + 20]
jmp esi