.global _start .extern long_mode_start .section .text .code32 /* Entry point. It puts the machine into a consistent state and starts long mode. */ _start: mov $0x80000, %esp // Setup the stack. call boot_check_multiboot call boot_check_cpuid call boot_check_long_mode call boot_setup_page_tables call boot_enable_paging lgdt (boot_gdtdesc) jmpl $0x8, $boot_long_mode_start hlt boot_check_multiboot: cmp $0x36d76289, %eax jne .boot_no_multiboot ret .boot_no_multiboot: mov $'M', %al jmp boot_error boot_check_cpuid: pushfd pop %eax mov %eax, %ecx xor $(1 << 21), %eax push %eax popfd pushfd pop %eax push %ecx popfd cmp %eax, %ecx je .boot_no_cpuid ret .boot_no_cpuid: mov $'C', %al jmp boot_error boot_check_long_mode: mov $0x80000000, %eax cpuid cmp $0x80000001, %eax jb .boot_no_long_mode mov $0x80000001, %eax cpuid test $(1 << 29), %edx jz .boot_no_long_mode ret .boot_no_long_mode: mov $'L', %al jmp boot_error boot_setup_page_tables: mov $page_table_l3, %eax or $0b11 , %eax /* present, writable */ mov %eax, (page_table_l4) mov $page_table_l2, %eax or $0b11, %eax /* present, writable */ mov %eax, (page_table_l3) mov $0, %ecx /* counter */ .boot_pages_loop: mov $0x200000, %eax /* 2MiB */ mul %ecx or $0b10000011, %eax /* present, writable, huge page */ mov %eax, +page_table_l2(,%ecx,8) inc %ecx /* increment counter */ cmp $512, %ecx /* checks if the whole table is mapped */ jne .boot_pages_loop /* if not, continue */ ret boot_enable_paging: /* pass page table location to cpu */ mov $page_table_l4, %eax mov %eax, %cr3 /* enable PAE */ mov %cr4, %eax or $(1 << 5), %eax mov %eax, %cr4 /* enable long mode */ mov $0xC0000080, %ecx rdmsr or $(1 << 8), %eax wrmsr /* enable paging */ mov %cr0, %eax or $(1 << 31), %eax mov %eax, %cr0 ret boot_error: /* print in VGA "ERR: X" where X is the error code */ movl $0x4f524f45, 0xb8000 movl $0x4f3a4f52, 0xb8004 movl $0x4f204f20, 0xb8008 movb %al, 0xb800a hlt .section .bss .align 4096 page_table_l4: .skip 4096 page_table_l3: .skip 4096 page_table_l2: .skip 4096 stack_bottom: .skip 4096 * 4 stack_top: .section .rodata .p2align 2 /* force 4 byte alignment */ boot_gdt64: .quad 0 /* zero entry */ .quad (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) /* code segment */ boot_gdtdesc: .word (boot_gdtdesc - boot_gdt64 - 1) /* sizeof(gdt) - 1 */ .long boot_gdt64 /* address gdt */