Page 1 of 1

Problem with activating paging

Posted: Sat Jan 14, 2023 3:07 pm
by tommasopeduzzi
Hello

I am very new to osdev, so please excuse if my problem arises from a complete lack of understanding.
I have read through a few resources and tried implementing paging in C++.

This is the relevant code:

Code: Select all

extern TTY tty;

uint32_t kmalloc_next_address = 0;
void *kmalloc(uint32_t size, bool align)
{
    if (align && (kmalloc_next_address & 0xFFFFF000))
    {
        // Align the address
        kmalloc_next_address &= 0xFFFFF000;
        kmalloc_next_address += 0x1000;
    }
    uint32_t tmp = kmalloc_next_address;
    kmalloc_next_address += size;
    return (void *)tmp;
}


void *kmalloc(uint32_t size)
{
    return kmalloc(size, false);
}

class PageManager {
public:
    PageManager();
    void map_next_free_block_to_page(uint32_t address);
    
private:
    void enable_paging();
    uint32_t* create_new_page_table(uint32_t index);
    
    uint8_t* blocks;
    void set_block(uint32_t address, bool used);

    uint32_t** m_page_directory;
    uint32_t current_page_directory_entry;
};

void PageManager::enable_paging()
{
    // Enable paging
    asm volatile("movl %0, %%cr3" ::"r"((uint32_t)m_page_directory));
    uint32_t cr0;
    asm volatile("movl %%cr0, %0"
                 : "=r"(cr0));
    cr0 |= 0x80000001; // enable paging, by setting bit 31 and bit 1
    asm volatile("movl %0, %%cr0" ::"r"(cr0));
}

PageManager::PageManager()
{
    // Assume we have 4GB of RAM (2^32 bytes), so we need 2^32 / 4096 = 2^21
    uint32_t block_count = 0x100000;
    // Divide by 8 because each byte represents 8 blocks
    blocks = (uint8_t *)kmalloc(block_count / 8);
    // TODO: Replace this with a memset
    for (int i = 0; i < block_count / 8; i++)
    {
        blocks[i] = 0;
    }

    m_page_directory = (uint32_t**)kmalloc(1024 * 4, true);
    for (int i = 0; i < 1024; i++)
    {
        m_page_directory[i] = (uint32_t *)2;
    }
    // Map the first 4MB of memory to the first 4MB of memory
    // This is so we can access the VGA text buffer
    uint32_t *page_table = create_new_page_table(0);
    for (int i = 0; i < 1024; i++)
    {
        page_table[i] = (uint32_t)((i * 0x1000) | 7); // attributes: user level, read/write, present.
        set_block(i * 0x1000, true);
    }
    enable_paging();
    tty.write("Page Manager Initialized");
    tty.write("Enabled Paging!");
}

uint32_t *PageManager::create_new_page_table(uint32_t index)
{
    // TODO: Make sure that the whole page table is mapped
    uint32_t *page_table = (uint32_t *)kmalloc(1024 * 4, true);
    for (int i = 0; i < 1024; i++)
    {
        page_table[i] = 2;
    }
    m_page_directory[index] = (uint32_t *)((uint32_t)page_table | 3);
    return page_table;
}
When I run this code, the VGA text output flickers very weirdly. When I don't enable paging, this doesn't happen and everything works perfectly.
Is there something that I am doing very wrong? I understand that identity mapping the first 4MB of RAM should keep the VGA buffer accesible.

Thank you in advance for the help!

Re: Problem with activating paging

Posted: Sat Jan 14, 2023 3:29 pm
by Octocontrabass

Code: Select all

uint32_t kmalloc_next_address = 0;

Code: Select all

    uint32_t tmp = kmalloc_next_address;

Code: Select all

    return (void *)tmp;
Null pointers are undefined behavior.

Have you checked to make sure your memory allocations are happening in memory that you aren't already using for something else?

Have you tried setting a breakpoint on the code that enables paging and stepping through it to see if it starts immediately misbehaving?

Have you tried examining your page tables using a virtual machine? For example, the QEMU monitor offers "info tlb" and "info mem" for describing the page tables.

Have you checked to see if any exceptions are occurring? QEMU (with hardware virtualization disabled) can log exceptions if you add "-d int" to your command line. You should also add "-no-reboot" to make it halt if the CPU triple faults.