Newer
Older
UbixOS / sys / kernel / elf.c
/*-
 * Copyright (c) 2002-2018, 2022 The UbixOS Project.
 * All rights reserved.
 *
 * This was developed by Christopher W. Olsen for the UbixOS Project.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 * 1) Redistributions of source code must retain the above copyright notice, this list of
 *    conditions, the following disclaimer and the list of authors.
 * 2) Redistributions in binary form must reproduce the above copyright notice, this list of
 *    conditions, the following disclaimer and the list of authors in the documentation and/or
 *    other materials provided with the distribution.
 * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
 *    endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/elf.h>
#include <ubixos/sched.h>
#include <ubixos/kpanic.h>
#include <lib/kmalloc.h>
#include <vmm/vmm.h>
#include <lib/kprintf.h>
#include <string.h>


/*
 * Must document elf_load_file function
 *
 * return -1 if file not found
 */
int elf_load_file( kTask_t *p, const char *file, uint32_t *addr, uint32_t *entry ) {

	int ret		= 0;

	int i		= 0x0;
	int x		= 0x0;
	int numsegs	= 0x0;

	uint32_t base_addr = 0x0;
	uint32_t real_base_addr = 0x0;

	Elf32_Ehdr *binaryHeader = 0x0;
	Elf32_Phdr *programHeader = 0x0;

	fileDescriptor_t *exec_fd = 0x0;

	exec_fd = fopen(file, "r");

	if (exec_fd == 0x0) {

		return ( -1 );

	}

	/* Load the ELF header */
	if( ( binaryHeader = ( Elf32_Ehdr * ) kmalloc( sizeof( Elf32_Ehdr ) ) ) == 0x0 ) {

		K_PANIC( "malloc failed!" );

	}

	if( fread( binaryHeader, sizeof( Elf32_Ehdr ), 1, exec_fd ) != sizeof( Elf32_Ehdr ) ) {

		K_PANIC( "Error loading EHDR" );

	}

	/* Check if the loaded binary is an ELF binary */
	if( ( binaryHeader->e_ident[1] != 'E' ) && ( binaryHeader->e_ident[2] != 'L' ) && ( binaryHeader->e_ident[3] != 'F' ) ) {

		ret = -1;

		goto failed;

	}

	if( binaryHeader->e_type == ET_DYN ) {

		real_base_addr = *addr;

	}else if( binaryHeader->e_type == ET_EXEC ) {

		real_base_addr = 0x0;

	} else {

		ret = -1;

		goto failed;

	}

	/* Load The Program Header(s) */
	if( ( programHeader = ( Elf32_Phdr * ) kmalloc( sizeof( Elf32_Phdr ) * binaryHeader->e_phnum ) ) == 0x0 ) {

		K_PANIC( "malloc failed!" );

	}

    if( kern_fseek( exec_fd, binaryHeader->e_phoff, 0 ) != binaryHeader->e_phoff ) {

    	K_PANIC( "Failed to seek" );

    }

    /* Load program header */
    if( fread( programHeader, ( sizeof( Elf32_Phdr ) * binaryHeader->e_phnum ), 1, exec_fd ) != ( sizeof( Elf32_Phdr ) * binaryHeader->e_phnum ) ) {

    	K_PANIC( "Failed to load program header" );

    }

    for( numsegs = 0x0, i = 0x0; i < binaryHeader->e_phnum; i++ ) {

    	switch ( programHeader[i].p_type ) {

    		case PT_LOAD:
    			/*
				Allocate Memory Im Going To Have To Make This Load Memory With Correct
				Settings so it helps us in the future
    			*/

    			for( x = 0x0; x < ( programHeader[i].p_memsz + 0xFFF ); x += 0x1000 ) {

    				/* Make readonly and read/write */
    				if( vmm_remapPage( vmm_findFreePage( _current->id ), ( ( programHeader[i].p_vaddr & 0xFFFFF000 ) + x + real_base_addr ), PAGE_DEFAULT, _current->id, 0x0 ) == 0x0 ) {

    					K_PANIC("Error: Remap Page Failed");

    				}

    				memset( ( void * ) ( ( programHeader[i].p_vaddr & 0xFFFFF000 ) + x + real_base_addr ), 0x0, 0x1000 );

    			}

    			/* Now Load Section To Memory */
    			if( kern_fseek( exec_fd, programHeader[i].p_offset, 0 ) != programHeader[i].p_offset ) {

    				K_PANIC( "fseek failed" );

    			}

    			fread( ( void * ) programHeader[i].p_vaddr + real_base_addr, programHeader[i].p_filesz, 1, exec_fd );

    			if( ( programHeader[i].p_flags & 0x2 ) != 0x2 ) {

    				for( x = 0x0; x < ( programHeader[i].p_memsz ); x += 0x1000 ) {

    					if( ( vmm_setPageAttributes( ( programHeader[i].p_vaddr & 0xFFFFF000 ) + x + real_base_addr, PAGE_PRESENT | PAGE_USER ) ) != 0x0 ) {

    						K_PANIC( "vmm_setPageAttributes failed" );

    					}
    				}
    			}


    			if (numsegs == 0x0) {

    				base_addr = programHeader[i].p_vaddr + real_base_addr; //(programHeader[i].p_vaddr & 0xFFFFF000) + real_base_addr;

    			}

    			numsegs++;

    			break;

    	}

    }

    *addr = base_addr;

    *entry = binaryHeader->e_entry + real_base_addr;

    failed:

	/* Close The Open File */
	fclose( exec_fd );

	/* Free Binary Header Memory */
	if( binaryHeader != 0x0 ) {

		kfree( binaryHeader );

	}

	/* Free Program Header Memory */
	if (programHeader != 0x0) {

		kfree( programHeader );

	}

	return( ret );

}

