Triple fault when enabling paging

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.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Triple fault when enabling paging

Post by osdever »

Sorry if my code is completely wrong, I'm not familiar with Paging.
Code is triple-faulting on setting bit in CR0.
Here's my code:

Code: Select all

//paging.c
#include "../../../include/arch/i686/paging.h"

#include <stdint.h>
#include <stddef.h>

#include "../../../include/stdio.h"

page_directory_t pgdir[1024] __attribute__((aligned(4096)));
page_table_t     pgtbl[1024] __attribute__((aligned(4096)));

void setup_pgdir(page_directory_t pgdir[1024])
{
    for(int i=0; i<1024; i++)
    {
        //Those page directory entries AREN'T USABLE. It just fills all page directory by not present page tables.
        pgdir[i].present    = 0;
        pgdir[i].rw_flag    = 1;
        pgdir[i].access_lvl = 0;
    }
}

void paging_ident(uint32_t* tbl)
{
    size_t size=4096*1024;
    uint32_t from=0x0;
    //Code from OSDev.org.
    from &= 0xfffff000; // discard bits we don't want
    for(;size>0;from+=4096,size-=4096,tbl++)
    {
        *tbl=from|1;     // mark page present.
    }
}

void setup_paging()
{
    void load_pg_dir(uint32_t*);
    void paging_enable(void);
    setup_pgdir(pgdir);
    paging_ident((uint32_t*)pgtbl);
    load_pg_dir((uint32_t*)pgdir);
    paging_enable();
}
//paging.h
#ifndef PAGING_H
#define PAGING_H

typedef struct page_directory_t page_directory_t;
typedef struct page_table_t page_table_t;

struct page_directory_t
{
    int present       : 1;
    int rw_flag       : 1;
    int access_lvl    : 1; //0 is for only ring0. 1 is for anybody.
    int write_through : 1;
    int cache_off     : 1;
    int accessed      : 1;
    int zero          : 1;
    int page_size     : 1;
    int reserved      : 3;
    int tbl_addr      : 21;
};

struct page_table_t
{
    int present       : 1;
    int rw_flag       : 1;
    int access_lvl    : 1; //0 is for only ring0. 1 is for anybody.
    int cache_off     : 1;
    int accessed      : 1;
    int dirty         : 1;
    int zero          : 1;
    int global        : 1;
    int reserved      : 3;
    int tbl_addr      : 21;
};

void load_page_directory(page_directory_t);

#endif // PAGING_H
//paging.asm
global load_pg_dir
load_pg_dir: 
        ; Loaging page directory.
	push ebp
	mov ebp, esp
	mov eax, [esp+8]
	mov cr3, eax
	mov esp, ebp
	pop ebp
	ret
