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 (0) or Code/Data (1) ; 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 - 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 or al, (1 << 7) ; Present-Bit cmp [ebp - 15], byte 0 je .after_task_segment_bit_setter or al, (1 << 4) .after_task_segment_bit_setter: cmp [ebp - 14], 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 ah, 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] ; Base Address 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 0x0a00 push dword 0xfffff push byte 1 push byte 0 push byte 1 push byte 1 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 1 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 1 call gdt_set_segment mov esp, ebp pop ebp ; Write the GDT Descriptor cli lgdt [.gdtr] mov ax, (3 << 3) mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ax, (2 << 3) mov ss, ax jmp dword (1 << 3):.epilog .epilog: mov eax, cr0 or eax, 1 mov cr0, eax 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 align 16 .gdtr: .gdtr.length: dw 31 .gdtr.address: dd GDT_MEMORY_AREA