Adding PE file support
authorJohn Hodge <tpg@prelude.(none)>
Sun, 17 Jan 2010 10:24:22 +0000 (18:24 +0800)
committerJohn Hodge <tpg@prelude.(none)>
Sun, 17 Jan 2010 10:24:22 +0000 (18:24 +0800)
- Also added binary register function (now modules can handle binary files)

Kernel/Makefile
Kernel/Makefile.BuildNum
Kernel/bin/pe.c [new file with mode: 0644]
Kernel/bin/pe.h [new file with mode: 0644]
Kernel/binary.c
Kernel/include/binary.h

index 279f251..8593d6f 100644 (file)
@@ -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)))
index e85c4e5..b0b7558 100644 (file)
@@ -1 +1 @@
-BUILD_NUM = 1359
+BUILD_NUM = 1368
diff --git a/Kernel/bin/pe.c b/Kernel/bin/pe.c
new file mode 100644 (file)
index 0000000..aa83ac9
--- /dev/null
@@ -0,0 +1,236 @@
+/*\r
+ * Acess v1\r
+ * Portable Executable Loader\r
+ */\r
+#define DEBUG  1\r
+#include <acess.h>\r
+#include <binary.h>\r
+#include <modules.h>\r
+#include "pe.h"\r
+\r
+// === PROTOTYPES ===\r
+ int   PE_Install(char **Arguments);\r
+tBinary        *PE_Load(int fp);\r
+tBinary        *MZ_Open(int fp);\r
+ int   PE_Relocate(void *Base);\r
+ int   PE_GetSymbol(void *Base, char *Name, Uint *Ret);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0032, BinPE, PE_Install, NULL, NULL);\r
+char   *gsPE_DefaultInterpreter = "/Acess/Libs/ld-acess.so";\r
+tBinaryType    gPE_Loader = {\r
+       NULL,\r
+       ('M'|('Z'<<8)), 0xFFFF, // 'MZ'\r
+       "PE/DOS",\r
+       PE_Load, PE_Relocate, PE_GetSymbol\r
+       };\r
+\r
+// === CODE ===\r
+int PE_Install(char **Arguments)\r
+{\r
+       Binary_RegisterType(&gPE_Loader);\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \brief Loads a PE Binary\r
+ */\r
+tBinary *PE_Load(int FP)\r
+{\r
+        int    count, i, j, k;\r
+        int    iPageCount;\r
+       tBinary *ret;\r
+       tPE_DOS_HEADER          dosHdr;\r
+       tPE_IMAGE_HEADERS       peHeaders;\r
+       tPE_SECTION_HEADER      *peSections;\r
+       char    namebuf[9] = {0};\r
+       Uint    iFlags, iVA;\r
+       \r
+       ENTER("xFP", FP);\r
+       \r
+       // Read DOS header and check\r
+       VFS_Read(FP, sizeof(tPE_DOS_HEADER), &dosHdr);\r
+       if( dosHdr.Ident != ('M'|('Z'<<8)) ) {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // - Read PE Header\r
+       VFS_Seek(FP, dosHdr.PeHdrOffs, SEEK_SET);\r
+       if( VFS_Tell(FP) != dosHdr.PeHdrOffs ) {\r
+               ret = MZ_Open(FP);\r
+               LEAVE('p', ret);\r
+               return ret;\r
+       }\r
+       VFS_Read(FP, sizeof(tPE_IMAGE_HEADERS), &peHeaders);\r
+       \r
+       // - Check PE Signature and pass on to the MZ Loader if invalid\r
+       if( peHeaders.Signature != (('P')|('E'<<8)) ) {\r
+               ret = MZ_Open(FP);\r
+               LEAVE('p', ret);\r
+               return ret;\r
+       }\r
+       \r
+       // Read Sections (Uses `count` as a temp variable)\r
+       count = sizeof(tPE_SECTION_HEADER) * peHeaders.FileHeader.SectionCount;\r
+       peSections = malloc( count );\r
+       if(!peSections)\r
+       {\r
+               Warning("PE_Load - Unable to allocate `peSections`, 0x%x bytes", count);\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       VFS_Read(FP, count, peSections);\r
+       \r
+       // Count Pages\r
+       iPageCount = 1; // 1st page is headers\r
+       for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
+       {\r
+               // Check if the section is loadable\r
+               // (VA is zero in non-loadable sections)\r
+               if(peSections[i].RVA + peHeaders.OptHeader.ImageBase == 0)              continue;\r
+               \r
+               // Moar pages\r
+               iPageCount += (peSections[i].VirtualSize + 0xFFF) >> 12;\r
+       }\r
+       \r
+       LOG("%i Pages", iPageCount);\r
+       \r
+       // Initialise Executable Information\r
+       ret = malloc(sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount);\r
+       \r
+       ret->Entry = peHeaders.OptHeader.EntryPoint + peHeaders.OptHeader.ImageBase;\r
+       ret->Base = peHeaders.OptHeader.ImageBase;\r
+       ret->Interpreter = gsPE_DefaultInterpreter;\r
+       ret->NumPages = iPageCount;\r
+       \r
+       LOG("Entry=%p, BaseAddress=0x%x\n", ret->Entry, ret->Base);\r
+       \r
+       ret->Pages[0].Virtual = peHeaders.OptHeader.ImageBase;\r
+       ret->Pages[0].Physical = 0;\r
+       ret->Pages[0].Size = 4096;\r
+       ret->Pages[0].Flags = 0;\r
+       \r
+       // Parse Sections\r
+       j = 1;  // Page Index\r
+       for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
+       {\r
+               iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase;\r
+               \r
+               // Skip non-loadable sections\r
+               if(iVA == 0)    continue;\r
+               \r
+               // Create Name Buffer\r
+               memcpy(namebuf, peSections[i].Name, 8);\r
+               LOG("Section %i '%s', iVA = %p", i, namebuf, iVA);\r
+               \r
+               // Create Flags\r
+               iFlags = 0;\r
+               if(peSections[i].Flags & PE_SECTION_FLAG_MEM_EXECUTE)\r
+                       iFlags |= BIN_PAGEFLAG_EXEC;\r
+               if( !(peSections[i].Flags & PE_SECTION_FLAG_MEM_WRITE) )\r
+                       iFlags |= BIN_PAGEFLAG_RO;\r
+               \r
+               // Create Page Listing\r
+               count = (peSections[i].RawSize + 0xFFF) >> 12;\r
+               for(k=0;k<count;k++)\r
+               {\r
+                       ret->Pages[j+k].Virtual = iVA + (k<<12);\r
+                       ret->Pages[j+k].Physical = peSections[i].RawOffs + (k<<12);     // Store the offset in the physical address\r
+                       if(k == count-1 && (peSections[i].RawSize & 0xFFF))\r
+                               ret->Pages[j+k].Size = peSections[i].RawSize & 0xFFF;   // Byte count in page\r
+                       else\r
+                               ret->Pages[j+k].Size = 4096;\r
+                       ret->Pages[j+k].Flags = iFlags;\r
+               }\r
+               count = (peSections[i].VirtualSize + 0xFFF) >> 12;\r
+               for(;k<count;k++)\r
+               {\r
+                       ret->Pages[j+k].Virtual = iVA + (k<<12);\r
+                       ret->Pages[j+k].Physical = -1;  // -1 = Fill with zeros\r
+                       if(k == count-1 && (peSections[i].VirtualSize & 0xFFF))\r
+                               ret->Pages[j+k].Size = peSections[i].VirtualSize & 0xFFF;       // Byte count in page\r
+                       else\r
+                               ret->Pages[j+k].Size = 4096;\r
+                       ret->Pages[j+k].Flags = iFlags;\r
+               }\r
+               j += count;\r
+               \r
+               LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x",\r
+                       i, namebuf, \r
+                       iVA,\r
+                       peSections[i].VirtualSize, peSections[i].RawSize, peSections[i].RawOffs,\r
+                       peSections[i].Flags\r
+                       );\r
+               \r
+       }\r
+       // Free Executable Memory\r
+       free(peSections);\r
+       \r
+       LEAVE('p', ret);\r
+       return ret;\r
+}\r
+\r
+/**\r
+ */\r
+tBinary *MZ_Open(int FP)\r
+{\r
+       ENTER("xFP", FP);\r
+       UNIMPLEMENTED();\r
+       LEAVE('n');\r
+       return NULL;\r
+}\r
+\r
+int PE_Relocate(void *Base)\r
+{\r
+       tPE_DOS_HEADER          *dosHdr;\r
+       tPE_IMAGE_HEADERS       *peHeaders;\r
+       tPE_SECTION_HEADER      *peSections;\r
+       tPE_DATA_DIR    *directory;\r
+       tPE_IMPORT_DIR  *impDir;\r
+        int    i;\r
+       Uint    iBase = (Uint)Base;\r
+       #if 0\r
+       void    *hLibrary;\r
+       char    *libPath;\r
+       #endif\r
+       \r
+       ENTER("pBase", Base);\r
+       dosHdr = Base;\r
+       peHeaders = (void*)( iBase + dosHdr->PeHdrOffs );\r
+       peSections = (void*)( iBase + sizeof(tPE_IMAGE_HEADERS) );\r
+       \r
+       directory = (void*)(peSections[0].RVA + iBase);\r
+       \r
+       // === Load Import Tables\r
+       impDir = (void*)( directory[PE_DIR_IMPORT].RVA + iBase );\r
+       for( i = 0; impDir[i].DLLName != NULL; i++ )\r
+       {\r
+               impDir[i].DLLName += iBase;\r
+               impDir[i].ImportLookupTable += iBase/4;\r
+               impDir[i].ImportAddressTable += iBase/4;\r
+               LOG("DLL Required '%s'(0x%x)", impDir[i].DLLName, impDir[i].DLLName);\r
+               #if 0\r
+               libPath = FindLibrary(impDir[i].DLLName);\r
+               if(libPath == NULL)\r
+               {\r
+                       Warning("PE_Relocate - Unable to find library '%s'");\r
+                       LEAVE('i', -1);\r
+                       return -1;\r
+               }\r
+               LOG("DLL Path = '%s'", libPath);\r
+               hLibrary = DynLib_Load(libPath, 0);\r
+               #endif\r
+       }\r
+       \r
+       for(i=0;i<PE_DIR_LAST;i++)\r
+               LOG("directory[%i] = {RVA=0x%x,Size=0x%x}", i, directory[i].RVA, directory[i].Size);\r
+       \r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+\r
+int PE_GetSymbol(void *Base, char *Name, Uint *Ret)\r
+{\r
+       return 0;\r
+}\r
diff --git a/Kernel/bin/pe.h b/Kernel/bin/pe.h
new file mode 100644 (file)
index 0000000..4e85cf9
--- /dev/null
@@ -0,0 +1,136 @@
+/*\r
+AcessOS/AcessBasic v1\r
+PE Loader\r
+HEADER\r
+*/\r
+#ifndef _EXE_PE_H\r
+#define _EXE_PE_H\r
+\r
+enum ePE_MACHINES {\r
+       PE_MACHINE_I386 = 0x14c,        // Intel 386+\r
+       PE_MACHINE_IA64 = 0x200         // Intel-64\r
+};\r
+\r
+enum ePE_DIR_INDX {\r
+       PE_DIR_EXPORT,          // 0\r
+       PE_DIR_IMPORT,          // 1\r
+       PE_DIR_RESOURCE,        // 2\r
+       PE_DIR_EXCEPTION,       // 3\r
+       PE_DIR_SECRURITY,       // 4\r
+       PE_DIR_RELOC,           // 5\r
+       PE_DIR_DEBUG,           // 6\r
+       PE_DIR_COPYRIGHT,       // 7\r
+       PE_DIR_ARCHITECTURE,// 8\r
+       PE_DIR_GLOBALPTR,       // 9\r
+       PE_DIR_TLS,                     // 10\r
+       PE_DIR_LOAD_CFG,        // 11\r
+       PE_DIR_BOUND_IMPORT,// 12\r
+       PE_DIR_IAT,                     // 13\r
+       PE_DIR_DELAY_IMPORT,// 14\r
+       PE_DIR_COM_DESCRIPTOR,  //15\r
+       PE_DIR_LAST\r
+};\r
+\r
+typedef struct {\r
+       Uint32  RVA;\r
+       Uint32  Size;\r
+} tPE_DATA_DIR;\r
+\r
+typedef struct {\r
+       Uint32  *ImportLookupTable;     //0x80000000 is Ordninal Flag\r
+       Uint32  TimeStamp;\r
+       Uint32  FowarderChain;\r
+       char    *DLLName;\r
+       Uint32  *ImportAddressTable;    // Array of Addresses - To be edited by loader\r
+} tPE_IMPORT_DIR;\r
+\r
+typedef struct {\r
+       Uint16  Hint;\r
+       char    Name[]; // Zero Term String\r
+} tPE_HINT_NAME;\r
+\r
+typedef struct {\r
+       char    Name[8];\r
+       Uint32  VirtualSize;\r
+       Uint32  RVA;\r
+       Uint32  RawSize;\r
+       Uint32  RawOffs;\r
+       Uint32  RelocationsPtr; //Set to 0 in executables\r
+       Uint32  LineNumberPtr;  //Pointer to Line Numbers\r
+       Uint16  RelocationCount;        // Set to 0 in executables\r
+       Uint16  LineNumberCount;\r
+       Uint32  Flags;\r
+} tPE_SECTION_HEADER;\r
+\r
+#define PE_SECTION_FLAG_CODE   0x00000020      // Section contains executable code.\r
+#define PE_SECTION_FLAG_IDATA  0x00000040      // Section contains initialized data.\r
+#define PE_SECTION_FLAG_UDATA  0x00000080      // Section contains uninitialized data.\r
+#define PE_SECTION_FLAG_DISCARDABLE    0x02000000      // Section can be discarded as needed.\r
+#define PE_SECTION_FLAG_MEM_NOT_CACHED 0x04000000      // Section cannot be cached.\r
+#define PE_SECTION_FLAG_MEM_NOT_PAGED  0x08000000      // Section is not pageable.\r
+#define PE_SECTION_FLAG_MEM_SHARED     0x10000000      // Section can be shared in memory.\r
+#define PE_SECTION_FLAG_MEM_EXECUTE    0x20000000      // Section can be executed as code.\r
+#define PE_SECTION_FLAG_MEM_READ       0x40000000      // Section can be read.\r
+#define PE_SECTION_FLAG_MEM_WRITE      0x80000000      // Section can be written to.\r
+\r
+typedef struct {\r
+       Uint32  page;\r
+       Uint32  size;\r
+       Uint16  ents[];\r
+} tPE_FIXUP_BLOCK;\r
+\r
+//File Header\r
+typedef struct {\r
+       Uint16  Machine;\r
+       Uint16  SectionCount;\r
+       Uint32  CreationTimestamp;\r
+       Uint32  SymbolTableOffs;\r
+       Uint32  SymbolCount;\r
+       Uint16  OptHeaderSize;\r
+       Uint16  Flags;\r
+} tPE_FILE_HEADER;\r
+\r
+typedef struct {\r
+       Uint16  Magic;  //0x10b: 32Bit, 0x20b: 64Bit\r
+       Uint16  LinkerVersion;\r
+       Uint32  CodeSize;       //Sum of all Code Segment Sizes\r
+       Uint32  DataSize;       //Sum of all Intialised Data Segments\r
+       Uint32  BssSize;        //Sum of all Unintialised Data Segments\r
+       Uint32  EntryPoint;\r
+       Uint32  CodeRVA;\r
+       Uint32  DataRVA;\r
+       Uint32  ImageBase;      //Prefered Base Address\r
+       Uint32  SectionAlignment;\r
+       Uint32  FileAlignment;\r
+       Uint32  WindowsVersion; //Unused/Irrelevent\r
+       Uint32  ImageVersion;   //Unused/Irrelevent\r
+       Uint32  SubsystemVersion;       //Unused, Set to 4\r
+       Uint32  Win32Version;   //Unused\r
+       Uint32  ImageSize;\r
+       Uint32  HeaderSize;\r
+       Uint32  Checksum;       //Unknown Method, Can be set to 0\r
+       Uint16  Subsystem;      //Required Windows Subsystem (None, GUI, Console)\r
+       Uint16  DllFlags;\r
+       Uint32  MaxStackSize;           //Reserved Stack Size\r
+       Uint32  InitialStackSize;       //Commited Stack Size\r
+       Uint32  InitialReservedHeap;    // Reserved Heap Size\r
+       Uint32  InitialCommitedHeap;    // Commited Heap Size\r
+       Uint32  LoaderFlags;    // Obselete\r
+       Uint32  NumberOfDirEntries;\r
+       tPE_DATA_DIR    Directory[16];\r
+} tPE_OPT_HEADER;\r
+\r
+// Root Header\r
+typedef struct {\r
+       Uint32  Signature;\r
+       tPE_FILE_HEADER FileHeader;\r
+       tPE_OPT_HEADER  OptHeader;\r
+} tPE_IMAGE_HEADERS;\r
+\r
+typedef struct {\r
+       Uint16  Ident;\r
+       Uint16  Resvd[29];\r
+       Uint32  PeHdrOffs;              // File address of new exe header\r
+} tPE_DOS_HEADER;\r
+\r
+#endif\r
index e3698da..a98e192 100644 (file)
@@ -55,6 +55,16 @@ tKernelBin   *glLoadedKernelLibs;
 tBinaryType    *gRegBinTypes = &gELF_Info;\r
  \r
 // === FUNCTIONS ===\r
+/**\r
+ * \brief Registers a binary type\r
+ */\r
+int Binary_RegisterType(tBinaryType *Type)\r
+{\r
+       Type->Next = gRegBinTypes;\r
+       gRegBinTypes = Type;\r
+       return 1;\r
+}\r
+\r
 /**\r
  * \fn int Proc_Spawn(char *Path)\r
  */\r
@@ -317,10 +327,19 @@ Uint Binary_MapIn(tBinary *binary)
                addr += base;\r
                LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);\r
                MM_Map( addr, (Uint) (binary->Pages[i].Physical) );\r
-               if( binary->Pages[i].Physical & 1)      // Read-Only\r
+               \r
+               // Read-Only?\r
+               if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)\r
                        MM_SetFlags( addr, MM_PFLAG_RO, -1 );\r
                else\r
                        MM_SetFlags( addr, MM_PFLAG_COW, -1 );\r
+               \r
+               // Execute?\r
+               if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )\r
+                       MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );\r
+               else\r
+                       MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );\r
+               \r
        }\r
        \r
        //Log("Mapped '%s' to 0x%x", binary->TruePath, base);\r
