Issue with Program Loading

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.

Moderators: JAAman, klange, Octocontrabass, sortie, kmcguire, chase, thepowersgang, Owen, Combuster, AJ, 01000101, carbonBased, Candy, pcmattman

Post Reply
nexos
Member
Member
Posts: 1071
Joined: Tue Feb 18, 2020 3:29 pm
Freenode IRC: nexos

Issue with Program Loading

Post by nexos »

Hello,

I am currently making an operating system called NexOS, and am working a program loader that can load PE programs made by MinGW for Linux. It has an Image Base of 4MB. When i execute it, it page faults. Here is the program loading code:

Code: Select all

int entryPoint;
int stack;
extern void execute_internal();

int create_process(char* path)
{
    IMAGE_DOS_HEADER* dosHeader;
    IMAGE_NT_HEADERS* peHeader;
    int size;
    process* proc;
    pdirectory* addressSpace;

    void* buffer = read_file(path, &size);
    dosHeader =(IMAGE_DOS_HEADER*)buffer;
    if(dosHeader->e_magic != 0x5A4D)
    {
        return -1;
    }

    peHeader = (dosHeader->e_lfanew + (uint32_t)buffer);
    addressSpace = get_directory();
    proc = kernel_heap_alloc(sizeof(process));
    proc->addressSpace = addressSpace;
    proc->threads = kernel_heap_alloc(sizeof(thread) * 10);
    proc->threads[0].state.eip = peHeader->OptionalHeader.ImageBase + peHeader->OptionalHeader.AddressOfEntryPoint;
    proc->threads[0].state.eflags = 0x200;
    if(!(size & 0xFFFFF000))
    {
        size &= 0xFFFFF000;
        size += 0x1000;
    }
    for(int i = 0; i < size; i += 4096)
    {
        void* block = alloc_block();
        map_address(addressSpace, peHeader->OptionalHeader.ImageBase + i, (uint32_t)block, I86_PTE_PRESENT | I86_PTE_WRITABLE | I86_PTE_USER);
        memcpy(peHeader->OptionalHeader.ImageBase + i, buffer, 4096);
        buffer += 4096;
    }

    void* stackVirt = peHeader->OptionalHeader.ImageBase + peHeader->OptionalHeader.SizeOfImage + 4096;
    void* stackPhys = alloc_block();
    map_address(addressSpace, (uint32_t)stackVirt, (uint32_t)stackPhys, I86_PTE_PRESENT | I86_PTE_WRITABLE | I86_PTE_USER);
    proc->threads[0].stack = stackVirt;
    proc->threads[0].state.esp = (uint32_t)stackVirt;
    proc->threads[0].state.ebp = (uint32_t)stackVirt;

    entryPoint = proc->threads[0].state.eip;
    stack = proc->threads[0].state.esp;

    execute_internal();

    return 0;
}


The execute_internal function looks like this:

Code: Select all

extern entryPoint
extern stack

global execute_internal

execute_internal:
    cli
    mov ax, 0x23
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push 0x23
    mov eax, [stack]
    push eax
    push 0x200
    push 0x1b
    mov eax, [entryPoint]
    push eax
    iretd

The full source repo is at https://github.com/NexSuite/NexOS
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Gigasoft
Member
Member
Posts: 854
Joined: Sat Nov 21, 2009 5:11 pm

Re: Issue with Program Loading

Post by Gigasoft »

The initial stack pointer points to the beginning of the stack instead of the end.
nexos
Member
Member
Posts: 1071
Joined: Tue Feb 18, 2020 3:29 pm
Freenode IRC: nexos

Re: Issue with Program Loading

Post by nexos »

I changed that and it still page faults. The value in CR2 is 0x401000.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Octocontrabass
Member
Member
Posts: 5218
Joined: Mon Mar 25, 2013 7:01 pm

Re: Issue with Program Loading

Post by Octocontrabass »

Code: Select all

    if(!(size & 0xFFFFF000))
    {
        size &= 0xFFFFF000;
        size += 0x1000;
    }

That doesn't look right.
User avatar
eekee
Member
Member
Posts: 827
Joined: Mon May 22, 2017 5:56 am
Freenode IRC: eekee
Location: Hyperspace
Contact:

Re: Issue with Program Loading

Post by eekee »

@Octocontrabass: That's rounding up to the next 4KiB boundary.
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
nexos
Member
Member
Posts: 1071
Joined: Tue Feb 18, 2020 3:29 pm
Freenode IRC: nexos

Re: Issue with Program Loading

Post by nexos »

I changed it up a little. It now looks like:

Code: Select all

int entryPoint;
int stack;
extern void execute_internal();

