87 lines
3.0 KiB
ArmAsm
87 lines
3.0 KiB
ArmAsm
|
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
|
||
|
|