223 lines
6.0 KiB
C
223 lines
6.0 KiB
C
/* elf_loader.c - This file is a part of NutsOS
|
|
*
|
|
* NutsOS
|
|
* Copyright (C) 2013 Free Software Foundation, Inc.
|
|
*
|
|
* NutsOS is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* NutsOS is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with NutsOS; If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Valentin Verdier <valentin.verdier03@gmail.com>
|
|
*/
|
|
|
|
#define ELF_LOADER_PRIVATE
|
|
#include "elf_loader.h"
|
|
|
|
#include "types.h"
|
|
#include "print.h"
|
|
#include "utils.h"
|
|
#include "memory.h"
|
|
#include "process.h"
|
|
|
|
/* Index dans id[] */
|
|
#define ID_MAG_0 0
|
|
#define ID_MAG_1 1
|
|
#define ID_MAG_2 2
|
|
#define ID_MAG_3 3
|
|
#define ID_CLASS 4
|
|
#define ID_DATA 5
|
|
#define ID_VERSION 6
|
|
#define ID_PAD 7
|
|
|
|
/* Classes ELF */
|
|
#define ELF_CLASS_NONE 0
|
|
#define ELF_CLASS_32 1
|
|
#define ELF_CLASS_64 2
|
|
|
|
/* Encodage des données */
|
|
#define ELF_DATA_NONE 0
|
|
#define ELF_DATA_LSB 1
|
|
#define ELF_DATA_MSB 2
|
|
|
|
/* Types de fichier ELF */
|
|
#define ELF_TYPE_NONE 0
|
|
#define ELF_TYPE_RELOC 1
|
|
#define ELF_TYPE_EXEC 2
|
|
#define ELF_TYPE_DYN 3
|
|
#define ELF_TYPE_CORE 4
|
|
|
|
/* Version */
|
|
#define ELF_VERSION_NONE 0
|
|
#define ELF_VERSION_CURRENT 1
|
|
|
|
/* Architectures cible */
|
|
#define ELF_ARCH_NONE 0
|
|
#define ELF_ARCH_M32 1
|
|
#define ELF_ARCH_SPARC 2
|
|
#define ELF_ARCH_386 3
|
|
#define ELF_ARCH_68K 4
|
|
#define ELF_ARCH_88K 5
|
|
#define ELF_ARCH_860 7
|
|
#define ELF_ARCH_MIPS 8
|
|
#define ELF_ARCH_MIPS_RS4_BE 10
|
|
|
|
/* Structure de l'entête des fichier ELF32 */
|
|
typedef struct {
|
|
T_byte id[16];
|
|
T_word type;
|
|
T_word targetArch;
|
|
T_dword version;
|
|
T_dword entry;
|
|
T_dword prgHdrTblOff;
|
|
T_dword secHdrTblOff; /* Pas utilisé ici */
|
|
T_dword flags; /* Pas utilisé ici */
|
|
T_word hdrSize;
|
|
T_word prgHdrTblEntrySize;
|
|
T_word prgHdrTblEntryCount;
|
|
T_word secHdrTblEntrySize; /* Pas utilisé ici */
|
|
T_word secHdrTblEntryCount; /* Pas utilisé ici */
|
|
T_word strTblIndex; /* Pas utilisé ici */
|
|
}__attribute__((packed)) T_ELF32_hdr;
|
|
|
|
/* Types de segment */
|
|
#define ELF_SEG_NULL 0
|
|
#define ELF_SEG_LOAD 1
|
|
#define ELF_SEG_DYNAMIC 2
|
|
#define ELF_SEG_INTERP 3
|
|
#define ELF_SEG_NOTE 4
|
|
#define ELF_SEG_SHLIB 5
|
|
#define ELF_SEG_PHDR 6
|
|
|
|
/* Permissions R|W|X */
|
|
#define ELF_SEG_PERM_READ 4
|
|
#define ELF_SEG_PERM_WRITE 2
|
|
#define ELF_SEG_PERM_EXEC 1
|
|
|
|
/* Structure d'une entrée du Program header */
|
|
typedef struct {
|
|
T_dword type;
|
|
T_dword offset;
|
|
T_dword vaddr;
|
|
T_dword paddr;
|
|
T_dword sizeInFile;
|
|
T_dword sizeInMem;
|
|
T_dword flags;
|
|
T_dword align;
|
|
}__attribute__((packed)) T_ELF32_prgHdrEntry;
|
|
|
|
int ELF32_checkFile(void *file)
|
|
{
|
|
T_ELF32_hdr* elfHdr = file;
|
|
if(elfHdr->id[ID_MAG_0] != 0x7F || elfHdr->id[ID_MAG_1] != 'E' || elfHdr->id[ID_MAG_2] != 'L' || elfHdr->id[ID_MAG_3] != 'F') {
|
|
print("[ELF Loader] : The file at 0x%x is not ELF type\n", DEFAULT_COLOR, file);
|
|
return 0;
|
|
}
|
|
if(elfHdr->id[ID_CLASS] != ELF_CLASS_32) {
|
|
print("[ELF Loader] : The file at 0x%x is not a 32 bits ELF\n", DEFAULT_COLOR, file);
|
|
return 0;
|
|
}
|
|
if(elfHdr->id[ID_DATA] != ELF_DATA_LSB) {
|
|
print("[ELF Loader] : The ELF file at 0x%x has a bad encoding\n", DEFAULT_COLOR, file);
|
|
return 0;
|
|
}
|
|
if(elfHdr->type == ELF_TYPE_EXEC) {
|
|
print("[ELF Loader] : The ELF file at 0x%x is not executable\n", DEFAULT_COLOR, file);
|
|
return 0;
|
|
}
|
|
if(elfHdr->targetArch == ELF_ARCH_386) {
|
|
print("[ELF_Loader] : The ELF file at 0x%x is not a x86 executable\n", DEFAULT_COLOR, file);
|
|
return 0;
|
|
}
|
|
if(elfHdr->entry >= KERNEL_SPACE_SIZE) {
|
|
return 1;
|
|
} else {
|
|
print("[ELF_Loader] : The ELF file at 0x%x has a bad entry point\n", DEFAULT_COLOR, file);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
unsigned int ELF32_Load(void *file, T_LinkedList* regionsList)
|
|
{
|
|
if(ELF32_checkFile(file)) {
|
|
T_ELF32_hdr* elfHdr = file;
|
|
|
|
unsigned int i, sc;
|
|
for(i = 0, sc = 0; i < elfHdr->prgHdrTblEntryCount; i++, sc++) {
|
|
T_ELF32_prgHdrEntry* prgHdrEntry = file + elfHdr->prgHdrTblOff + i * elfHdr->prgHdrTblEntrySize;
|
|
|
|
if(prgHdrEntry->type == ELF_SEG_LOAD) {
|
|
if(!prgHdrEntry->sizeInMem) {
|
|
goto error;
|
|
}
|
|
|
|
T_Page segStartPage = prgHdrEntry->vaddr & 0xFFFFF000;
|
|
unsigned int pageCount = prgHdrEntry->sizeInMem & 0xFFFFF000;
|
|
if(prgHdrEntry->sizeInMem & 0x00000FFF) {
|
|
pageCount++;
|
|
}
|
|
if((prgHdrEntry->vaddr & 0x00000FFF) >= PAGE_SIZE - (prgHdrEntry->sizeInMem & 0x00000FFF)) {
|
|
pageCount++;
|
|
}
|
|
|
|
if(prgHdrEntry->flags == (ELF_SEG_PERM_READ | ELF_SEG_PERM_EXEC)) {
|
|
T_Page* pglist = malloc(sizeof(T_Page) * pageCount);
|
|
if(!pglist) {
|
|
goto error;
|
|
}
|
|
|
|
unsigned int j;
|
|
for(j = 0; j < pageCount; j++) {
|
|
pglist[j] = ((T_Page) file + prgHdrEntry->offset & 0xFFFFF000) + (j << PAGE_OFFSET_BITS);
|
|
}
|
|
|
|
if(!ProcessCreateRegion_RO(segStartPage, pglist, pageCount, regionsList)) {
|
|
free(pglist);
|
|
goto error;
|
|
}
|
|
free(pglist);
|
|
} else if(prgHdrEntry->flags == (ELF_SEG_PERM_READ | ELF_SEG_PERM_WRITE)) {
|
|
if(!ProcessCreateRegion_RW(segStartPage, pageCount, regionsList)) {
|
|
goto error;
|
|
}
|
|
|
|
unsigned int j;
|
|
for(j = 0; j < pageCount; j++) {
|
|
memcopy((char*) (((unsigned int) file + prgHdrEntry->offset & 0xFFFFF000) + (j << PAGE_OFFSET_BITS)),(char*) (segStartPage + (j << PAGE_OFFSET_BITS)), PAGE_SIZE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return elfHdr->entry;
|
|
|
|
error:
|
|
for(i = 0; i < sc; i++) {
|
|
T_ELF32_prgHdrEntry* prgHdrEntry = file + elfHdr->prgHdrTblOff + i * elfHdr->prgHdrTblEntrySize;
|
|
if(prgHdrEntry->type == ELF_SEG_LOAD) {
|
|
T_Page segStartPage = prgHdrEntry->vaddr & 0xFFFFF000;
|
|
unsigned int pageCount;
|
|
if(prgHdrEntry->sizeInMem & 0x00000FFF) {
|
|
pageCount = (prgHdrEntry->sizeInMem & 0xFFFFF000) + 1;
|
|
}
|
|
if(prgHdrEntry->align > 0) {
|
|
pageCount++;
|
|
}
|
|
|
|
ProcessRemoveRegion(segStartPage, pageCount, regionsList);
|
|
}
|
|
}
|
|
return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|