/* 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 . * * Valentin Verdier */ #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; } }