Page 1 of 1

Problem with paging (Triple fault)

Posted: Sat Aug 12, 2023 2:22 am
by KrotovOSdev
Hello forum!
I'm new to OS development and now I'm developing my first OS. I've already implemented simple exception handler and now I'm trying to implement paging. I have decided to start with Identity Paging but for all memory because I have to enable paging for future multitasking, but still want to control memory same as before. So I wrote a simple function for Identify Paging. Here is the code:

Code: Select all

#define PAGE_SIZE 4 // given in kilobytes

extern void panic(char* error);

typedef struct {
    uint32_t address : 20; // 4 KiB aligned adress of PT
    uint16_t avl : 4; // available
    uint8_t flags : 8; // 5th bit is available
} __attribute__((packed)) pd_entry_t;

typedef struct {
    uint32_t address : 20; // 4 KiB aligned adress of PT
    uint8_t avl : 3; // available
    uint16_t flags : 9; // flags
} __attribute__((packed)) pt_entry_t;

uint32_t get_memory_size(multiboot_info_t* mbd) {
    uint32_t lower = mbd->mem_lower;
    uint32_t higher = mbd->mem_upper;
    return lower + higher;
}

void init_paging(multiboot_info_t* mbd) {
    uint32_t total_memory = get_memory_size(mbd);
    if (total_memory < 16384) {
        panic("At least 16Mb of RAM required to run operating system.");
    }

    if (total_memory > 4194303) {
        total_memory = 4194303;
    }
    
    /*extern uint32_t _end;
    uint32_t kernel_end_addr = (uint32_t)&_end;
    kernel_end_addr = (kernel_end_addr + 4095) & ~4095;*/

    pd_entry_t page_directory[1024] __attribute__((aligned(4096)));
    pt_entry_t page_table[(total_memory + PAGE_SIZE - 1) / PAGE_SIZE] __attribute__((aligned(4096)));
    
    uint16_t pd_index;
    uint16_t pt_index;
    uint32_t phys_addr;
    uint32_t pt_addr;

    for (uint32_t i = 0; i < total_memory; i += PAGE_SIZE)
    {
        phys_addr = i * 1024;
        
        pd_index = phys_addr >> 22;
        pt_index = phys_addr >> 12 & 0x03FF;

        if ((phys_addr & 0xFFF))
        {
            printf("0x%x ", phys_addr);
            panic("Adress cannot be aligned at 4 KB.");
        }
        
        pt_addr = (uint32_t)(&page_table[pd_index * 1024]);

        if ((pt_addr & 0xFFF))
        {
            printf("0x%x ", pt_addr);
            panic("Adress cannot be aligned at 4 KB.");
        }

        page_directory[pd_index].address = pt_addr >> 12;
        page_directory[pd_index].avl = 0;
        page_directory[pd_index].flags = 0b11010000;

        page_table[pd_index * 1024 + pt_index].address = phys_addr >> 12;
        page_table[pd_index * 1024 + pt_index].avl = 0;
        page_table[pd_index * 1024 + pt_index].flags = 0b110100000;
    }

    uint32_t pd_address = (uint32_t)page_directory;

    asm volatile ("mov %0, %%cr3" : : "r" (pd_address) : "memory");
    //asm volatile ("mov %%cr0, %%eax; or $0x80000000, %%eax; mov %%eax, %%cr0" : :);
    //for(;;);

    printf("Paging enabled (1:1, Page Directory = 0x%x)", pd_address);
}
:(
But... this function is not working properly. Once I write PG bit to CR0, I get a Triple Fault. GDB tells me that my code doesn't even switch to next instruction and instantly resets I also know that page fault happens before reset (CR2 register != 0) but have no idea why. Can someone help me with explanation about what happens here? Or maybe Identify Paging for all memory is not needed and different memory models can be used.
Thank you for your reply.

Re: Problem with paging (Triple fault)

Posted: Sat Aug 12, 2023 9:58 pm
by davmac314
I have only given a quick glance. I doubt this is the only problem but:

Code: Select all

uint32_t get_memory_size(multiboot_info_t* mbd) {
    uint32_t lower = mbd->mem_lower;
    uint32_t higher = mbd->mem_upper;
    return lower + higher;
}
That isn't right, if you're trying to calculate the highest possible address, which is what you appear to treat the returned value as. From the spec:
Lower memory starts at address 0, and upper memory starts at address 1 megabyte
I.e. the return should be mem_upper + 1MB, the lower memory amount doesn't even enter the equation. However I should add that using these is over-simplistic anyway, you should really use the full memory map (although I guess you could use these values just to get started). Note that:
The value returned for upper memory is maximally the address of the first upper memory hole minus 1 megabyte. It is not guaranteed to be this value.
I.e. mem_upper only goes so far as the first memory hole and might not even go that far, so it may report far less memory than is actually available.

Re: Problem with paging (Triple fault)

Posted: Sat Aug 12, 2023 10:06 pm
by davmac314
Ok this is more likely to be the main problem:

Code: Select all

    pt_entry_t page_table[(total_memory + PAGE_SIZE - 1) / PAGE_SIZE] __attribute__((aligned(4096)));
Your page table array is a local variable which means that (a) you're allocating the whole thing on the stack which is probably going to overflow it and (b) it will become invalid once you return from the function. Same issue with the page directory.

Re: Problem with paging (Triple fault)

Posted: Sat Aug 12, 2023 10:15 pm
by davmac314
Oh and finally:

Code: Select all

typedef struct {
    uint32_t address : 20; // 4 KiB aligned adress of PT
    uint16_t avl : 4; // available
    uint8_t flags : 8; // 5th bit is available
} __attribute__((packed)) pd_entry_t;
Isn't that back-to-front? The address should be the upper 20 bits IIRC.

Re: Problem with paging (Triple fault)

Posted: Sun Aug 13, 2023 9:27 am
by KrotovOSdev
I'm going to check later today. I'll notify you about the results. :)

