To think of it, there might be a contrived way of enabling PAE on the fly. You could rewrite the first 8 PDEs into PDPTEs, make them point to page directories, etc, and then enable PAE. Assuming that the IDT, GDT and TSS are pointed at higher half memory at this point, you shouldn't fault yet. Turning on PAE should serialize the execution, flush the pipeline and discard the TLB entries, and hopefully just reload the paging structures. Of course, starting with PAE will be more conventional, but it is your decision.Octacone wrote:I definitely don't want to keep PSE. This never gets easy, doesn't it?simeonz wrote:When you turn off PSE, the current code page (being large 4MB page) will be immediately discarded from the TLB, then resolved again, but since PSE is off, the PS bit will be ignored, and the PDE will be interpreted as a pointer to a page table. This is sufficient for a crash. If you turn on the PAE, the paging structures immediately switch to 3-level with PDPTEs at the top. I don't think that there is a way to do that safely without disabling paging first, in which case you are back to square one. I would advise you to keep PSE. Or don't map the kernel with large pages. If you want PAE, you better start with PAE on. There will be one more level of indirection, and you will have to set the first directory entry of the first and fourth page directories.Octacone wrote:Success!!!
I managed to enable PSE 4 MB paging in assembly and identity map 1 MB to 1 MB and 3 GB to 1 MB. Everything seems to be working fine. My kernel is officially in higher half.
Now I'm having a problem because it crashes when I try to re-enable paging, more specially turning off PSE and turning on PAE and resetting CR3. How to solve that?
This is going to get really messy and complicated. Making PAE work in assembly, great, just great. Shouldn't take more than like 5 weeks, but OK.
Fixed: Higher Half in C?
Re: Higher Half in C?
Re: Higher Half in C?
I'll go for PAE from the beginning.simeonz wrote:To think of it, there might be a contrived way of enabling PAE on the fly. You could rewrite the first 8 PDEs into PDPTEs, make them point to page directories, etc, and then enable PAE. Assuming that the IDT, GDT and TSS are pointed at higher half memory at this point, you shouldn't fault yet. Turning on PAE should serialize the execution, flush the pipeline and discard the TLB entries, and hopefully just reload the paging structures. Of course, starting with PAE will be more conventional, but it is your decision.
Uhmm, how exactly am I supposed to access 64-bit bitfields in assembly while in 32-bit mode? Never had to do something like this.
Like how to move data from one register to some_data + 40 bits? That is why is love higher languages so much and that is why programming abstractions in assembly is hard.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
Re: Higher Half in C?
Initializing PAE is not much more complicated than non-PAE. Here is what I do:
You can see the whole implementation here:
https://github.com/kiznit/kiznix/blob/f ... ot_pae.asm
Hope this helps...
Code: Select all
; Initialize the PDPT
mov edi, _BootPDPT - KERNEL_VIRTUAL_BASE
mov eax, (_BootPageDirectory - KERNEL_VIRTUAL_BASE) + PAGE_PRESENT
mov [edi], eax ; Identity map the first 4 MB
mov [edi + 3 * 8], eax ; Map the same 4 MB to high memory
; Initialize the page directory (2 MB per entry)
mov edi, _BootPageDirectory - KERNEL_VIRTUAL_BASE
mov eax, (_BootPageTables - KERNEL_VIRTUAL_BASE) + PAGE_WRITE + PAGE_PRESENT
mov [edi], eax ; First page table (First 2 MB)
add eax, 0x1000
mov [edi + 8], eax ; Second page table (Next 2 MB)
; Initialize the page tables
mov edi, _BootPageTables - KERNEL_VIRTUAL_BASE
mov eax, 0x00000000 | PAGE_WRITE | PAGE_PRESENT ; Start at physical address 0
mov ecx, 1024 ; 1024 entries
.fill_page_table:
mov [edi], eax
add eax, 0x1000
add edi, 8
loop .fill_page_table
https://github.com/kiznit/kiznix/blob/f ... ot_pae.asm
Hope this helps...
Re: Higher Half in C?
Easy for you to say, my pages are 4 KB not 2 MB. Thanks anyways!kzinti wrote:Initializing PAE is not much more complicated than non-PAE. Here is what I do:You can see the whole implementation here:Code: Select all
---snip---
https://github.com/kiznit/kiznix/blob/f ... ot_pae.asm
Hope this helps...
Btw, I found a solution to my problem, that doesn't work, yet.
What I did is basically inspected the paging structures in memory (C++ generated) and then I figured out where to put stuff at and what bytes are flags and what bytes are address bytes. That made my job a lot easier.
After all the pain I created 6 page tables filled them accordingly did all the math, interconnected everything and yet Bochs is not happy:
Code: Select all
SetCR0(): PDPTR check failed !
Anyways here are chunks of my code:
Code: Select all
//Do so for all 4, make sure that page directory pointer table has 4 page directories
mov eax, (first_page_directory - 0xC0000000)
shr eax, 12
mov dword [page_directory_pointer_table.first_page_directory_pointer_table_entry - 0xC0000000 + 1], eax
mov byte [page_directory_pointer_table.first_page_directory_pointer_table_entry - 0xC0000000], 1
//Inserting page table address and flags into page directory entry, do so for all six of them
mov eax, (first_page_table - 0xC0000000)
shr eax, 12
mov dword [first_page_directory.first_page_directory_entry - 0xC0000000 + 1], eax
mov dword [third_page_directory.first_page_directory_entry - 0xC0000000 + 1], eax
mov byte [first_page_directory.first_page_directory_entry - 0xC0000000], 3
mov byte [third_page_directory.first_page_directory_entry - 0xC0000000], 3
//The way I fill my page tables, only showing the first 3
mov ecx, 512
xor eax, eax
xor edx, edx
.Fill_First_Page_Table:
cmp ecx, 0
je .Done_Filling_First_Page_Table
shr eax, 12
mov dword [first_page_table - 0xC0000000 + 1 + edx], eax
shl eax, 12
mov byte [first_page_table - 0xC0000000 + edx], 3
add eax, 0x1000
dec ecx
add edx, 8
jmp .Fill_First_Page_Table
.Done_Filling_First_Page_Table:
mov ecx, 512
mov eax, 0x200000
xor edx, edx
.Fill_Second_Page_Table:
cmp ecx, 0
je .Done_Filling_Second_Page_Table
shr eax, 12
mov dword [second_page_table - 0xC0000000 + 1 + edx], eax
shl eax, 12
mov byte [second_page_table - 0xC0000000 + edx], 3
add eax, 0x1000
dec ecx
add edx, 8
jmp .Fill_Second_Page_Table
.Done_Filling_Second_Page_Table:
mov ecx, 512
mov eax, 0x400000
xor edx, edx
.Fill_Third_Page_Table:
cmp ecx, 0
je .Done_Filling_Third_Page_Table
shr eax, 12
mov dword [third_page_table - 0xC0000000 + 1 + edx], eax
shl eax, 12
mov byte [third_page_table - 0xC0000000 + edx], 3
add eax, 0x1000
dec ecx
add edx, 8
jmp .Fill_Third_Page_Table
.....etc
//Last chunk
mov eax, (page_directory_pointer_table - 0xC0000000)
mov cr3, eax
mov eax, cr4
or eax, 00000000000000000000000000100000b
mov cr4, eax
mov eax, cr0
or eax, 10000000000000000000000000000000b
mov cr0, eax
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
Re: Higher Half in C?
My pages are 4 KB.Octacone wrote: Easy for you to say, my pages are 4 KB not 2 MB. Thanks anyways!
There are 512 entries in one page table. 512 x 4 KB = 2 MB per page directory entry.
I use 2 page tables for a total of 4 MB.
That 4 MB is identity-mapped and mapped to 3 GB using the first an last entries of the PDPT.
Re: Higher Half in C?
Why did I assume they were 2 MB?kzinti wrote:My pages are 4 KB.Octacone wrote: Easy for you to say, my pages are 4 KB not 2 MB. Thanks anyways!
There are 512 entries in one page table. 512 x 4 KB = 2 MB per page directory entry.
I use 2 page tables for a total of 4 MB.
That 4 MB is identity-mapped and also mapped to 3 GB.
I'll definitely have a look to see if anything stands out.
I need like 12 MB but I'll figure it out.
Edit: So you are using like 1 page directory for the whole thing, just pointing to it twice inside the page directory pointer table. That is smart, it could save a lot of space when I think of it.
Edit: Wait, I don't see you shifting any addresses to the right by 12. Isn't that like mandatory, or it only applies to pages?
Reply to edit above: since it's page aligned it doesn't matter..., only matters for pages looks like.
Okay, I did some bug fixing and now I am getting physical address not available, which is better than not getting it. But why can't I see my page tables in Bochs? How am I supposed to fix them without seeing them?
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
Fixed: Higher Half in C?
VICTORY!
It is done, it is over, finally!
Boooooy that took a while, but it was worth it. So how did I fix it?
While looking through @kzinti's code I noticed that he was adding flags directly to the address value, while I was doing it separately and accidentally offsetting it by 1 byte.
Many many thanks to @kzinti he appeared exactly when I needed him.
Now I just need to figure out how to load a new page directory pointer table with different values while removing 0xC000000 offset from all the values so they are physical. I will probably have to switch from static to dynamic allocation, but that is a problem for later for me to figure out.
Again, thanks to everybody who showed interest in helping.
It is done, it is over, finally!
Boooooy that took a while, but it was worth it. So how did I fix it?
While looking through @kzinti's code I noticed that he was adding flags directly to the address value, while I was doing it separately and accidentally offsetting it by 1 byte.
Many many thanks to @kzinti he appeared exactly when I needed him.
Now I just need to figure out how to load a new page directory pointer table with different values while removing 0xC000000 offset from all the values so they are physical. I will probably have to switch from static to dynamic allocation, but that is a problem for later for me to figure out.
Again, thanks to everybody who showed interest in helping.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader