format elf64 section '.text' executable ; Details on Control Registers and MSRs can be found here: ; https://wiki.osdev.org/CPU_Registers_x86-64 ; x64fastcall void paging_modeswitch_4LevelPaging(void* pml4, int pcid) ; ; This function assumes that the program is now in 64-bit mode (long mode). ; Paging(CR0.PG) in general and long mode (MSR EFER.LME) must already be enabled in this state. ; ; Input: (void* rcx, int rdx) ; Clobbers: rax, flags public paging_modeswitch_4LevelPaging paging_modeswitch_4LevelPaging: ; 4 Level paging: CR0.PG (bit 31) = 1 (Protected mode enable) ; CR4.PAE (bit 05) = 1 (PAE enable) ; MSR IA32_EFER.LME (bit 10) = 1 (IA32e 64-bit mode enable) ; CR4.LA57 (bit 12) = 0 (4-level paging instead of 5) ; We only need to set CR4.LA57 ; Let's also set CR4.PCIDE(bit 17)=1, enabling process-context identifiers mov rax, cr0 and rax, 0xFFFFFFFFFFFFEFFF ; unset CR4.LA57 or rax, 0x20000 ; set CR4.PCIDE mov cr0, rax and rdx, 0xFFF ; take only the 11:0 bits of the PCID or rcx, rdx ; construct the full CR3 mov cr3, rcx ; set CR3, invalidate all TLB cache ret ; x64fastcall void paging_modeswitch_4LevelPagingNX(void* pml4, int pcid) ; ; This function assumes that the program is now in 64-bit mode (long mode). ; Paging(CR0.PG) in general and long mode (MSR EFER.LME) must already be enabled in this state. ; ; This function also sets the IA32_EFER.NXE bit, enabling No-Execute feature. ; ; Input: (void* rcx, int rdx) ; Clobbers: rax, r8, r9, flags public paging_modeswitch_4LevelPagingNX paging_modeswitch_4LevelPagingNX: ; 4 Level paging: CR0.PG (bit 31) = 1 (Protected mode enable) ; CR4.PAE (bit 05) = 1 (PAE enable) ; MSR IA32_EFER.LME (bit 10) = 1 (IA32e 64-bit mode enable) ; CR4.LA57 (bit 12) = 0 (4-level paging instead of 5) ; We only need to set CR4.LA57 ; Let's also set CR4.PCIDE(bit 17)=1, enabling process-context identifiers mov rax, cr0 and rax, 0xFFFFFFFFFFFFEFFF ; unset CR4.LA57 or rax, 0x20000 ; set CR4.PCIDE (bit 17) mov cr0, rax ; save rcx and rdx, RDMSR/WRMSR uses these mov r8, rcx mov r9, rdx mov ecx, 0xC0000080 ; operate on the IA32_EFER MSR rdmsr ; read the MSR into edx:eax or eax, (1 shl 11) ; set No-Execute Enable (bit 11) wrmsr ; write the MSR back ; restore rcx and rdx mov rcx, r8 mov rdx, r9 and rdx, 0xFFF ; take only the 11:0 bits of the PCID or rcx, rdx ; construct the full CR3 mov cr3, rcx ; set CR3, invalidate all TLB cache ret ; x64fastcall void paging_modeswitch_Table(void* pml, int pcid) ; ; This function simply sets CR3 and run INVLPG, flushing the TLB cache. ; ; Input: (void* rcx, int rdx) ; Clobbers: none public paging_modeswitch_Table paging_modeswitch_Table: and rdx, 0xFFF ; take only the 11:0 bits of the PCID or rcx, rdx ; construct the full CR3 mov cr3, rcx ; set CR3, invalidate all TLB cache ret