From d95ad83dd0bfb3a8f6919f93ce5ead77a5905421 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 17 Jan 2010 18:24:22 +0800 Subject: [PATCH] Adding PE file support - Also added binary register function (now modules can handle binary files) --- Kernel/Makefile | 2 +- Kernel/Makefile.BuildNum | 2 +- Kernel/bin/pe.c | 236 +++++++++++++++++++++++++++++++++++++++ Kernel/bin/pe.h | 136 ++++++++++++++++++++++ Kernel/binary.c | 42 +++++-- Kernel/include/binary.h | 15 +++ 6 files changed, 421 insertions(+), 12 deletions(-) create mode 100644 Kernel/bin/pe.c create mode 100644 Kernel/bin/pe.h diff --git a/Kernel/Makefile b/Kernel/Makefile index 279f251d..8593d6fb 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -27,7 +27,7 @@ endif OBJ = $(addprefix arch/$(ARCHDIR)/,$(A_OBJ)) OBJ += heap.o messages.o debug.o modules.o lib.o syscalls.o system.o threads.o drvutil.o -OBJ += binary.o bin/elf.o +OBJ += binary.o bin/elf.o bin/pe.o OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o vfs/memfile.o vfs/nodecache.o OBJ += vfs/fs/root.o vfs/fs/devfs.o OBJ += $(addprefix vfs/fs/, $(addsuffix .o,$(FILESYSTEMS))) diff --git a/Kernel/Makefile.BuildNum b/Kernel/Makefile.BuildNum index e85c4e56..b0b7558c 100644 --- a/Kernel/Makefile.BuildNum +++ b/Kernel/Makefile.BuildNum @@ -1 +1 @@ -BUILD_NUM = 1359 +BUILD_NUM = 1368 diff --git a/Kernel/bin/pe.c b/Kernel/bin/pe.c new file mode 100644 index 00000000..aa83ac9f --- /dev/null +++ b/Kernel/bin/pe.c @@ -0,0 +1,236 @@ +/* + * Acess v1 + * Portable Executable Loader + */ +#define DEBUG 1 +#include +#include +#include +#include "pe.h" + +// === PROTOTYPES === + int PE_Install(char **Arguments); +tBinary *PE_Load(int fp); +tBinary *MZ_Open(int fp); + int PE_Relocate(void *Base); + int PE_GetSymbol(void *Base, char *Name, Uint *Ret); + +// === GLOBALS === +MODULE_DEFINE(0, 0x0032, BinPE, PE_Install, NULL, NULL); +char *gsPE_DefaultInterpreter = "/Acess/Libs/ld-acess.so"; +tBinaryType gPE_Loader = { + NULL, + ('M'|('Z'<<8)), 0xFFFF, // 'MZ' + "PE/DOS", + PE_Load, PE_Relocate, PE_GetSymbol + }; + +// === CODE === +int PE_Install(char **Arguments) +{ + Binary_RegisterType(&gPE_Loader); + return 1; +} + +/** + * \brief Loads a PE Binary + */ +tBinary *PE_Load(int FP) +{ + int count, i, j, k; + int iPageCount; + tBinary *ret; + tPE_DOS_HEADER dosHdr; + tPE_IMAGE_HEADERS peHeaders; + tPE_SECTION_HEADER *peSections; + char namebuf[9] = {0}; + Uint iFlags, iVA; + + ENTER("xFP", FP); + + // Read DOS header and check + VFS_Read(FP, sizeof(tPE_DOS_HEADER), &dosHdr); + if( dosHdr.Ident != ('M'|('Z'<<8)) ) { + LEAVE('n'); + return NULL; + } + + // - Read PE Header + VFS_Seek(FP, dosHdr.PeHdrOffs, SEEK_SET); + if( VFS_Tell(FP) != dosHdr.PeHdrOffs ) { + ret = MZ_Open(FP); + LEAVE('p', ret); + return ret; + } + VFS_Read(FP, sizeof(tPE_IMAGE_HEADERS), &peHeaders); + + // - Check PE Signature and pass on to the MZ Loader if invalid + if( peHeaders.Signature != (('P')|('E'<<8)) ) { + ret = MZ_Open(FP); + LEAVE('p', ret); + return ret; + } + + // Read Sections (Uses `count` as a temp variable) + count = sizeof(tPE_SECTION_HEADER) * peHeaders.FileHeader.SectionCount; + peSections = malloc( count ); + if(!peSections) + { + Warning("PE_Load - Unable to allocate `peSections`, 0x%x bytes", count); + LEAVE('n'); + return NULL; + } + VFS_Read(FP, count, peSections); + + // Count Pages + iPageCount = 1; // 1st page is headers + for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ ) + { + // Check if the section is loadable + // (VA is zero in non-loadable sections) + if(peSections[i].RVA + peHeaders.OptHeader.ImageBase == 0) continue; + + // Moar pages + iPageCount += (peSections[i].VirtualSize + 0xFFF) >> 12; + } + + LOG("%i Pages", iPageCount); + + // Initialise Executable Information + ret = malloc(sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount); + + ret->Entry = peHeaders.OptHeader.EntryPoint + peHeaders.OptHeader.ImageBase; + ret->Base = peHeaders.OptHeader.ImageBase; + ret->Interpreter = gsPE_DefaultInterpreter; + ret->NumPages = iPageCount; + + LOG("Entry=%p, BaseAddress=0x%x\n", ret->Entry, ret->Base); + + ret->Pages[0].Virtual = peHeaders.OptHeader.ImageBase; + ret->Pages[0].Physical = 0; + ret->Pages[0].Size = 4096; + ret->Pages[0].Flags = 0; + + // Parse Sections + j = 1; // Page Index + for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ ) + { + iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase; + + // Skip non-loadable sections + if(iVA == 0) continue; + + // Create Name Buffer + memcpy(namebuf, peSections[i].Name, 8); + LOG("Section %i '%s', iVA = %p", i, namebuf, iVA); + + // Create Flags + iFlags = 0; + if(peSections[i].Flags & PE_SECTION_FLAG_MEM_EXECUTE) + iFlags |= BIN_PAGEFLAG_EXEC; + if( !(peSections[i].Flags & PE_SECTION_FLAG_MEM_WRITE) ) + iFlags |= BIN_PAGEFLAG_RO; + + // Create Page Listing + count = (peSections[i].RawSize + 0xFFF) >> 12; + for(k=0;kPages[j+k].Virtual = iVA + (k<<12); + ret->Pages[j+k].Physical = peSections[i].RawOffs + (k<<12); // Store the offset in the physical address + if(k == count-1 && (peSections[i].RawSize & 0xFFF)) + ret->Pages[j+k].Size = peSections[i].RawSize & 0xFFF; // Byte count in page + else + ret->Pages[j+k].Size = 4096; + ret->Pages[j+k].Flags = iFlags; + } + count = (peSections[i].VirtualSize + 0xFFF) >> 12; + for(;kPages[j+k].Virtual = iVA + (k<<12); + ret->Pages[j+k].Physical = -1; // -1 = Fill with zeros + if(k == count-1 && (peSections[i].VirtualSize & 0xFFF)) + ret->Pages[j+k].Size = peSections[i].VirtualSize & 0xFFF; // Byte count in page + else + ret->Pages[j+k].Size = 4096; + ret->Pages[j+k].Flags = iFlags; + } + j += count; + + LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x", + i, namebuf, + iVA, + peSections[i].VirtualSize, peSections[i].RawSize, peSections[i].RawOffs, + peSections[i].Flags + ); + + } + // Free Executable Memory + free(peSections); + + LEAVE('p', ret); + return ret; +} + +/** + */ +tBinary *MZ_Open(int FP) +{ + ENTER("xFP", FP); + UNIMPLEMENTED(); + LEAVE('n'); + return NULL; +} + +int PE_Relocate(void *Base) +{ + tPE_DOS_HEADER *dosHdr; + tPE_IMAGE_HEADERS *peHeaders; + tPE_SECTION_HEADER *peSections; + tPE_DATA_DIR *directory; + tPE_IMPORT_DIR *impDir; + int i; + Uint iBase = (Uint)Base; + #if 0 + void *hLibrary; + char *libPath; + #endif + + ENTER("pBase", Base); + dosHdr = Base; + peHeaders = (void*)( iBase + dosHdr->PeHdrOffs ); + peSections = (void*)( iBase + sizeof(tPE_IMAGE_HEADERS) ); + + directory = (void*)(peSections[0].RVA + iBase); + + // === Load Import Tables + impDir = (void*)( directory[PE_DIR_IMPORT].RVA + iBase ); + for( i = 0; impDir[i].DLLName != NULL; i++ ) + { + impDir[i].DLLName += iBase; + impDir[i].ImportLookupTable += iBase/4; + impDir[i].ImportAddressTable += iBase/4; + LOG("DLL Required '%s'(0x%x)", impDir[i].DLLName, impDir[i].DLLName); + #if 0 + libPath = FindLibrary(impDir[i].DLLName); + if(libPath == NULL) + { + Warning("PE_Relocate - Unable to find library '%s'"); + LEAVE('i', -1); + return -1; + } + LOG("DLL Path = '%s'", libPath); + hLibrary = DynLib_Load(libPath, 0); + #endif + } + + for(i=0;iNext = gRegBinTypes; + gRegBinTypes = Type; + return 1; +} + /** * \fn int Proc_Spawn(char *Path) */ @@ -317,10 +327,19 @@ Uint Binary_MapIn(tBinary *binary) addr += base; LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical); MM_Map( addr, (Uint) (binary->Pages[i].Physical) ); - if( binary->Pages[i].Physical & 1) // Read-Only + + // Read-Only? + if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO) MM_SetFlags( addr, MM_PFLAG_RO, -1 ); else MM_SetFlags( addr, MM_PFLAG_COW, -1 ); + + // Execute? + if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC ) + MM_SetFlags( addr, MM_PFLAG_EXEC, -1 ); + else + MM_SetFlags( addr, MM_PFLAG_EXEC, 0 ); + } //Log("Mapped '%s' to 0x%x", binary->TruePath, base); @@ -420,23 +439,30 @@ tBinary *Binary_DoLoad(char *truePath) Uint dest; tPAddr paddr; paddr = (Uint)MM_AllocPhys(); + if(paddr == 0) { + Warning("Binary_DoLoad - Physical memory allocation failed"); + for( ; i--; ) { + MM_DerefPhys( pBinary->Pages[i].Physical ); + } + return NULL; + } MM_RefPhys( paddr ); // Make sure it is _NOT_ freed until we want it to be dest = MM_MapTemp( paddr ); dest += pBinary->Pages[i].Virtual & 0xFFF; LOG("dest = 0x%x, paddr = 0x%x", dest, paddr); - LOG("Pages[%i]={Physical:0x%x,Virtual:0x%x,Size:0x%x}", + LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}", i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size); // Pure Empty Page if(pBinary->Pages[i].Physical == -1) { LOG("%i - ZERO", i); - memsetd( (void*)dest, 0, 1024 ); + memsetd( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF)/4 ); } else { VFS_Seek( fp, pBinary->Pages[i].Physical, 1 ); if(pBinary->Pages[i].Size != 0x1000) { - LOG("%i - 0x%x - 0x%x bytes", + LOG("%i - 0x%llx - 0x%x bytes", i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size); memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) ); VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest ); @@ -678,13 +704,9 @@ void *Binary_LoadKernel(char *file) LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical); MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) ); MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL ); - #if 0 // Why was this here? It's the kernel - if( pBinary->Pages[i].Physical & 1) // Read-Only + + if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only? MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL ); - else - MM_SetFlags( addr, MM_PFLAG_COW, MM_PFLAG_KERNEL ); - //MM_SetCOW( addr ); - #endif } // Relocate Library diff --git a/Kernel/include/binary.h b/Kernel/include/binary.h index a1265515..fe80f5b0 100644 --- a/Kernel/include/binary.h +++ b/Kernel/include/binary.h @@ -21,6 +21,19 @@ typedef struct sBinaryPage Uint16 Flags; //!< Load Flags } __attribute__ ((packed)) tBinaryPage; +/** + * \brief Flags for ::tBinaryPage.Flags + * \name Binary Page Flags + * \{ + */ +//! \brief Read-only +#define BIN_PAGEFLAG_RO 0x0001 +//! \brief Executable +#define BIN_PAGEFLAG_EXEC 0x0002 +/** + * \} + */ + /** * \brief Defines a binary file * @@ -144,4 +157,6 @@ typedef struct sBinaryType */ extern char *Binary_RegInterp(char *Path); +extern int Binary_RegisterType(tBinaryType *Type); + #endif -- 2.20.1