Entering Long Mode Directly
Posted: Mon Feb 26, 2018 11:43 am
Does anybody have any experience doing this on recent hardware? I was using the following AP trampoline to go from real mode to long mode
It works on Qemu (not like that means much in my experience), VMWare, and VirtualBox. Trying it on one of my laptops that has an i5 3320M and the AP does start and starts executing the real mode portion, but never gets to the 64-Bit portion. The computer doesn't restart though so it isn't triple faulting. If I change the trampoline to switch to protected mode first then long mode the mode switching works on the VMs and hardware.
I'm wondering if anyone else has experienced similar issues? I'm not sure if there is a problem with my code or if switching directly to long mode from real mode no longer works on new hardware. I assume it has to be the former but I don't see anything wrong with my code, and am I wrong assuming that it should either
1. Successfully jump to LongModeTest in long mode or
2. Triple Fault
I haven't gotten a chance to debug it more (I should probably try it with 0 length IDT). Here is LongModeTest:
So long as I switch to protected mode first, it sets the CpuGood flag fine. It can also write to the screen without crashing. On hardware it seems to triple fault as soon as it acquires the lock and jumps to RAX. I haven't tried to debug this at all yet, but can confirm that it works on VMWare and VirtualBox just fine. There are some other differences between the hardware VMs in regards to that issue though, but they don't affect the mode switching code.
Is there something wrong with my trampoline (other than not trying to mask NMIs) that would be causing this? Has anyone else had similar problems on hardware? Im trying to figure out if its possible that some pieces of hardware will not go from Real mode to Long mode directly, but this doesn't seem possible.
Code: Select all
Trampoline_Start:
cli
xor ax, ax
mov ds, ax
mov ebx, [HeapStart]
; Set CR3 to PML4
mov eax, [ebx+BasicInfo.PageTable]
mov cr3, eax
; Enable PAE and PSE
mov eax, cr4
or eax, 0x30
mov cr4, eax
; Enable Long mode
mov ecx, 0xC0000080
rdmsr
or eax, 0x00000100
wrmsr
; Enable Paging and Protection at same time
mov eax, cr0
or eax, 0x80000001
mov cr0, eax
lgdt [GDT_PTR_Long]
jmp 0x8:LongModeTest
Trampoline_End:
Code: Select all
Trampoline_Start:
cli
lgdt [GDT_PTR]
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x8:.AP_PMode
[BITS 32]
.AP_PMode:
mov eax, 0x10
mov ds, ax
mov ebx, [HeapStart]
; Set CR3 to PML4
mov eax, [ebx+BasicInfo.PageTable]
mov cr3, eax
; Enable PAE and PSE
mov eax, cr4
or eax, 0x30
mov cr4, eax
; Enable Long mode
mov ecx, 0xC0000080
rdmsr
or eax, 0x00000100
wrmsr
; Enable Paging
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
lgdt [GDT_PTR_Long]
jmp 0x8:LongModeTest
Trampoline_End:
I'm wondering if anyone else has experienced similar issues? I'm not sure if there is a problem with my code or if switching directly to long mode from real mode no longer works on new hardware. I assume it has to be the former but I don't see anything wrong with my code, and am I wrong assuming that it should either
1. Successfully jump to LongModeTest in long mode or
2. Triple Fault
I haven't gotten a chance to debug it more (I should probably try it with 0 length IDT). Here is LongModeTest:
Code: Select all
[BITS 64]
LongModeTest:
cli
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov rax, [PayloadEntry]
mov edi, [HeapStart]
; Tell BSP we've started
mov DWORD [CpuGood], 1
; Wait for BSP to give us the OK to execute payload
.GetLock:
lock bts DWORD [Spinlock], 0
jc .PauseSpin
jmp rax
.PauseSpin:
pause
test DWORD [Spinlock], 1
jnz .PauseSpin
jmp .GetLock
Is there something wrong with my trampoline (other than not trying to mask NMIs) that would be causing this? Has anyone else had similar problems on hardware? Im trying to figure out if its possible that some pieces of hardware will not go from Real mode to Long mode directly, but this doesn't seem possible.