Page 1 of 1

ELF Loading causes Triple Fault

Posted: Sun Mar 03, 2024 8:34 am
by KrotovOSdev
Hello!
I'm trying to load my first ELF as a GRUB module. I don't know why, but loading procedure throwing page fault, although I mapped all pages which contain my ELF.
So here is the code of my ELF loader:

Code: Select all

#include <stdint.h>
#include <stdbool.h>
#include <elf.h>

#include "../include/vmm.h"
#include "../include/pmm.h"

bool vefify_file(Elf32_Ehdr* hdr) {
    //map_page((uint32_t)hdr & ~(4095), (uint32_t)hdr & ~(4095), 0, page_directory);
    printf("%d\n", (uint32_t)hdr);
    
    printf("ox%x", vmem_translate(&(hdr), page_directory));
    /*while (1)
    {
        
    }
    */
    if (!hdr) return false;
    if (hdr->e_ident[EI_MAG0] != ELFMAG0 || hdr->e_ident[EI_MAG1] != ELFMAG1 || hdr->e_ident[EI_MAG2] != ELFMAG2 || hdr->e_ident[EI_MAG3] != ELFMAG3) return false;
    if (hdr->e_machine != EM_386 || hdr->e_machine != EM_X86_64) return false;
    if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) return false;
    if (hdr->e_type != ET_EXEC && hdr->e_type != ET_EXEC) return false;
    if (hdr->e_ident[EI_CLASS] != ELFCLASS32) return false;
    /*while (1)
    {
        
    }*/
    
    return false;
}

uint32_t get_entry_point(uint64_t kvaddr) {
    Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*)(uint32_t)kvaddr;
    if (!vefify_file(elf_hdr)) return 0;

    return elf_hdr->e_entry;
}

bool load_elf(uint64_t kvaddr, pd_entry_t* p_vas, bool user) {
    Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*)(uint32_t)kvaddr;
    printf("%d\n", kvaddr);
    if (!vefify_file((Elf32_Ehdr*)kvaddr)) return 1;

    for (uint16_t i = 0; i < elf_hdr->e_phnum; i++) {
        Elf32_Phdr* phdr = (Elf32_Phdr*)(elf_hdr->e_phoff + i);

        switch (phdr->p_type)
        {
        case 1:
            //load
            for (uint32_t j = phdr->p_vaddr; j < phdr->p_filesz; i += 4096) {
                uint32_t phys_page = (uint32_t)page_alloc(PAGE_SIZE);
                map_page(phys_page, j, user, p_vas);
                uint32_t kvirtpage = find_free_vpage(page_directory);
                map_page(phys_page, kvirtpage, 0, page_directory);
                kmemcpy((void*)((uint32_t)kvaddr + phdr->p_offset + j - phdr->p_vaddr), (void*)kvirtpage, (phdr->p_vaddr + phdr->p_filesz - j > 4096) ? 4096 : phdr->p_vaddr + phdr->p_filesz - j);
                unmap_page(kvirtpage, page_directory);
            }

            break;
        
        default:
            break;
        }
    }
}
Here is the code of ELF:

Code: Select all

section .text
    global _start

_start:
    ret
And, finally, this is the code of page fault handler which causes a page fault (idk why):

Code: Select all

void do_page_fault(exception_frame* context) {
    //TODO: add process page fault handler
    uint32_t fault_addr;

    asm volatile ("mov %%cr2, %0" : "=r" (fault_addr));

    uint16_t pd_index = (fault_addr >> 22) & 0x3FF;
    uint16_t pt_index = (fault_addr >> 12) & 0x3FF;

    if (!*((pmem_bitmap + (vmem_translate(fault_addr, page_directory) / PAGE_SIZE))) && context->error_code >> 1 & 0x1) {
        do_exception(context);
    }

    if (context->error_code & 0x1) {
        do_exception(context);
    }

    if (fault_addr > 0xFFFFFFFF) {
        do_exception(context);
    }
    
    map_page(fault_addr & ~(4095), fault_addr & ~(4095), (context->error_code >> 2) & 1, page_directory);
}
I'm totally sure that map_page works fine because I've already used it in the kernel. But if it's needed, here is the code of map_page():

Code: Select all

void map_page(uint64_t phys_addr, uint64_t virt_addr, bool user, pd_entry_t* pd) {
    uint16_t pd_index = (virt_addr >> 22) & 0x3FF;
    uint16_t pt_index = (virt_addr >> 12) & 0x3FF;

    if (phys_addr & 0xFFF) {
        printf("Cannot map page (virt=%x, phys=%x)\n", virt_addr, phys_addr);

        return;
    }

    pt_entry_t* pt;
    if ((pd + pd_index)->frame == 0) {

        pt = create_pt();

        for (uint16_t i = 0; i < 1024; i++) {
            (pt + i)->frame = 0;
        }
        
        (pd + pd_index)->frame = (uint32_t)pt >> 12;
    }
    else pt = (pt_entry_t*)((pd + pd_index)->frame << 12);

    (pd + pd_index)->present = 1;
    (pd + pd_index)->rw = 1;
    (pd + pd_index)->user = user;
    (pd + pd_index)->pwt = 1;
    (pd + pd_index)->pcd = 0;
    (pd + pd_index)->accessed = 0;
    (pd + pd_index)->ps = 0;

    (pd + pd_index)->unused = 0;
    (pd + pd_index)->unused2 = 0;

    (pt + pt_index)->present = 1;
    (pt + pt_index)->rw = 1;
    (pt + pt_index)->user = user;
    (pt + pt_index)->pwt = 1;
    (pt + pt_index)->pcd = 0;
    (pt + pt_index)->accessed = 0;
    (pt + pt_index)->pat = 0;
    (pt + pt_index)->global = 0;

    (pt + pt_index)->unused = 0;

    (pt + pt_index)->frame = phys_addr >> 12;
}

Re: ELF Loading causes Triple Fault

Posted: Sun Mar 03, 2024 5:56 pm
by Octocontrabass
More information about the page fault would be helpful. What were the values of EIP, CR2, and the error code? Which part of your code does EIP point to? Is CR2 a reasonable address for that code to be accessing?