OSDev.org

The Place to Start for Operating System Developers
It is currently Mon Apr 29, 2024 9:40 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Kernel triple faults when I dont map the first 261 pages?
PostPosted: Mon Oct 30, 2023 7:43 am 
Offline

Joined: Fri Jan 06, 2023 12:07 pm
Posts: 9
Hi!

I am adding paging to my small kernel, but I am encountering an issue that causes my kernel to triple fault and crash. If I don't identity-map the first 261 blocks (I have found this number through trial and error), the kernel crashes immediately after enabling paging. I have my paging code attached below.

Code:
void PageManager::initialize()
{
    PageManager* page_manager = PageManager::get();
    // 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
    page_manager->blocks = (uint8_t *)kmalloc(block_count / 8);
    memset(page_manager->blocks, 0, block_count / 8);

    // This is guaranteed to be physical memory, because we haven't enabled paging and initialized the heap yet.
    page_manager->m_page_directory = (Entry*)kmalloc(PAGE_DIRECTORY_SIZE*sizeof(Entry), true);
    for (int i = 0; i < 1024; i++)
    {
        page_manager->m_page_directory[i] = Entry{
            .present = 0,
            .read_write = 1,
            .user_supervisor = 0,
            .write_through = 0,
            .cache_disabled = 0,
            .accessed = 0,
            .reserved = 0,
            .page_size = 0,
            .global = 0,
            .available = 0,
            .page_table_base_address = 0
        };
    }
    // Map the first 768 blocks to themselves. This is up to the start of the kernel heap.
    // In this first section of section of memory we allocate stuff before we initialize the heap
    // and we have the page VGA text buffer.
    Entry page_directory_entry = page_manager->create_new_page_table(0);
    Entry *page_table = (Entry *)(page_directory_entry.page_table_base_address << 12);
    uint32_t current = 0;
    while(current <= 0x1000 * 261)
    {
        page_table[current>>12] = Entry{
            .present = 1,
            .read_write = 1,
            .user_supervisor = 1,
            .write_through = 0,
            .cache_disabled = 0,
            .accessed = 0,
            .reserved = 0,
            .page_size = 0,
            .global = 0,
            .available = 0,
            .page_table_base_address = current >> 12
        };
        current += 0x1000;
    }
    page_manager->enable_paging();
    TTY::get()->write("Enabled Paging!");
}

