OSDev.org https://forum.osdev.org/ |
|
PAE paging problem https://forum.osdev.org/viewtopic.php?f=1&t=57216 |
Page 1 of 1 |
Author: | awik [ Sun Apr 21, 2024 12:33 pm ] |
Post subject: | PAE paging problem |
Hi all, I've written a program that enters long mode, clears the screen, and exits long mode. As part of returning from long mode to 32-bit "regular" protected mode, I'm trying to re-enable PAE-style paging. So, after the exit from long mode, I change CR3 from pointing to the PML4 table to point to the Page Directory Pointer Table instead. Then Bochs generates this error message: Code: 202206508436e[CPU0 ] SetCR0(): PDPTR check failed ! What might be wrong? The PDPT works fine in long mode. Source code is available on request. Regards, Albert. |
Author: | Octocontrabass [ Sun Apr 21, 2024 1:15 pm ] |
Post subject: | Re: PAE paging problem |
awik wrote: What might be wrong? Bochs displays that message when reserved bits are set in the PDPT. awik wrote: The PDPT works fine in long mode. Long mode and protected mode have different definitions for the PDPT. A PDPT that's valid in long mode may not be valid in protected mode. |
Author: | awik [ Mon Apr 22, 2024 11:56 pm ] |
Post subject: | Re: PAE paging problem |
You're were right. Apparently, only bit 0 may be set in a PDPT entry in regular protected mode. It is necessary to re-initialise the entries, because in long mode, several other bits get set automatically. -Albert. |
Author: | rdos [ Tue Apr 23, 2024 11:06 am ] |
Post subject: | Re: PAE paging problem |
You must create a GDT, switch to compatibility mode, disable paging, change CR3, set PAE bit and then renable protected mode paging. My code looks like this: (it's mostly hex-coded since my assembler cannot handle mixed 32 & 64-bit code) Code: IMAGE_BASE = 110000h
param_struc STRUC lfb_base DD ?,? lfb_width DD ? lfb_height DD ? lfb_line_size DD ? lfb_flags DD ? mem_entries DD ? acpi_table DD ?,? param_struc ENDS _TEXT segment byte public use16 'CODE' .386p db 0Ebh ; jmp init64 db 38h + SIZE param_struc param param_struc <> rom_gdt: gdt0: dw 0 dd 0 dw 0 gdt8: dw 0 dd 0 dw 0 gdt10: dw 28h-1 dd 92000000h + OFFSET rom_gdt + IMAGE_BASE dw 0 gdt18: dw 0FFFFh dd 9A000000h dw 0CFh gdt20: dw 0FFFFh dd 92000000h dw 08Fh gdt_ptr: dw 28h-1 dd OFFSET rom_gdt + IMAGE_BASE dd 0 prot_ptr: dd OFFSET prot_init + IMAGE_BASE dw 18h init64: db 0FAh ; cli db 0Fh ; lgdt gdt_ptr db 01h db 15h dd 0FFFFFFE8h ; db 0FFh db 1Dh dd 0FFFFFFECh prot_init: db 0Fh ; mov eax,cr0 db 20h db 0C0h ; db 25h ; and eax,7FFFFFFFh dd 07FFFFFFFh ; db 0Fh ; mov cr0,eax db 22h db 0C0h ; db 0B9h ; mov ecx,IA32_EFER dd 0C0000080h ; db 0Fh ; rdmsr db 32h ; db 25h ; and eax,0FFFFFEFFh dd 0FFFFFEFFh ; db 0Fh ; wrmsr db 30h ; db 0Fh ; mov rax,cr4 db 20h db 0E0h ; db 83h ; and eax,NOT 20h db 0E0h db 0DFh ; db 0Fh ; mov cr4,rax db 22h db 0E0h ; db 0B8h ; mov eax,20h dd 20h ; db 8Eh ; mov ds,eax db 0D8h ; db 0BBh ; mov ebx,OFFSET gdt18 dd OFFSET gdt18 + IMAGE_BASE ; db 0BAh ; mov edx,IMAGE_BASE dd IMAGE_BASE ; db 89h ; mov [ebx+2],edx db 53h db 02h ; db 0B0h ; mov al,9Ah db 9Ah ; db 86h ; xchg al,[ebx+5] db 43h db 5 ; db 32h ; xor cl,cl db 0C9h ; db 8Ah ; mov ch,al db 0E8h ; db 66h ; mov [ebx+6],cx db 89h db 4Bh db 6 ; db 0EAh ; jmp 18:init dd OFFSET init dw 18h init: mov ax,20h mov ds,ax mov es,ax mov fs,ax mov gs,ax |
Author: | awik [ Wed Apr 24, 2024 7:41 am ] |
Post subject: | Re: PAE paging problem |
rdos wrote: You must create a GDT, switch to compatibility mode, disable paging, change CR3, set PAE bit and then renable protected mode paging. I already have a GDT, and the PAE bit is already set. Quote: My code looks like this: (it's mostly hex-coded since my assembler cannot handle mixed 32 & 64-bit code) My (now working) code is as follows: Code: ;
; Going from 64-bit mode straight to legacy (non-long) mode is ; not legal. Also, we cannot go directly to a 32-bit code segment ; with a (non-zero) base, because the base does not get loaded as ; long (pun not intended) as we are in Long Mode. The solution is ; to go to Compatibility Mode first. ; ; mov ax, SEG_BASED_CS_32 mov ax, SEG_FLAT_CS_32 ; segment suitable for ; ; Compatibility Mode push rax lea eax,[esi+.exit_from_64] push rax retfq BITS 32 ALIGN 4 .exit_from_64: ; ; We are now in Compatibility Mode. ; ; We need to turn off paging before we can exit Long Mode. ; mov eax,cr0 btr eax,CR0_PG_BIT mov cr0,eax ; ; Disable Long Mode ; mov ecx,MSR_EFER rdmsr btr eax,EFER_LM_BIT wrmsr ; push SEG_BASED_CS_32 ; "based" 32-bit code segment push .exit_from_lm32 retfd ALIGN 4 BITS 32 .exit_from_lm32: ; ; We are now running from our "based" 32-bit code segment. ; mov ax,SEG_BASED_DS_16 ; "based" data/stack segment mov ss, ax sub esp,esi ; convert linear to segment-relative sub ebp,esi mov ds, ax mov es, ax ; ; Set up paging for "normal" Protected Mode ; mov eax,[ebp+BSS_PDPT_PHYSADDR] mov ebx,eax sub ebx,esi ; convert linear to segment-relative and byte [ebx], 1 ; clear reserved bits mov cr3,eax mov eax,cr0 bts eax,CR0_PG_BIT mov cr0,eax ; |
Author: | rdos [ Wed Apr 24, 2024 11:43 pm ] |
Post subject: | Re: PAE paging problem |
Not sure about the non-zero base. You can load selectors with non-zero base in long mode, but the base will not be applied until you are in compatibility mode. It's perfectly possible to do a far jump to legacy code with a non-zero base. Segment register loads operates exactly the same in long mode as in protected mode. I posted my EFI 64->32 bit code previously, but I also have simpler code to switch between protected mode and long mode and the reverse. Switching to long mode is pretty easy: Code: ; EAX = cr3 switch_to_long_mode Proc far push eax push ebx push ecx push edx pushf ; mov ebx,eax cli ; mov eax,cr0 and eax,7FFFFFFFh mov cr0,eax ; mov ecx,IA32_EFER rdmsr or eax,101h wrmsr ; mov cr3,ebx ; mov eax,cr0 or eax,80000000h mov cr0,eax ; lidt fword ptr cs:long_idt_size ; popf pop edx pop ecx pop ebx pop eax ret switch_to_long_mode Endp Switching back is easy too: Code: ; EAX = cr3 switch_to_protected_mode Proc far push eax push ebx push ecx push edx pushf ; mov ebx,eax cli ; mov eax,cr0 and eax,7FFFFFFFh mov cr0,eax ; mov ecx,IA32_EFER rdmsr and eax,0FFFFFEFFh wrmsr ; mov cr3,ebx ; mov eax,cr0 or eax,80000000h mov cr0,eax ; lidt fword ptr cs:prot_idt_size ; popf pop edx pop ecx pop ebx pop eax ret switch_to_protected_mode Endp However, the switching back code is running in compatibility mode since the scheduler is running in compatibility mode and not in long mode. The switching from long mode to compatibility mode happens as part of a syscall or an IRQ, which contain code to do a far call to the common handler code in compatibility mode. Also note that the GDT can be shared between protected mode and long mode, but not the IDT. There is a need for a specific IDT for long mode. |
Author: | awik [ Thu Apr 25, 2024 3:36 am ] |
Post subject: | Re: PAE paging problem |
rdos wrote: Not sure about the non-zero base. I was pretty sure about it, because I had tested it, but now that I tested it again, the base *does* get set. I think I must have pushed the wrong (ie. flat) address last time. Quote: Switching to long mode is pretty easy: It *is* easy once you have PAE paging set up. Otherwise, you have to set up 4 levels of paging structures first. Quote: ... a syscall or an IRQ, which contain handlers with a compatibility mode descriptor. Cool, I didn't know you could do that. Quote: Also note that the GDT can be shared between protected mode and long mode, but not the IDT. There is a need for a specific IDT for long mode. I know. I haven't tried creating a 64-bit IDT myself yet. -Albert. |
Author: | awik [ Fri Apr 26, 2024 5:47 am ] |
Post subject: | Re: PAE paging problem |
awik wrote: rdos wrote: ... a syscall or an IRQ, which contain handlers with a compatibility mode descriptor. Cool, I didn't know you could do that.The "AMD64 Architecture Programmer's Manual", volume 2, "System Programming), page 102, reads: "The target code segment referenced by a long-mode gate descriptor must be a 64-bit code segment (CS.L=1, CS.D=0). If the target is not a 64-bit code segment, a general-protection exception, #GP(error), occurs.". Is this incorrect? |
Author: | rdos [ Fri Apr 26, 2024 6:56 am ] |
Post subject: | Re: PAE paging problem |
awik wrote: awik wrote: rdos wrote: ... a syscall or an IRQ, which contain handlers with a compatibility mode descriptor. Cool, I didn't know you could do that.The "AMD64 Architecture Programmer's Manual", volume 2, "System Programming), page 102, reads: "The target code segment referenced by a long-mode gate descriptor must be a 64-bit code segment (CS.L=1, CS.D=0). If the target is not a 64-bit code segment, a general-protection exception, #GP(error), occurs.". Is this incorrect? The manual is correct. I changed my post so that the IRQ handler does a far call to the compatibility mode server procedure. That's part of the reason you need different IDTs, and also different high-level handler procedures. The long mode interrupt handlers must run in long mode, but can defer their function to compatibility mode for common cases like IRQs. Exceptions, including page fault, need to be handled completely in long mode, perhaps except for aborting a faulty process. |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |