OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 6:47 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: Entering Long Mode Directly
PostPosted: Mon Feb 26, 2018 11:43 am 
Offline
Member
Member

Joined: Thu Jun 17, 2010 2:36 am
Posts: 141
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
Code:
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:


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.

Code:
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:
[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


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.


Top
 Profile  
 
 Post subject: Re: Entering Long Mode Directly
PostPosted: Mon Feb 26, 2018 12:22 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4594
Location: Chichester, UK
If going via protected mode works then what's the problem?


Top
 Profile  
 
 Post subject: Re: Entering Long Mode Directly
PostPosted: Mon Feb 26, 2018 12:36 pm 
Offline
Member
Member

Joined: Thu Jun 17, 2010 2:36 am
Posts: 141
iansjack wrote:
If going via protected mode works then what's the problem?


First and foremost, I'm curious. Second on the off chance it is hardware related than someone should probably update the wiki on Entering_Long_Mode_Directly.

It would also beg the question what is the status of the CPU? If it hasn't triple faulted and didn't do the long jump, then what is it doing? I think that would be considered a bug. I know Intel manuals specifically say that the CPU needs to be in protected mode to activate long mode, but AFAIK they don't say what will happen if they aren't either.


Top
 Profile  
 
 Post subject: Re: Entering Long Mode Directly
PostPosted: Mon Feb 26, 2018 12:50 pm 
Offline
Member
Member
User avatar

Joined: Sat Dec 27, 2014 9:11 am
Posts: 901
Location: Maadi, Cairo, Egypt
Entering long mode directly works on all my test PCs, on all SMP APs. I seriously doubt this is a hardware bug or some undefined hardware behavior. It's much more likely something is wrong with your code.
Code:
trampoline16:
use16
   xor ax, ax
   mov ds, ax
   mov es, ax

   lgdt [0x1800]   ; temporary GDT just for switching
         ; we can't use the real GDT because it's around 1024 GB
         ; and we can't access that in real mode and pmode

   ; enable PAE, SSE and PSE
   mov eax, 0x630
   mov cr4, eax

   mov eax, cr0
   and eax, 0xFFFFFFFB
   or eax, 2
   mov cr0, eax

   ; go to long mode
   mov eax, PML4
   mov cr3, eax

   mov ecx, 0xC0000080
   rdmsr
   or eax, 0x100
   wrmsr

   mov eax, cr0
   or eax, 0x80000001
   and eax, not 0x60000000
   mov cr0, eax
   jmp 0x08:0x1100

_________________
You know your OS is advanced when you stop using the Intel programming guide as a reference.


Top
 Profile  
 
 Post subject: Re: Entering Long Mode Directly
PostPosted: Tue Feb 27, 2018 12:13 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

Rudster816 wrote:
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


Sadly, no. When the AP is started it begins in real mode using the BIOS IVT, and any exception that occurs while in real mode will use the BIOS interrupt handler. More specifically; if a general protection fault occurs while your trampoline is in real mode the CPU will start the BIOS interrupt handler for "int 0x0D", the BIOS will assume that the interrupt was caused by "IRQ5", do almost nothing (check if the device that generates IRQ5 needs attention, then send an EOI to the PIC chip) and return to the instruction that caused the general protection fault (which will cause another general protection fault, which will cause an infinite loop of general protection faults).

For this reason (and because it's theoretically possible for the AP CPU to receive an NMI while executing the trampoline) I'd recommend loading an IDT with "limit = 0" as early in your trampoline as possible (e.g. "lidt [cs:null_idt]" as the first instruction in the trampoline), so that you have a guarantee that all interrupts and exceptions that can't be masked will trigger a triple fault.

Note: In my opinion it's always a bad idea to mask/disable NMI because NMI is used to indicate hardware failures. When you're unable to handle NMI properly (which is almost impossible for code like this) it's much better to reset the computer (via. triple fault) than it is to continue executing after hardware has failed.

Rudster816 wrote:
Code:
Trampoline_Start:
   cli
   xor ax, ax
   mov ds, ax
   mov ebx, [HeapStart]
   ; Set CR3 to PML4
   mov eax, [ebx+BasicInfo.PageTable]


Can you guarantee that "ebx+BasicInfo.PageTable" is always within the 64 KiB segment limit? Maybe on some computers (those with more memory?) "HeapStart" has a much higher value, and maybe on some computers the "mov eax, [ebx+BasicInfo.PageTable]" instruction causes a general protection fault.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Entering Long Mode Directly
PostPosted: Tue Feb 27, 2018 2:13 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4594
Location: Chichester, UK
Rudster816 wrote:
I know Intel manuals specifically say that the CPU needs to be in protected mode to activate long mode, but AFAIK they don't say what will happen if they aren't either.

I think it is unreasonable to expect the manuals to detail all undefined behaviour. By it's very nature undefined behaviour is undefined. The result might well depend upon the particular model, or even batch, of the CPU.

If instructions, or sequences of instructions, are undocumented then it is not, IMO, sensible to use them. That sort of programming has broken many an application in the past as new CPUs are introduced.


Top
 Profile  
 
 Post subject: Re: Entering Long Mode Directly
PostPosted: Tue Feb 27, 2018 4:11 am 
Offline
Member
Member

Joined: Tue Mar 04, 2014 5:27 am
Posts: 1108
iansjack wrote:
I think it is unreasonable to expect the manuals to detail all undefined behaviour. By it's very nature undefined behaviour is undefined.


It should be bounded, however. I'm not sure what make of the abort class exceptions like #DF and #MC. Just how botched is the CPU state on these? Should it still be possible to log the error (meaning, utilize page translation, caches, DMA, disk I/O, interrupts, etc etc) or things are so undefined that one shouldn't even try? Or one should try, but nobody knows if it'll work? The manual doesn't quite say.


Top
 Profile  
 
 Post subject: Re: Entering Long Mode Directly
PostPosted: Tue Feb 27, 2018 7:48 pm 
Offline
Member
Member

Joined: Thu Jun 17, 2010 2:36 am
Posts: 141
Brendan wrote:
Hi,

Sadly, no. When the AP is started it begins in real mode using the BIOS IVT, and any exception that occurs while in real mode will use the BIOS interrupt handler. More specifically; if a general protection fault occurs while your trampoline is in real mode the CPU will start the BIOS interrupt handler for "int 0x0D", the BIOS will assume that the interrupt was caused by "IRQ5", do almost nothing (check if the device that generates IRQ5 needs attention, then send an EOI to the PIC chip) and return to the instruction that caused the general protection fault (which will cause another general protection fault, which will cause an infinite loop of general protection faults).

For this reason (and because it's theoretically possible for the AP CPU to receive an NMI while executing the trampoline) I'd recommend loading an IDT with "limit = 0" as early in your trampoline as possible (e.g. "lidt [cs:null_idt]" as the first instruction in the trampoline), so that you have a guarantee that all interrupts and exceptions that can't be masked will trigger a triple fault.

Note: In my opinion it's always a bad idea to mask/disable NMI because NMI is used to indicate hardware failures. When you're unable to handle NMI properly (which is almost impossible for code like this) it's much better to reset the computer (via. triple fault) than it is to continue executing after hardware has failed.

Can you guarantee that "ebx+BasicInfo.PageTable" is always within the 64 KiB segment limit? Maybe on some computers (those with more memory?) "HeapStart" has a much higher value, and maybe on some computers the "mov eax, [ebx+BasicInfo.PageTable]" instruction causes a general protection fault.


Cheers,

Brendan



I had a feeling it was something stupid, not sure why I didn't see that. [HeapStart] is in the first 64Kb, but the pointer it contains definitely is not. I guess the BIOS AP initialization routines in the VMs must have raised the segmentation limit and not restored it prior to halting. Sometimes I forgot that just because it works in VMs doesn't mean it isn't broken lol.


I've been meaning to add a 0 length IDT to my code, but have been lazy. I agree though, I've never seen the point in trying to mask NMIs when Intel says they should be. I'd rather triple fault, which accomplishes the same thing that a sane OS should do when it gets an NMI minus an error message.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 181 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group