int create_process(char* path)
{
    IMAGE_DOS_HEADER* dosHeader;
    IMAGE_NT_HEADERS* peHeader;
    int size;
    process* proc;
    pdirectory* addressSpace;

    void* buffer = read_file(path, &size);
    dosHeader =(IMAGE_DOS_HEADER*)buffer;
    if(dosHeader->e_magic != 0x5A4D)
    {
        return -1;
    }

    peHeader = (dosHeader->e_lfanew + (uint32_t)buffer);
    addressSpace = get_directory();
    proc = kernel_heap_alloc(sizeof(process));
    proc->addressSpace = addressSpace;
    proc->threads = kernel_heap_alloc(sizeof(thread)* 10);
    proc->threads[0].state.eip = peHeader->OptionalHeader.ImageBase + peHeader->OptionalHeader.AddressOfEntryPoint;
    proc->threads[0].state.eflags = 0x200;
    for(int i = 0; i < size; i += 4096)
    {
        void* block = alloc_block();
        map_address(addressSpace, peHeader->OptionalHeader.ImageBase + i, (uint32_t)block, I86_PTE_PRESENT | I86_PTE_WRITABLE | I86_PTE_USER);
        memcpy(peHeader->OptionalHeader.ImageBase + i, buffer, 4096);
        buffer += 4096;
    }

    void* stackVirt = peHeader->OptionalHeader.ImageBase + peHeader->OptionalHeader.SizeOfImage;
    void* stackPhys = alloc_block();
    map_address(addressSpace, (uint32_t)stackVirt, (uint32_t)stackPhys, I86_PTE_PRESENT | I86_PTE_WRITABLE | I86_PTE_USER);
    proc->threads[0].stack = stackVirt;
    proc->threads[0].state.esp = (uint32_t)stackVirt;
    asm("cli");
    switch_pdirectory(addressSpace);
    entryPoint = proc->threads[0].state.eip;
    stack = proc->threads[0].state.esp;
    void (*entry) () = (entryPoint);
    execute_internal();
    return 0;
}


and execute_internal is:

Code: Select all

extern entryPoint
extern stack

global execute_internal

execute_internal:
    mov ax, 0x23
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push 0x23
    lea eax, [stack]
    push eax
    push 0x200
    push 0x1b
    lea eax, [entryPoint]
    push eax
    iretd

I also tried compiling it under Visual Studio,
and yet it still page faults at address 0x-3FEF7754
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Octocontrabass
Member
Member
Posts: 5218
Joined: Mon Mar 25, 2013 7:01 pm

Re: Issue with Program Loading

Post by Octocontrabass »

eekee wrote:That's rounding up to the next 4KiB boundary.

Maybe that's what it's supposed to do, but that's not what it does.
User avatar
iansjack
Member
Member
Posts: 4602
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Issue with Program Loading

Post by iansjack »

Is

Code: Select all

0x12345678 & 0xfffff000
true or false?
User avatar
eekee
Member
Member
Posts: 827
Joined: Mon May 22, 2017 5:56 am
Freenode IRC: eekee
Location: Hyperspace
Contact:

Re: Issue with Program Loading

Post by eekee »

Oh of course! If it's meant to round up, the condition is wrong. Hmm...

Code: Select all

if(size & 0xFFFF)
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
User avatar
iansjack
Member
Member
Posts: 4602
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Issue with Program Loading

Post by iansjack »

Still not quite correct. What if size was 0x12345000?

This is where using a debugger is such a useful tool. You would have spotted the problem there as soon as you stepped through the relevant code. That's why I risk boring people (and upsetting some) who ask the community to debug their code by suggesting they learn how to use a debugger. Effort spent up front, with simple user programs, learning how to use gdb, or the like, effectively is the best investment you can make.
Last edited by iansjack on Sat Mar 21, 2020 5:03 am, edited 1 time in total.
User avatar
eekee
Member
Member
Posts: 827
Joined: Mon May 22, 2017 5:56 am
Freenode IRC: eekee
Location: Hyperspace
Contact:

Re: Issue with Program Loading

Post by eekee »

derp...

Knew I shouldn't have posted. I not has a brain today.
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
nexos
Member
Member
Posts: 1071
Joined: Tue Feb 18, 2020 3:29 pm
Freenode IRC: nexos

Re: Issue with Program Loading

Post by nexos »

I got it to run in kernel mode, but it won't run in user mode
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Gigasoft
Member
Member
Posts: 854
Joined: Sat Nov 21, 2009 5:11 pm

Re: Issue with Program Loading

Post by Gigasoft »

The PDEs must have the User bit set.
Post Reply