void PageManager::enable_paging()
{
    // Set location of page directory
    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::Entry PageManager::create_new_page_table(uint32_t index)
{
    // FIXME: Get the physical address of the allocated page table, even when heap
    // is initialized and paging is enabled.
    Entry *page_table_adress = (Entry *)kmalloc(PAGE_TABLE_SIZE * sizeof(Entry), true);
    for (int i = 0; i < 1024; i++)
    {
        page_table_adress[i] = Entry{
            .present = 0,
            .read_write = 1,
            .user_supervisor = 0,
            .write_through = 0,
            .cache_disabled = 0,
            .accessed = 0,
            .reserved = 0,
            .page_size = 0,
            .global = 0,
            .available = 0,
            .page_table_base_address = 0
        };
    }
    Entry page_table = Entry{
        .present = 1,
        .read_write = 1,
        .user_supervisor = 0,
        .write_through = 0,
        .cache_disabled = 0,
        .accessed = 0,
        .reserved = 0,
        .page_size = 0,
        .global = 0,
        .available = 0,
        .page_table_base_address = (uint32_t)page_table_adress >> 12
    };
    m_page_directory[index] = page_table;
    return page_table;
}


Notice the 261, which is the minimum number of pages on which the kernel runs. This is the output I get from QEMU:
Code:
     6: v=08 e=0000 i=0 cpl=0 IP=0008:001018ef pc=001018ef SP=0010:00105f18 env->regs[R_EAX]=80000011
EAX=80000011 EBX=00000010 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00001000 EBP=00105f28 ESP=00105f18
EIP=001018ef EFL=00000286 [--S--P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 000fffff 006f9300 DPL=0 DS   [-WA]
CS =0008 00000000 000fffff 006f9a00 DPL=0 CS64 [-R-]
SS =0010 00000000 000fffff 006f9300 DPL=0 DS   [-WA]
DS =0010 00000000 000fffff 006f9300 DPL=0 DS   [-WA]
FS =0010 00000000 000fffff 006f9300 DPL=0 DS   [-WA]
GS =0010 00000000 000fffff 006f9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00000004 00000031
IDT=     0000004a 000007ff
CR0=80000011 CR2=00105f14 CR3=00021000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000010 CCD=80000011 CCO=LOGICL
EFER=0000000000000000
check_exception old: 0x8 new 0xe


It crashes at the leave instruction of the enable_paging method.

Thank you in advance for the help! Let me know if you need more information, I am just really confused why this might be happening, as the encoding seems good.


Top
 Profile  
 
 Post subject: Re: Kernel triple faults when I dont map the first 261 pages
PostPosted: Mon Oct 30, 2023 8:21 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4597
Location: Chichester, UK
Hint: 261 decimal = 105 hexadecimal.

Look at ESP.


Top
 Profile  
 
 Post subject: Re: Kernel triple faults when I dont map the first 261 pages
PostPosted: Mon Oct 30, 2023 9:28 am 
Offline

Joined: Fri Jan 06, 2023 12:07 pm
Posts: 9
Ah, so I need to make sure that the stack is identity mapped, such that is preserved?
That seems clunky, there's surely a better solution, right? Also how do I know where the stack starts?


Top
 Profile  
 
 Post subject: Re: Kernel triple faults when I dont map the first 261 pages
PostPosted: Mon Oct 30, 2023 10:22 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4597
Location: Chichester, UK
You need to ensure that any memory you access is mapped (including memory-mapped devices). The stack doesn’t have to be identity mapped, but it must be mapped. If you map the memory to a different location you will need to adjust esp (and/or copy the stack to its new location). It’s not a good idea to do this within a subroutine so identity mapping (at this stage) is the best idea.

I doubt that you need to map all 261 pages (and it’s a good idea not to map page 0) but you must produce mappings for all code and data locations (including stacks) that your kernel uses.

You know where the stack starts because one of the first things your OS does is to set up the stack.


Top
 Profile  
 
 Post subject: Re: Kernel triple faults when I dont map the first 261 pages
PostPosted: Mon Oct 30, 2023 10:55 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
tommasopeduzzi wrote:
Ah, so I need to make sure that the stack is identity mapped, such that is preserved?

Pretty much, yeah. If you really wanted to, you could move the stack to a different physical address as long as it stays at the same virtual address.

tommasopeduzzi wrote:
That seems clunky, there's surely a better solution, right?

The better solution is to enable paging during a time when you don't need a stack. Usually this is in your bootloader somewhere, in the beginning of your kernel before you start calling C++ code, or in a stub kernel that sets up mappings for the real kernel.

tommasopeduzzi wrote:
Also how do I know where the stack starts?

If you set up your own stack, the stack is where you put it. If you're using the stack set up by the bootloader, it's wherever your bootloader put it (if your bootloader promises to set up a valid stack; GRUB will not set up a stack for you).

Also, a few things caught my eye in your first post...
Code:
     6: v=08

That's a double fault. You probably want to look at the previous exception to see what's wrong.

Code:
ES =0010 00000000 000fffff 006f9300 DPL=0 DS   [-WA]
CS =0008 00000000 000fffff 006f9a00 DPL=0 CS64 [-R-]

Your segment limits are too low. It looks like you miscounted and set the wrong bits in the flags byte (0x6F when it should be 0xCF). It only works for you because QEMU ignores segment limits.


Top
 Profile  
 
 Post subject: Re: Kernel triple faults when I dont map the first 261 pages
PostPosted: Wed Nov 01, 2023 2:03 am 
Offline

Joined: Fri Jan 06, 2023 12:07 pm
Posts: 9
Thank you both for the helpful replies. I completely forgot about having set up the stack, so fixing that issue was easy.


Last edited by tommasopeduzzi on Wed Nov 01, 2023 8:23 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Kernel triple faults when I dont map the first 261 pages
PostPosted: Wed Nov 01, 2023 2:15 am 
Offline

Joined: Fri Jan 06, 2023 12:07 pm
Posts: 9
Octocontrabass wrote:
That's a double fault. You probably want to look at the previous exception to see what's wrong.

Thanks for the hint. I will debug this after I fix the previously mentioned issue.

Octocontrabass wrote:
Your segment limits are too low. It looks like you miscounted and set the wrong bits in the flags byte (0x6F when it should be 0xCF). It only works for you because QEMU ignores segment limits.

Oh, I thought I checked that. Seems like I need to fix that too! Thanks!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot] and 27 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group