global paging_enable
paging_enable: ; Enable the paging by setting bit in CR0.
	push ebp
	mov ebp, esp
	mov eax, cr0
	or eax, 0x80000000
	mov cr0, eax ; Here it crashes, noo :(
	mov esp, ebp
	pop ebp
	ret
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Triple fault when enabling paging

Post by iansjack »

You should set a breakpoint just before enabling paging. Then use your debugger to examine your Page Table to see that it contains the entries you expect it to.
User avatar
Nutterts
Member
Member
Posts: 159
Joined: Wed Aug 05, 2015 5:33 pm
Libera.chat IRC: Nutterts
Location: Drenthe, Netherlands

Re: Triple fault when enabling paging

Post by Nutterts »

A page table entry for protected mode is a 32bit value. I just skimmed your code and as far as I can see your code creates entries as a struct that's 40 bytes in size.

You either want to change your structs to use bool and be packed or more reliably use macros to create the entry you want. Below is what I use to create a pml4 entry. It's for 64bit tho but the principle is the same.

Code: Select all

#define MAKE_PML4E(base, avl, pcd, pwt, us, rw, p) \
  (uint64_t)( \
  (base << 12) | \
  (avl << 9) | \
  (pcd << 4) | \
  (pwt << 3) | \
  (us << 2) | \
  (rw << 1) | \
  p)
There are also some other issues so you might want to grab a cup of coffee and read the relevant part of the Intel docs again. The accessed bit is best set to zero on creation for example. Also unless 32bit paging is way different then 64bit the caching bit only selects between write-through and write-back, it doesn't disable caching as a whole.
"Always code as if the guy who ends up maintaining it will be a violent psychopath who knows where you live." - John F. Woods

Failed project: GoOS - https://github.com/nutterts/GoOS
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Triple fault when enabling paging

Post by neon »

A page table entry for protected mode is a 32bit value. I just skimmed your code and as far as I can see your code creates entries as a struct that's 40 bytes in size.
Slight correction here - his structures would be 32 bits on any sane compiler that implements bit fields properly.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Nutterts
Member
Member
Posts: 159
Joined: Wed Aug 05, 2015 5:33 pm
Libera.chat IRC: Nutterts
Location: Drenthe, Netherlands

Re: Triple fault when enabling paging

Post by Nutterts »

neon wrote:
A page table entry for protected mode is a 32bit value. I just skimmed your code and as far as I can see your code creates entries as a struct that's 40 bytes in size.
Slight correction here - his structures would be 32 bits on any sane compiler that implements bit fields properly.
At the moment he's defining every member in his structs as an int.
"Always code as if the guy who ends up maintaining it will be a violent psychopath who knows where you live." - John F. Woods

Failed project: GoOS - https://github.com/nutterts/GoOS
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Triple fault when enabling paging

Post by neon »

Right, and under the assumption that sizeof(int) = 32 bits, the bit fields he creates would be 32 bits in size. I.e. he is using bit fields - he is not defining a normal structure. If he was not using bit fields, you would be right.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Nutterts
Member
Member
Posts: 159
Joined: Wed Aug 05, 2015 5:33 pm
Libera.chat IRC: Nutterts
Location: Drenthe, Netherlands

Re: Triple fault when enabling paging

Post by Nutterts »

neon wrote:I.e. he is using bit fields - he is not defining a normal structure. If he was not using bit fields, you would be right.
You're absolutely right. Ignore what I said. But that makes me wonder even more whats wrong with it.
"Always code as if the guy who ends up maintaining it will be a violent psychopath who knows where you live." - John F. Woods

Failed project: GoOS - https://github.com/nutterts/GoOS
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Triple fault when enabling paging

Post by neon »

catnikita255 - Your code is incomplete. Most importantly, paging_ident doesn't completely identity map the space you want. Think of it from the perspective of the cpu, given only the page directory, how can it find your page table when you marked all of its entries as non-usable? In fact, I don't see anywhere where you set tbl_addr which should store the page frame number.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Triple fault when enabling paging

Post by osdever »

neon wrote:catnikita255 - Your code is incomplete. Most importantly, paging_ident doesn't completely identity map the space you want. Think of it from the perspective of the cpu, given only the page directory, how can it find your page table when you marked all of its entries as non-usable? In fact, I don't see anywhere where you set tbl_addr which should store the page frame number.
Oh, I realized it before you. Here's an updated code:

Code: Select all

#include "../../../include/arch/i686/paging.h"

#include <stdint.h>
#include <stddef.h>

#include "../../../include/stdio.h"

// DEPRECATED
page_directory_t pgdir[1024] __attribute__((aligned(4096)));
page_table_t     pgtbl[1024] __attribute__((aligned(4096)));

void setup_pgdir(page_directory_t pgdir[1024])
{
    for(int i=0; i<1024; i++)
    {
        //Those page directory entries AREN'T USABLE. It just fills all page directory by not present page tables.
        pgdir[i].present    = 0;
        pgdir[i].rw_flag    = 1;
        pgdir[i].access_lvl = 0;
    }
}

void paging_ident(page_table_t *tbl)
{
    //Identity map first 4 megabytes of memory.
    size_t size=1024;
    uint32_t mem=0x0;
    for(size_t i=0; i<size; i++, mem+=PAGE_SIZE)
    {
        tbl[i].rw_flag   =1;
        tbl[i].access_lvl=0;
        tbl[i].phys_addr =mem;
        tbl[i].cache_off =1;
        tbl[i].present =1;

    }
}

void setup_paging()
{
    void load_pg_dir(page_directory_t *);
    void paging_enable(void);
    setup_pgdir(pgdir);
    paging_ident(pgtbl);
    pgdir[0].tbl_addr=pgtbl;
    pgdir[0].present    = 1;
    load_pg_dir(pgdir);
    paging_enable();
}
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Triple fault when enabling paging

Post by neon »

Hello,

I have to assume the code does not work. tbl_addr stores a page frame number not an address. For example, something like pgdir[0].tbl_addr = pgtbl >> 12; should work. I don't quite know what tbl.phys_addr is since its not in the original post, however the same concept applies to the page directory tbl_addr field here. Although in this case you can actually just do "tbl.phys_addr = i" assuming phys_addr = tbl_addr.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Triple fault when enabling paging

Post by osdever »

neon wrote:Hello,

I have to assume the code does not work. tbl_addr stores a page frame number not an address. For example, something like pgdir[0].tbl_addr = pgtbl >> 12; should work. I don't quite know what tbl.phys_addr is since its not in the original post, however the same concept applies to the page directory tbl_addr field here. Although in this case you can actually just do "tbl.phys_addr = i" assuming phys_addr = tbl_addr.

phys_addr is a renamed tbl_addr in page_table_t. And it doesn't have anything about table address or index, I forgot to rename it.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Triple fault when enabling paging

Post by osdever »

Is anybody here?
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Triple fault when enabling paging

Post by iansjack »

Have you examined your page table yet to verify it is correct?
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Triple fault when enabling paging

Post by osdever »

iansjack wrote:Have you examined your page table yet to verify it is correct?
My page directory in 32-bit unsigned integer is 0x9b800003, the page table is 0x00137000. Looks like everything's correct.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Triple fault when enabling paging

Post by iansjack »

Your page directory is at a physical address higher than 2GB, and the page table address is much lower in physical memory (just above the 1MB mark)? That just doesn't feel right. I don't know how you are assigning physical pages but I would guess that most people assign the lowest available page first.

Without going in to the full details of how you are managing your pages I just have the gut feeling that your page table is screwed up.
Post Reply