Last active
November 9, 2025 01:53
-
-
Save dabsamak/41e7c4a20886201071ac7cf062ff4a6c to your computer and use it in GitHub Desktop.
x86_64 Kernel bootstrap / entry
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ; x86_64 kernel bootstrap, commented | |
| ; int16h @ cryogenix.org | |
| ; ------------------------------------------------------------------------------ | |
| ; --- Assemble in 32-bit mode | |
| [BITS 32] | |
| [GLOBAL start] ; Export the entry symbol for the linker. | |
| GLOBAL long_mode_entry ; 64-bit entry shared by both boot paths. | |
| GLOBAL uefi_entry ; Alias used by the UEFI loader. | |
| extern kmain ; Pull in the C kernel entry point. | |
| extern boot_info_set_multiboot | |
| ; --- multiboot2 header for GRUB | |
| section .multiboot2 | |
| align 8 ; 8-byte alignment | |
| mb2_hdr_start: | |
| dd 0xE85250D6 ; mb2 magic number | |
| dd 0 ; architecture = 0 (i386) | |
| dd mb2_hdr_end - mb2_hdr_start ; total header length | |
| dd -(0xE85250D6 + 0 + (mb2_hdr_end - mb2_hdr_start)) ; checksum | |
| ; required end tag (type 0) | |
| dw 0 ; tag type (=0 end) | |
| dw 0 ; reserved | |
| dd 8 ; tag size (bytes) | |
| mb2_hdr_end: ; end of header | |
| section .text | |
| ; --- 32-bit protected mode start symbol | |
| start: | |
| ; Remember Multiboot2 handoff registers for later. | |
| mov [multiboot_magic], eax | |
| mov [multiboot_info], ebx | |
| ; --- Tiny GDT (32-bit; 64-bit after ljmp) --- | |
| lgdt [gdt_descriptor32] | |
| mov ax, 0x10 | |
| mov ds, ax | |
| mov es, ax | |
| mov ss, ax | |
| mov fs, ax | |
| mov gs, ax | |
| ; --- Enable PAE (CR4.PAE=1) / Physical Address Extension --- | |
| ; Allows access to >4GiB memory by widening physical addresses | |
| ; from 32 to 36+ bits and changing paging structure (PML4/PDPT) | |
| mov eax, cr4 | |
| bts eax, 5 ; PAE | |
| mov cr4, eax | |
| ; --- Load identity-mapped PML4 into CR3 --- | |
| mov eax, pml4 | |
| mov cr3, eax | |
| ; --- Enable LME (IA32_EFER.LME=1) / Long Mode Enable --- | |
| ; Allows the PCU to enter 64-bit / long mode once paging is enabled | |
| mov ecx, 0xC0000080 ; IA32_EFER | |
| rdmsr | |
| bts eax, 8 ; LME | |
| wrmsr | |
| ; --- Enable paging (CR0.PG=1) --- | |
| ; | |
| mov eax, cr0 | |
| bts eax, 31 ; PG | |
| mov cr0, eax | |
| ; --- Far jump to 64-bit code segment --- | |
| jmp 0x08:long_mode_entry | |
| ; --- Assemble in 64-bit / long mode | |
| [BITS 64] | |
| long_mode_entry: | |
| lgdt [rel gdt_descriptor64] | |
| ; Now in long mode with CS=0x08 (64-bit code). Set a stack. | |
| mov ax, 0x10 | |
| mov ds, ax | |
| mov es, ax | |
| mov ss, ax | |
| mov fs, ax | |
| mov gs, ax | |
| mov rsp, 0x0000000000090000 ; Point the temporary stack at 0x90000. | |
| ; Pass Multiboot2 info to common boot_info helpers if GRUB loaded us. | |
| mov eax, dword [rel multiboot_magic] | |
| test eax, eax | |
| jz .no_mb | |
| mov edi, eax | |
| mov esi, dword [rel multiboot_info] | |
| call boot_info_set_multiboot | |
| .no_mb: | |
| call kmain ; hand off to C kernel | |
| .hang: ; halt loop if kmain ever returns | |
| hlt ; halt CPU | |
| jmp .hang ; keep halting! | |
| uefi_entry: | |
| lgdt [rel gdt_descriptor64] | |
| lea rax, [rel long_mode_entry] | |
| push qword 0x08 | |
| push rax | |
| retfq | |
| ; ------------------ Tiny GDT (with a 64-bit code segment) ------------------ | |
| [BITS 32] | |
| align 8 ; 8-byte alignment | |
| gdt: | |
| dq 0x0000000000000000 ; null descriptor (required) | |
| ; 64-bit code descriptor: | |
| ; Bits 0-15: 0x0000 (ignored in long mode) | |
| ; 16-31: 0x0000 (segment base address = 0) | |
| ; 32-39: 0x09A => | |
| ; Bit 7 (0x80) P=1 - segment present | |
| ; Bit 6 (0x40) DPL[1]=0 | |
| ; Bit 5 (0x20) DPL[0]=0 -> Descriptor Priv Level: | |
| ; 00 - ring 0 (highest) | |
| ; 01 - ring 1 | |
| ; 10 - ring 2 | |
| ; 11 - ring 3 (user mode) | |
| ; Bit 4 (0x10) S=1 - code/data segment (not LDT/TSS/etc) | |
| ; Bit 3 (0x08) Type[3]=1 (code segment) | |
| ; Bit 2 (0x04) Type[2]=1 (readable+executable) | |
| ; Bit 1 (0x02) Type[1]=0 (non-conforming CS) | |
| ; Bit 0 (0x01) Type[0]=0 (accessed bit) | |
| ; 40-43: 0x0 (limit high) | |
| ; 44: AVL=0 (available bit not used) | |
| ; 45: L=1 (enable 64-bit long mode semantics for CS) | |
| ; 46: D/B=0 (default operand size - must be 0 for 64-bit mode) | |
| ; 47: G=0 (granularity flag; 0=bytes not 4KiB chunks; ignored in long mode) | |
| ; 48-63: base high+reserved=0, seg remains at 0 | |
| ; | |
| ; Succinctly: L=1, P=1, DPL=0, executable | |
| dq 0x00209A0000000000 | |
| ; 64-bit data segment (not strictly needed for pure code) - legacy/32-bit | |
| ; L=0, D/B=1, P=1, DPL=0 | |
| dq 0x0000920000000000 | |
| ; | |
| gdt_descriptor32: | |
| dw gdt_end - gdt - 1 ; GDT size-1 | |
| dd gdt ; write 32-bit address of GDT | |
| gdt_descriptor64: | |
| dw gdt_end - gdt - 1 | |
| dq gdt | |
| gdt_end: | |
| ; ------------------ Minimal page tables (identity map low 2MB) -------- | |
| ; PML4: Page-Map Level-4 tablt, 4KiB-aligned (top-level in x86_64 paging) | |
| ; Entries store physical base of next paging level (PDPT)+low-bit flags | |
| align 4096 | |
| pml4: dq pdpt + 0x003 ; P/W, present | |
| ; PDPT: Page-Directory-Pointer-Table, 4KiB-aigned (second level) | |
| ; Entries point to a PD (Page-Directory). Normally gates access to | |
| ; large regions, but here it links down to the 2 MB PD. PML4 points here. | |
| align 4096 | |
| pdpt: dq pde + 0x003 | |
| ; PDE: Page-Directory Entry, points to lower-level page table or | |
| ; directly describes a large page (as it does here). | |
| ; | |
| ; Mapped with large pages, ensures code loaded by GRUB remains accessible | |
| ; after paging is enabled | |
| ; | |
| ; 2MB page for 0..2MB: | |
| ; Flags 0x083 => | |
| ; Bit 0 (0x01) PS=1 - present, | |
| ; Bit 1 (0x02) R/W=1 - writable, | |
| ; Bit 7 (0x80) P=1 - page-size flag (map single large (2MiB) page directly). | |
| ; | |
| ; High bits zeroed (address 9), a mapping of the first 2 MiB | |
| align 4096 | |
| pde: dq 0x0000000000000083 | |
| ; --- Boot metadata captured from firmware loaders --- | |
| section .bss | |
| align 8 | |
| multiboot_magic: resq 1 | |
| multiboot_info: resq 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment