ELF Loading causes Triple Fault

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.
Post Reply
KrotovOSdev
Member
Member
Posts: 40
Joined: Sat Aug 12, 2023 1:48 am
Location: Nizhny Novgorod, Russia

ELF Loading causes Triple Fault

Post 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;
}
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: ELF Loading causes Triple Fault

Post 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?
Post Reply