Only Identity paging causes Triple Fault

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
NOOOCCCC
Posts: 11
Joined: Sat Nov 17, 2018 2:47 pm
Libera.chat IRC: blackburn

Only Identity paging causes Triple Fault

Post by NOOOCCCC »

Hello there,

I have a problem with my paging initializer code. There is no problem when I idty. map all my kernel or when I map it to any address. But recently I tried to identity-map only the first megabyte of physical memory, and I had an unresolved problem. First i used this very simple code to see if it works(and it does perfectly):

Code: Select all

ptable_t *first_page_table = epalloc(sizeof(ptable_t));

    printf("Mapping pages to first table %x\n", first_page_table);
    
    for (address_t i = 0; i < PAGING_MAX_ENTRIES; i++)
    {
        //first_page_table= (i*0x1000)|PAGE_READ_WRITE|PAGE_PRESENT;
        first_page_table->pages[i] = (i * 0x1000) | PAGE_READ_WRITE | PAGE_PRESENT;
    }
    kdir.tables[0] = ((address_t)first_page_table) | PAGE_READ_WRITE | PAGE_PRESENT;
Second, I put that code outside to a new function, this is how it looks:

Code: Select all

void identity_paging(phys_t start, size_t end, uint8 flags, pdir_t * dir)
{
    address_t address;
    pindex_t pdiridx, ptabidx;
    ptable_t * table;
    ppage_t page;
    for(address = start; address < end; address+=0x1000){
        //check direntry is present
        pdiridx = get_direntry_index(address);
        table = dir->tables[pdiridx];
        if(!((address_t) table & TABLE_PRESENT)){
            //table = create_table_from_address(dir, address, flags);
            table = epalloc(sizeof(ptable_t));
            clear_page_table(table);
            dir->tables[pdiridx] = ((address_t)table) | TABLE_READ_WRITE | TABLE_PRESENT;
        }else{
            table = (address_t)table & TABLE_FRAME;
        }

        //now we have the table, we need to set the page
        ptabidx = get_tabentry_index(address);
        //page = table->pages[ptabidx];
        page = ((address_t) address & PAGE_FRAME) | (flags & PAGING_ENTRY_FLAGS);

        table->pages[ptabidx] = page;
        printf("Address: %x-Table: %x-Page: %x-Val: %x\n",address, table, ptabidx, page);


    }

}
This second code is where the problems appear... BUT, only if I map the first megabyte exclusively, if I map the whole kernel or something else, there is no problem at all. This is the caller of the function:

Code: Select all

identity_paging(0, 0x100000, (PAGE_PRESENT | PAGE_READ_WRITE), &kdir);
Below there are two screenshots of the result after the funtion returned. If you see, in one of them I show the directory entries value, and in the other the table entries(so the referenced address is 4k aligned, w/o flags).

Thank you very much, in advance.
Attachments
tab_entries.png
dir_entries.png
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Only Identity paging causes Triple Fault

Post by nexos »

The kernel must be be mapped in. If it is not mapped then there is a triple fault.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
NOOOCCCC
Posts: 11
Joined: Sat Nov 17, 2018 2:47 pm
Libera.chat IRC: blackburn

Re: Only Identity paging causes Triple Fault

Post by NOOOCCCC »

nexos wrote:The kernel must be be mapped in. If it is not mapped then there is a triple fault.

Did not know, maybe I missed it. Thank you very much.
NOOOCCCC
Posts: 11
Joined: Sat Nov 17, 2018 2:47 pm
Libera.chat IRC: blackburn

Re: Only Identity paging causes Triple Fault

Post by NOOOCCCC »

Triple Fault when enabling paging, part 2.

I followed the Higher Half page on the wiki and what I have got is a identity mapped first megabyte and the remaining addresses are mapped to the 0xC0000000 virtual address. So now the remaining addresses from 0x100000 to 0x13663C(where my kernel ends) are mapped to the #768 entry at my kernel directory. The pages value are {0x100003,0x101003,...,0x136003}.
I did not found any error or mistake with GDB, so I turned to bochs in order to get more verbose info(i think "-d" option of qemu does not worth it). With bochs, preventing the CPU from resetting(halting instead), I realized that the CR3 is correctly set, and there is a very interesting thing: CR2 register was pointing to the address 0x135e00... But why? this virtual address is mapped actually(checked serveral times). I can guess it is because my kernel tries to access that address as a virtual address(you know, table 0, page 0x135, 0xe00 bytes offset)... I am not sure, anyways.