Re: Problem with paging (Triple fault)

Posted: Sun Aug 13, 2023 9:58 am
by KrotovOSdev
Or maybe I don't have to use Identify Paging for all memory. Maybe I can do it only for first n megabytes and use remaining memory for heap and allocating programs and map them only in case of request or page fault.
What do you think is the best memory model?

Re: Problem with paging (Triple fault)

Posted: Sun Aug 13, 2023 1:37 pm
by Octocontrabass
KrotovOSdev wrote:What do you think is the best memory model?
"Best" is very subjective, but at least in my opinion, don't identity-map anything. Use paging to put your kernel somewhere in the upper half of the virtual address space and dynamically map memory as you need it.

Re: Problem with paging (Triple fault)

Posted: Sun Aug 13, 2023 2:54 pm
by KrotovOSdev
davmac314 wrote:Oh and finally:

Code: Select all

typedef struct {
    uint32_t address : 20; // 4 KiB aligned adress of PT
    uint16_t avl : 4; // available
    uint8_t flags : 8; // 5th bit is available
} __attribute__((packed)) pd_entry_t;
Isn't that back-to-front? The address should be the upper 20 bits IIRC.
Octocontrabass wrote:
KrotovOSdev wrote:What do you think is the best memory model?
"Best" is very subjective, but at least in my opinion, don't identity-map anything. Use paging to put your kernel somewhere in the upper half of the virtual address space and dynamically map memory as you need it.
Thank you for your replies, I did everything that you recommended to do but I still get a Triple Fault.
According to you recommendations, I've deleted my old code and wrote a new one. I started with Setting Up Paging tutorial and everything worked fine until I changed int type of page_directory to my structure. Once I do that, problem returns. I think that array of structures != array of integers with same size. Am I right?

Code: Select all

typedef struct {
    uint32_t present : 1;  
    uint32_t rw : 1;      
    uint32_t user : 1;    
    uint32_t pwt : 1;  
    uint32_t pcd : 1; 
    uint32_t accessed : 1;     
    uint32_t unused : 1;
    uint32_t ps : 1;
    uint32_t unused2 : 4; 
    uint32_t frame : 20; 
} __attribute__((packed)) pd_entry_t;

This is a code for pd_entry.

Re: Problem with paging (Triple fault)

Posted: Sun Aug 13, 2023 3:19 pm
by Octocontrabass
KrotovOSdev wrote:I think that array of structures != array of integers with same size. Am I right?
No, they're the same. It sounds like the problem is the values you're placing in those structures. You're initializing every field, right?

Your virtual machine may be able to give you more information about the cause of the exception.

Re: Problem with paging (Triple fault)

Posted: Mon Aug 14, 2023 6:55 am
by KrotovOSdev
Octocontrabass wrote:
KrotovOSdev wrote:I think that array of structures != array of integers with same size. Am I right?
No, they're the same. It sounds like the problem is the values you're placing in those structures. You're initializing every field, right?

Your virtual machine may be able to give you more information about the cause of the exception.
I found a problem. I forgot to do the rightshift >> for address.