Page 1 of 1

Unusual page table reported by Bochs

Posted: Tue May 08, 2012 8:48 pm
by ATXcs1372
I'm currently moving to the use of 2 MiB pages, but whenever I try to use large pages Bochs' report of my page table doesn't even make sense.

The code I use to initialize the PML4 table is:

Code: Select all

//-----------------------------------------------------------------
// Definitions
//-----------------------------------------------------------------
#ifndef synapse_mmanager_c
#define synapse_mmanager_c

#define PAGE_PRESENT        0x01                // page is present
#define PAGE_WRITABLE       0x02                // page is writable
#define PAGE_USERACCESS     0x04                // user mode accessable
#define PAGE_WRITETHROUGH   0x08
#define PAGE_CACHEDISABLE   0x10                // disable caching for page
#define PAGE_ACCESSED       0x20                // has been accessed; set by CPU
#define PAGE_DIRTY          0x40
#define PAGE_LARGEPAGE      0x80                // page size, 0 = 4KiB
#define PAGE_GLOBALPAGE     0x100
#define PAGE_NOEXECUTE      0x8000000000000000  //disable execution

//-----------------------------------------------------------------
// Data Types
//----------------------------------------------------------------- 
typedef struct
{
    uint64_t present        : 1;
    uint64_t writable       : 1;
    uint64_t useraccess     : 1;
    uint64_t writethru		: 1;
    uint64_t disablecache	: 1;
    uint64_t accessed       : 1;
    uint64_t dirty          : 1;
    uint64_t largepage		: 1;
    uint64_t global			: 1;
    uint64_t reserved		: 3;
    uint64_t frame          : 51;
    uint64_t noexecute		: 1;
} Page;

typedef struct
{
    uint64_t    *page[512];    // pointers to the 2 MiB page frames
} PageTable;

typedef struct
{
    PageTable 	*table[512];	// pointers to the 1 GiB page tables
} PageDirectory;

//-----------------------------------------------------------------
// Variables
//-----------------------------------------------------------------
PageDirectory *pageDirectory;
PageTable *pageTable;
uint64_t *pages;

Code: Select all

pageDirectory 	= (PageDirectory *)0x2000;		// define this location as PML4 base, maps 512 GiB
	pageTable       = (PageTable *)0x3000;
	pages           = (uint64_t *)0x10000;
	
	pageDirectory->table[0] = (PageTable *)(((uint64_t)pageTable) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USERACCESS);    // attributes resolve to 0x07
	
    uint16_t i;
    for (i = 0; i < 32; i++)    // identity map the first 64 MiB and make it kernel elevated (can change later if needed)
    {
        pages[i]                = (uint64_t)((i * 0x200000) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_LARGEPAGE);   // attributes resolve to 0x83
        pageTable->page[i]      = pages[i] | PAGE_PRESENT | PAGE_WRITABLE;  // attributes resolve to 0x03
    }

    asm volatile("mov %0, %%cr3":: "r"(0x2000));
}
yet Bochs' debugger reports the page table as

Code: Select all

0x00000000-0x00005fff -> 0x0000000000000000-0x0000000000005fff
0x00007000-0x00009fff -> 0x0000000000007000-0x0000000000009fff
0x00010000-0x00010fff -> 0x0000000000010000-0x0000000000010fff
0x00050000-0x00050fff -> 0x0000000000050000-0x0000000000050fff
0x000b8000-0x000b8fff -> 0x00000000000b8000-0x00000000000b8fff
0x000e0000-0x000fcfff -> 0x00000000000e0000-0x00000000000fcfff
0x00200000-0x00204fff -> 0x0000000000200000-0x0000000000204fff
0x3fff0000-0x3fff0fff -> 0x000000003fff0000-0x000000003fff0fff
This happens even when I do not reload CR3.
I am in long mode and PAE as well as paging are enabled.
Am I missing something obvious?

Re: Unusual page table reported by Bochs

Posted: Tue May 08, 2012 9:37 pm
by Rudster816
You're missing a level of indirection, and actually end up mapping 32 1GB pages instead.

The value in CR3 contains the address to the PML4, which maps 256TB.
Each entry in the PML4 (aka a PML4E) maps 512GB.
Each entry in the PML4E (a PDPE) maps 1GB.
Each entry in the PDPE (a PDE) maps 2MB.
Each entry in the PDE (a PTE) maps 4KB.

Re: Unusual page table reported by Bochs

Posted: Tue May 08, 2012 9:43 pm
by ATXcs1372
atxcs1372 wrote:
Rudster816 wrote:You're missing a level of indirection, and actually end up mapping 32 1GB pages instead.

The value in CR3 contains the address to the PML4, which maps 256TB.
Each entry in the PML4 (aka a PML4E) maps 512GB.
Each entry in the PML4E (a PDPE) maps 1GB.
Each entry in the PDPE (a PDE) maps 2MB.
Each entry in the PDE (a PTE) maps 4KB.
I'm not using the 4KiB level, but I don't see how this is so.

Code: Select all

PML4 (512 GiB | located at 0x600000)
    |
    |--> PML3 (1 GiB | located at 0x601000)
                |
                |-> PML2 (2 MiB | located at 0x602000)
                           |
                           |-->  Page at location pointed to by PML2 [(i * 0x200000) | PRESENT | WRITABLE | LARGE]
Is what I'm doing.... where am I missing an indirection table?
EDIT: Sorry, I misread your post. I did misunderstand the role of the PML4 and then proceeding on.

Re: Unusual page table reported by Bochs

Posted: Wed May 09, 2012 4:20 am
by Combuster
What have you done with CR4 to get large pages working?

Re: Unusual page table reported by Bochs

Posted: Wed May 09, 2012 5:03 am
by sandras
Just a thought. Do you think it would be possible to make it configurable - you set the page size you want at compile time. I mean, additional configurability does not hurt as long as the code is still readable. And what if you wanted to go back to 4kb pages again in the future.

Re: Unusual page table reported by Bochs

Posted: Wed May 09, 2012 5:58 am
by bluemoon
Sandras wrote:Just a thought. Do you think it would be possible to make it configurable - you set the page size you want at compile time. I mean, additional configurability does not hurt as long as the code is still readable. And what if you wanted to go back to 4kb pages again in the future.
The amount of mmu code is not huge. It's simpler to just write two version instead of unifying them.
Furthermore, on 4KiB page you can handle PML4/PDPT/PD fault exactly the same way as ordinary address region, while supporting 2MiB page you need to handle them differently - you won't allocate 2MiB for an page structure.

Re: Unusual page table reported by Bochs

Posted: Wed May 09, 2012 6:08 am
by sandras
bluemoon wrote:The amount of mmu code is not huge. It's simpler to just write two version instead of unifying them.
Furthermore, on 4KiB page you can handle PML4/PDPT/PD fault exactly the same way as ordinary address region, while supporting 2MiB page you need to handle them differently - you won't allocate 2MiB for an page structure.
I suppose I wouldn't know these things. Paging is what I'm at right now for the first time after all. : )

Re: Unusual page table reported by Bochs

Posted: Wed May 09, 2012 8:45 am
by bluemoon
By the way I found it more useful to have the slot id for recursive page directory be configurable, especially when working with 64bit where you may shuffle/reorder things around in the huge address space early development phase.

For example, I have these setting on 32 and 64bit kernel:

Code: Select all

#define MMU_RECURSIVE_SLOT      (1023UL)  // 32-bit
#define MMU_RECURSIVE_SLOT      (510UL)    // 64-bit