This is the cpu state from bochs:

Code: Select all

00122661447i[CPU0  ] CPU is in protected mode (active)
00122661447i[CPU0  ] CS.mode = 32 bit
00122661447i[CPU0  ] SS.mode = 32 bit
00122661447i[CPU0  ] EFER   = 0x00000000
00122661447i[CPU0  ] | EAX=e0000011  EBX=00010000  ECX=0000001a  EDX=00121b3c
00122661447i[CPU0  ] | ESP=00131fa0  EBP=00131fc0  ESI=00000000  EDI=00000000
00122661447i[CPU0  ] | IOPL=0 id vip vif ac vm RF nt of df IF tf SF zf af PF cf
00122661447i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
00122661447i[CPU0  ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00122661447i[CPU0  ] |  DS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661447i[CPU0  ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661447i[CPU0  ] |  ES:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661447i[CPU0  ] |  FS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661447i[CPU0  ] |  GS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661447i[CPU0  ] | EIP=00107421 (00107421)
00122661447i[CPU0  ] | CR0=0xe0000011 CR2=0x00135e00
00122661447i[CPU0  ] | CR3=0x00130000 CR4=0x00000000
00122661447p[CPU0  ] >>PANIC<< exception(): 3rd (14) exception with no resolution
00122661447e[CPU0  ] WARNING: Any simulation after this point is completely bogus !
00122661448i[      ] Ctrl-C detected in signal handler.
00122661448i[      ] dbg: Quit
00122661448i[CPU0  ] CPU is in protected mode (in shutdown)
00122661448i[CPU0  ] CS.mode = 32 bit
00122661448i[CPU0  ] SS.mode = 32 bit
00122661448i[CPU0  ] EFER   = 0x00000000
00122661448i[CPU0  ] | EAX=e0000011  EBX=00010000  ECX=0000001a  EDX=00121b3c
00122661448i[CPU0  ] | ESP=00131fa0  EBP=00131fc0  ESI=00000000  EDI=00000000
00122661448i[CPU0  ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00122661448i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
00122661448i[CPU0  ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00122661448i[CPU0  ] |  DS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661448i[CPU0  ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661448i[CPU0  ] |  ES:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661448i[CPU0  ] |  FS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661448i[CPU0  ] |  GS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00122661448i[CPU0  ] | EIP=00107421 (00107421)
00122661448i[CPU0  ] | CR0=0xe0000011 CR2=0x00135e00
00122661448i[CPU0  ] | CR3=0x00130000 CR4=0x00000000
I am going to check some other things not related while I am waiting for a response. Thanks
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Only Identity paging causes Triple Fault

Post by nexos »

Is the value of EIP mapped?
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
NOOOCCCC
Posts: 11
Joined: Sat Nov 17, 2018 2:47 pm
Libera.chat IRC: blackburn

Re: Only Identity paging causes Triple Fault

Post by NOOOCCCC »

Yes, EIP value(physical) is mapped to 0xC0107421(table 301 has a correct entry).
NOOOCCCC
Posts: 11
Joined: Sat Nov 17, 2018 2:47 pm
Libera.chat IRC: blackburn

Re: Only Identity paging causes Triple Fault

Post by NOOOCCCC »

Wait... Do I need to jump to the new virtual address 0xC0....? If yes, how do I have to do the jump? Jump to some address in particular or long-jump to the current instruction? Because I make some stack operations with ebp as all regular C function(with gcc) does.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Only Identity paging causes Triple Fault

Post by nullplan »

Yes, you do need to jump. Also you need to reset your stack (stack pointer points to 1MB+something, right? That won't be mapped once you remove the identity mapping). So, one approach is to put all the code that runs before enabling paging in one section, and all the other code in another section. Link the first section to 1MB and the second one to 3GB. After creating the page tables, you reload ESP with the new virtual top of stack and jump to an entry symbol in the second section. Of course, you also need to relocate all the data you might need.

Far jumping is not usually needed. That is only needed to reload CS.
Carpe diem!
Post Reply