[SOLVED] Paging 1-GByte Page

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Rukog
Member
Member
Posts: 51
Joined: Sun Aug 01, 2021 5:24 pm

[SOLVED] Paging 1-GByte Page

Post by Rukog »

I don't know what is wrong since this code update isn't working, ive maybe missed something in intel docs.

Image
Image

Code: Select all

    ; Setup paging
    ;{
        ; Linear-Address Translation to a 1-GByte Page using 4-Level Paging
        ;{
            ; Format of a Page-Directory-Pointer-Table Entry (PDPTE) that Maps a 1-GByte Page
            ;{
                %define PG_FLAG_P(bit)      (bit << 0)  ; 0: Page not Present           1: Page Present
                %define PG_FLAG_RW(bit)     (bit << 1)  ; 0: Read-only                  1: Read Write
                %define PG_FLAG_US(bit)     (bit << 2)  ; 0: Supervisor Mode            1: User Mode
                %define PG_FLAG_PWT(bit)    (bit << 3)  ; 0: Page-level write-through   1: Page-level write-through
                %define PG_FLAG_PCD(bit)    (bit << 4)  ; 0: Page-level cache disable   1: Page-level cache disable
                %define PG_FLAG_A(bit)      (bit << 5)  ; 0: Accessed                   1: Accessed
                %define PG_FLAG_D(bit)      (bit << 6)  ; 0: Dirty                      1: Dirty
                %define PG_FLAG_PS(bit)     (bit << 7)  ; 0: Refer a Page Directory     1: Refer a 1-GByte Page
                %define PG_FLAG_G(bit)      (bit << 8)  ; 0: Global                     1: Global
                %define PG_FLAG_PAT(bit)    (bit << 12) ; 0: Paging and Memory Typing   1: Paging and Memory Typing
                
                mov     eax, PG_FLAG_P(1) + PG_FLAG_RW(1) + PG_FLAG_US(0) + PG_FLAG_A(1) + PG_FLAG_D(1)+ PG_FLAG_PS(1)
                mov     [PagingTable.PML4], dword PagingTable.PDPT
                or      [PagingTable.PML4], eax
                
                ; Build the Page-Directory-Pointer Table
                mov     ecx, 4     ; 4 GB
                mov     edi, PagingTable.PDPT
                .SetNextEntry:
                ;{
                    mov     [edi], eax          ; Set page entry
                    add     eax, 0x4000_0000    ; Next 1-GB page
                    add     edi, 8              ; Next PDPT entry
                
                    loop    .SetNextEntry
                ;}
            ;}
        ;}
    ;}
Last edited by Rukog on Thu Aug 19, 2021 11:48 am, edited 2 times in total.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Paging 1-GByte Page

Post by iansjack »

You don't say what your problem is. But what you may have missed s that not all processors support 1GB pages.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Paging 1-GByte Page

Post by Octocontrabass »

You're setting the page size bit in your PML4E, not your PDPTEs. The page size bit is not valid in a PML4E.

You're not setting the present bit or the page size bit in your PDPTEs. You need both of those to get 1GB pages. You probably want to set a few other bits too.

The behavior of large pages that cross effective memory type boundaries is undefined. Before using large pages, you must read the MTRRs and verify that the effective memory type will be the same across the entire page. (See Intel SDM 3A 11.11.9 for details.)

And, of course, you have to make sure your CPU supports 1GB pages.
Rukog
Member
Member
Posts: 51
Joined: Sun Aug 01, 2021 5:24 pm

Re: Paging 1-GByte Page

Post by Rukog »

The original code reset the CPU constantly, so I think my CPU does support the 1 GB Page, it does looping with that code.

Code: Select all

    Yes:
        mov     eax, 0x80000001
        cpuid
        mov     eax, edx
        or      eax, 1 << 26
        cmp     edx, eax
    je      Yes
And you are right about the PS thus here's an update of the code.

