4

I want to implement the initialisation of paging . Referring to some links of osdev wiki : https://wiki.osdev.org/Paging , https://wiki.osdev.org/Setting_Up_Paging , my own version is very different. Because , when we look at the page directory , they said that 12 bits is for the flag and the rest is for the address of the page table , so I tried something like this:

void init_paging() {
    unsigned int i = 0;

    unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000)));

    for (i = 0; i < 0x400; i++) __PAGE_DIRECTORY__[i] = PAGE_PRESENT(0) | PAGE_READ_WRITE;

    for (i = 0; i < 0x400; i++) __FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;

    __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__  << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;

    _EnablingPaging_();
} 

this function help me to know the physical address knowing the virtual address :

void *get_phyaddr(void *virtualaddr) {
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;

unsigned long *pd = (unsigned long *)__PAGE_DIRECTORY__[pdindex];

unsigned long *pt = (unsigned long *)pd[ptindex];

return (void *)(pt + ((unsigned int)virtualaddr & 0xFFF));

}

I'm in the wrong direction?

Or still the same?

ledoux
  • 91
  • 9

2 Answers2

4

Assuming you're trying to identity map the first 4 MiB of the physical address space:

a) for unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000))); it's a local variable (e.g. likely put on the stack); and it will not survive after the function returns (e.g. the stack space it was using will be overwritten by other functions later), causing the page table to become corrupted. That isn't likely to end well.

b) For __FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;, you're shifting i twice, once with * 0x1000 (which is the same as << 12) and again with the << 12. This is too much, and it needs to be more like __FIRST_PAGE_TABLE__[i] = (i << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;.

c) For __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__ << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;, the address is already an address (and not a "page number" that needs to be shifted), so it needs to be more like __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__) | PAGE_PRESENT(1) | PAGE_READ_WRITE;.

Beyond that; I'd very much prefer better use of types. Specifically; you should probably get in the habit of using uint32_t (or uint64_t, or a typedef of your own) for physical addresses to make sure you don't accidentally confuse a virtual address with a physical address (and make sure the compiler complains abut the wrong type when you make a mistake); because (even though it's not very important now because you're identity mapping) it will become important "soon". I'd also recommend using uint32_t for page table entries and page directory entries, because they must be 32 bits and not "whatever size the compiler felt like int should be" (note that this is a difference in how you think about the code, which is more important than what the compiler actually does or whether int happens to be 32 bits anyway).

Brendan
  • 35,656
  • 2
  • 39
  • 66
  • it may even be worth doing `typedef struct { uint32_t addr; } physaddr_t;` and `typedef struct { uint32_t addr; } virtaddr_t;` to make them two distinct types that the compiler will complain about if you accidentally mix them up. – Chris Dodd Jan 15 '20 at 19:21
  • another problem , is to know the physical address knowing virtual address `void *get_phyaddr(void *virtualaddr);` . we know that when we put virtaul address that is not mapped , _pagingFault_ should occur ... but nothing has done ... where is the problem ?? – ledoux Jan 16 '20 at 10:04
  • @ledoux: `uint64_t get_phyaddr(void *virtualaddr)` would use the page tables (same as CPU would) - e.g. find the right page directory entry and examine that info, then (maybe) find the right page table entry and examine that info, then return a physical address of a "there is no physical address" status or a "you don't have permission" status.`uint64_t get_phyaddr(void *virtualaddr)` shouldn't cause a page fault if the page isn't present (you only want page fault when the page is accessed). – Brendan Jan 16 '20 at 11:59
  • @Brendan , look at this link https://github.com/kouamdo/PEPPER_OS/blob/dd36bd7ca2d433b8b87f341d2c92d7789476319e/arch_ia32/kernel/memory_management/paging/paging.c#L20 , is it perfect ?? But , when i check some virtual address , the `pageFault interrupt` doesn't occur – ledoux Jan 16 '20 at 21:16
  • @ledoux: You're not checking any of the flags in page directory entries or page table entries. E.g. if a page directory entry says "page table isn't present" then you'll just assume that the page table is present (and is at physical address 0x00000000) and try to access it (which will work because its the wrong address), instead of returning any kind of "That virtual address doesn't have a physical address" error back to caller. – Brendan Jan 17 '20 at 04:53
0

When we ask page , but the page was not present , we have pageFault Interrupt . SO to avoid that , we can check if the page is there , else , i choice to return 0x0:

physaddr_t *get_phyaddr(void *virtualaddr) {
    uint32_t pdindex = (uint32_t)virtualaddr >> 22;
    uint32_t ptindex = (uint32_t)virtualaddr >> 12 & 0x03FF;

    uint32_t *pd, *pt, ptable;

    if ((page_directory[pdindex] & 0x3) == 0x3) {
        pd = (uint32_t *)(page_directory[pdindex] & 0xFFFFF000);

        if ((pd[ptindex] & 0x3) == 0x3) {
            ptable = pd[ptindex] & 0xFFFFF000;

            pt = (uint32_t *)ptable;

            return (physaddr_t *)(pt + ((uint32_t)(virtualaddr)&0xFFF));
        } else
            return 0x0;
    } else
        return 0x0;
}
ledoux
  • 91
  • 9