I've found a nice bit of assembly in xv6 https://github.com/chrisdew/xv6/blob/master/bootasm.S which shows me how to move from 16 bit to 32 bit protected mode.
Does anyone know of a similar example for entering the 64-bit mode? (Either through or without using 32 bit mode.)
In order to enable 64 bit capabillities, you must switch the CPU to Long Mode.
To enter Long Mode on a 64-bit x86 processor (x86-64):
If paging is enabled, disable paging.
If CR4.PAE is not already set, set it.
Set IA32_EFER.LME = 1.
Load CR3 with a valid PML4 table.
Enable paging.
At this point you will be in compatibility mode. A far jump may be executed to switch to long mode. However, the offset must not exceed 32-bit.
If you want to go directly to 64-bit mode, you can do something like this:
%xdefine PML4_BASE 0x70000 ; Address of PML4-table.
%xdefine CR0_PE 1 << 0
%xdefine CR0_PG 1 << 31
%xdefine CR4_PAE 1 << 5
%xdefine CR4_PGE 1 << 7
%xdefine EFER_LME 1 << 8
mov eax, CR4_PAE | CR4_PGE ; Set PAE- (Physical Address Extensions) and
mov cr4, eax ; PGE- (Page Global Enable).
mov eax, PML4_BASE ; Address of PML4.
mov cr3, eax ; Point CR3 to PML4.
mov ecx, 0xC0000080 ; EFER MSR selector.
rdmsr ; Read from model specific register.
or eax, EFER_LME ; Set LME (Long Mode Enable).
wrmsr ; Write to model specific register.
mov ebx, cr0 ; Get CR0.
or ebx, CR0_PG | CR0_PE ; Set PG (Paging) and PE (Protection Enabled).
mov cr0, ebx ; Set flags to CR0.
lgdt [GDT.ptr] ; Load global descriptor table.
jmp GDT.code_0:long_mode_entry ; Jump to long mode.
Above code requires that you have already setup page tables and Global Descriptor Table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With