const struct {

		char *elfTypeName;

		uInt32 id;

} elfType[] = { { "ET_NONE", 0 }, { "ET_REL", 1 }, { "ET_EXEC", 2 }, { "ET_DYN", 3 }, { "ET_CORE", 4 }, { "ET_LOPROC", 0xff00 }, { "ET_HIPROC", 0xffff }, };

const struct {

		char *phTypeName;

		uInt32 id;

} elfPhType[] = { { "PT_NULL", 0 }, { "PT_LOAD", 1 }, { "PT_DYNAMIC", 2 }, { "PT_INTERP", 3 }, { "PT_NOTE", 4 }, { "PT_SHLIB", 5 }, { "PT_PHDR", 6 }, { "PT_LOPROC", 0x70000000 }, { "PT_HIPROC", 0x7fffffff }, };

const struct {

		char *shTypeName;

		uInt32 id;

} elfShType[] = { { "SHT_NULL", 0 }, { "SHT_PROGBITS", 1 }, { "SHT_SYMTAB", 2 }, { "SHT_STRTAB", 3 }, { "SHT_RELA", 4 }, { "SHT_HASH", 5 }, { "SHT_DYNAMIC", 6 }, { "SHT_NOTE", 7 }, { "SHT_NOBITS", 8 }, { "SHT_REL", 9 }, { "SHT_SHLIB", 10 }, { "SHT_DYNSYM", 11 }, };

const struct {

		char *relTypeName;

		uInt32 id;

} elfRelType[] = { { "R_386_NONE", 0 }, { "R_386_32", 1 }, { "R_386_PC32", 2 }, { "R_386_GOT32", 3 }, { "R_386_PLT32", 4 }, { "R_386_COPY", 5 }, { "R_386_GLOB_DAT", 6 }, { "R_386_JMP_SLOT", 7 }, { "R_386_RELATIVE", 8 }, { "R_386_GOTOFF", 9 }, { "R_386_GOTPC", 10 }, };

char *elfGetShType( int shType ) {

	return( ( char * ) elfShType[shType].shTypeName );

}

char *elfGetPhType( int phType ) {

	return( ( char * ) elfPhType[phType].phTypeName );

}

char *elfGetRelType( int relType ) {

	return( ( char * ) elfRelType[relType].relTypeName );

}

/***
 END
 ***/