@@ -420,23 +439,30 @@ tBinary *Binary_DoLoad(char *truePath)
                Uint    dest;\r
                tPAddr  paddr;\r
                paddr = (Uint)MM_AllocPhys();\r
+               if(paddr == 0) {\r
+                       Warning("Binary_DoLoad - Physical memory allocation failed");\r
+                       for( ; i--; ) {\r
+                               MM_DerefPhys( pBinary->Pages[i].Physical );\r
+                       }\r
+                       return NULL;\r
+               }\r
                MM_RefPhys( paddr );    // Make sure it is _NOT_ freed until we want it to be\r
                dest = MM_MapTemp( paddr );\r
                dest += pBinary->Pages[i].Virtual & 0xFFF;\r
                LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);\r
-               LOG("Pages[%i]={Physical:0x%x,Virtual:0x%x,Size:0x%x}",\r
+               LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",\r
                        i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);\r
                \r
                // Pure Empty Page\r
                if(pBinary->Pages[i].Physical == -1) {\r
                        LOG("%i - ZERO", i);\r
-                       memsetd( (void*)dest, 0, 1024 );\r
+                       memsetd( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF)/4 );\r
                }\r
                else\r
                {\r
                        VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );\r
                        if(pBinary->Pages[i].Size != 0x1000) {\r
-                               LOG("%i - 0x%x - 0x%x bytes",\r
+                               LOG("%i - 0x%llx - 0x%x bytes",\r
                                        i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);\r
                                memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) );\r
                                VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );\r
@@ -678,13 +704,9 @@ void *Binary_LoadKernel(char *file)
                LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);\r
                MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );\r
                MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );\r
-               #if 0   // Why was this here? It's the kernel\r
-               if( pBinary->Pages[i].Physical & 1)     // Read-Only\r
+               \r
+               if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO)  // Read-Only?\r
                        MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );\r
-               else\r
-                       MM_SetFlags( addr, MM_PFLAG_COW, MM_PFLAG_KERNEL );\r
-                       //MM_SetCOW( addr );\r
-               #endif\r
        }
 \r
        // Relocate Library\r
index a126551..fe80f5b 100644 (file)
@@ -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

UCC git Repository :: git.ucc.asn.au