Code: Select all

    ; Setup paging
    ;{
        ; Paging Structures in the Different Paging Modes
        
        ; Linear-Address Translation to a 1-GByte Page using 4-Level Paging
        ;{
            ; Format of a PML4 Entry (PML4E) that References a Page-Directory-Pointer Table
            ;{
                %define PG_FLAG_P(bit)      (bit << 0)  ; 0: Page not Present           1: Page Present
                %define PG_FLAG_RW(bit)     (bit << 1)  ; 0: Read-only                  1: Read Write
                %define PG_FLAG_US(bit)     (bit << 2)  ; 0: Supervisor Mode            1: User Mode
                %define PG_FLAG_PWT(bit)    (bit << 3)  ; 0: Page-level write-through   1: Page-level write-through
                %define PG_FLAG_PCD(bit)    (bit << 4)  ; 0: Page-level cache disable   1: Page-level cache disable
                %define PG_FLAG_A(bit)      (bit << 5)  ; 0: Accessed                   1: Accessed
                %define PG_FLAG_PS(bit)     (bit << 7)  ; Reserved (must be 0)
                
                mov     eax, PG_FLAG_P(1) + PG_FLAG_RW(1) + PG_FLAG_US(0) + PG_FLAG_A(1) + PG_FLAG_PS(0)
                
                ; Build the PML4 Table
                mov     [PagingTable.PML4], dword PagingTable.PDPT
                or      [PagingTable.PML4], eax
            ;}
            
            ; Format of a Page-Directory-Pointer-Table Entry (PDPTE) that Maps a 1-GByte Page
            ;{
                %define PG_FLAG_P(bit)      (bit << 0)  ; 0: Page not Present           1: Page Present
                %define PG_FLAG_RW(bit)     (bit << 1)  ; 0: Read-only                  1: Read Write
                %define PG_FLAG_US(bit)     (bit << 2)  ; 0: Supervisor Mode            1: User Mode
                %define PG_FLAG_PWT(bit)    (bit << 3)  ; 0: Page-level write-through   1: Page-level write-through
                %define PG_FLAG_PCD(bit)    (bit << 4)  ; 0: Page-level cache disable   1: Page-level cache disable
                %define PG_FLAG_A(bit)      (bit << 5)  ; 0: Accessed                   1: Accessed
                %define PG_FLAG_D(bit)      (bit << 6)  ; 0: Dirty                      1: Dirty
                %define PG_FLAG_PS(bit)     (bit << 7)  ; 0: Refer a Page Directory     1: Refer a 1-GByte Page
                %define PG_FLAG_G(bit)      (bit << 8)  ; 0: Global                     1: Global
                %define PG_FLAG_PAT(bit)    (bit << 12) ; 0: Paging and Memory Typing   1: Paging and Memory Typing
                
                mov     eax, PG_FLAG_P(1) + PG_FLAG_RW(1) + PG_FLAG_US(0) + PG_FLAG_A(1) + PG_FLAG_D(1)+ PG_FLAG_PS(1)
                
                ; Build the Page-Directory-Pointer-Table
                mov     ecx, 4     ; 512 entries max
                mov     edi, PagingTable.PDPT
                .SetNextEntry:
                ;{
                    mov     [edi], eax          ; Set new PDPT Entry
                    add     eax, 0x4000_0000    ; Next 1-GB page
                    add     edi, 8              ; Next PDPT Entry
                
                    loop    .SetNextEntry
                ;}
            ;}
        ;}
    ;}

And Qemu does boot this but not my real machine.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Paging 1-GByte Page

Post by Octocontrabass »

It's hard to say what else could be wrong, especially when it only fails on hardware.

You made sure the rest of your PML4 and PDPT is cleared to zero, right?
Rukog
Member
Member
Posts: 51
Joined: Sun Aug 01, 2021 5:24 pm

Re: Paging 1-GByte Page

Post by Rukog »

Octocontrabass wrote:It's hard to say what else could be wrong, especially when it only fails on hardware.

You made sure the rest of your PML4 and PDPT is cleared to zero, right?
Yep, I am using the same paging table of my previous 4 KB pages mapping.

Code: Select all

PagingTable:    ; 512 address of 64-bit
;{
    .PML5: times 512 dq 0  ; Page Map Level 5
    .PML4: times 512 dq 0  ; Page Map Level 4
    .PDPT: times 512 dq 0  ; Page Directory Pointer Table
    .PD:   times 512 dq 0  ; Page Directory
    .PT:   times 512 dq 0  ; Page Table
;}
EndPagingTable:
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Paging 1-GByte Page

Post by nexos »

Are you trying to use 5 level paging? It looks that way as, you have a PML5 in your code. 5 level paging hasn't been released by Intel yet :) . It only works on QEMU.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Rukog
Member
Member
Posts: 51
Joined: Sun Aug 01, 2021 5:24 pm

Re: Paging 1-GByte Page

Post by Rukog »

nexos wrote:Are you trying to use 5 level paging? It looks that way as, you have a PML5 in your code. 5 level paging hasn't been released by Intel yet :) . It only works on QEMU.
I found the bug and it was the enable of PCIDE in cr4 that caused problem.
I thought I needed that flag for the 1 GB page mapping :shock:

Code: Select all

mov     eax, cr4
or      eax, 1 << 5
; or      eax, 1 << 17    ; PCIDE
mov     cr4, eax
Post Reply