From a29ad3fcf4e0f52348fccbeb88add8031ca7e531 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 23 Aug 2011 14:57:08 +0800 Subject: [PATCH] Kernel - Converted binary loading to mmap --- Kernel/bin/elf.c | 143 ++------------ Kernel/bin/pe.c | 58 ++---- Kernel/binary.c | 400 +++++++++++++++------------------------ Kernel/include/binary.h | 51 +++-- Kernel/include/vfs_ext.h | 58 +++--- Kernel/vfs/mmap.c | 2 +- 6 files changed, 250 insertions(+), 462 deletions(-) diff --git a/Kernel/bin/elf.c b/Kernel/bin/elf.c index d04dbda4..c844ff08 100644 --- a/Kernel/bin/elf.c +++ b/Kernel/bin/elf.c @@ -30,9 +30,8 @@ tBinary *Elf_Load(int fp) tBinary *ret; Elf32_Ehdr hdr; Elf32_Phdr *phtab; - int i, j, k; - int iPageCount; - int count; + int i, j; + int iLoadCount; ENTER("xfp", fp); @@ -66,32 +65,31 @@ tBinary *Elf_Load(int fp) VFS_Read(fp, sizeof(Elf32_Phdr)*hdr.phentcount, phtab); // Count Pages - iPageCount = 0; + iLoadCount = 0; LOG("hdr.phentcount = %i", hdr.phentcount); for( i = 0; i < hdr.phentcount; i++ ) { // Ignore Non-LOAD types if(phtab[i].Type != PT_LOAD) continue; - iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12; + iLoadCount ++; LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize); } - LOG("iPageCount = %i", iPageCount); + LOG("iLoadCount = %i", iLoadCount); // Allocate Information Structure - ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount ); + ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount ); // Fill Info Struct ret->Entry = hdr.entrypoint; ret->Base = -1; // Set Base to maximum value - ret->NumPages = iPageCount; + ret->NumSections = iLoadCount; ret->Interpreter = NULL; // Load Pages j = 0; for( i = 0; i < hdr.phentcount; i++ ) { - int lastSize; //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type); LOG("phtab[%i] = {", i); LOG(" .Type = 0x%08x", phtab[i].Type); @@ -125,126 +123,17 @@ tBinary *Elf_Load(int fp) LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}", i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize); - //if( (phtab[i].FileSize & 0xFFF) < 0x1000 - (phtab[i].VAddr & 0xFFF) ) - // lastSize = phtab[i].FileSize; - //else - lastSize = (phtab[i].FileSize & 0xFFF) + (phtab[i].VAddr & 0xFFF); - //lastSize &= 0xFFF; - - //LOG("lastSize = 0x%x", lastSize); - - lastSize = phtab[i].FileSize; - - // Get Pages - count = ( (phtab[i].VAddr&0xFFF) + phtab[i].FileSize + 0xFFF) >> 12; - for( k = 0; k < count; k ++ ) - { - ret->Pages[j+k].Virtual = phtab[i].VAddr + (k<<12); - ret->Pages[j+k].Physical = phtab[i].Offset + (k<<12); // Store the offset in the physical address - if(k != 0) { - ret->Pages[j+k].Physical -= ret->Pages[j+k].Virtual&0xFFF; - ret->Pages[j+k].Virtual &= ~0xFFF; - } - if(k == count-1) - ret->Pages[j+k].Size = lastSize; // Byte count in page - else if(k == 0) - ret->Pages[j+k].Size = 4096 - (phtab[i].VAddr&0xFFF); - else - ret->Pages[j+k].Size = 4096; - LOG("ret->Pages[%i].Size = 0x%x", j+k, ret->Pages[j+k].Size); - ret->Pages[j+k].Flags = 0; - lastSize -= ret->Pages[j+k].Size; - } - count = (phtab[i].MemSize + 0xFFF) >> 12; - for(;kPages[j+k].Virtual = phtab[i].VAddr + (k<<12); - ret->Pages[j+k].Physical = -1; // -1 = Fill with zeros - if(k != 0) ret->Pages[j+k].Virtual &= ~0xFFF; - if(k == count-1 && (phtab[i].MemSize & 0xFFF)) - ret->Pages[j+k].Size = phtab[i].MemSize & 0xFFF; // Byte count in page - else - ret->Pages[j+k].Size = 4096; - ret->Pages[j+k].Flags = 0; - LOG("%i - 0x%x => 0x%x - 0x%x", j+k, - ret->Pages[j+k].Physical, ret->Pages[j+k].Virtual, ret->Pages[j+k].Size); - } - j += count; - } - - #if 0 - LOG("Cleaning up overlaps"); - // Clear up Overlaps - { - struct { - Uint V; - Uint P; - Uint S; - Uint F; - } *tmpRgns; - count = j; - tmpRgns = malloc(sizeof(*tmpRgns)*count); - // Copy - for(i=0;iPages[i].Virtual; - tmpRgns[i].P = ret->Pages[i].Physical; - tmpRgns[i].S = ret->Pages[i].Size; - tmpRgns[i].F = ret->Pages[i].Flags; - } - // Compact - for(i=1,j=0; i < count; i++) - { - if( tmpRgns[j].F == tmpRgns[i].F - && tmpRgns[j].V + tmpRgns[j].S == tmpRgns[i].V - && ((tmpRgns[j].P == -1 && tmpRgns[i].P == -1) - || (tmpRgns[j].P + tmpRgns[j].S == tmpRgns[i].P)) ) - { - tmpRgns[j].S += tmpRgns[i].S; - } else { - j ++; - tmpRgns[j].V = tmpRgns[i].V; - tmpRgns[j].P = tmpRgns[i].P; - tmpRgns[j].F = tmpRgns[i].F; - tmpRgns[j].S = tmpRgns[i].S; - } - } + ret->LoadSections[j].Offset = phtab[i].Offset; + ret->LoadSections[j].FileSize = phtab[i].FileSize; + ret->LoadSections[j].Virtual = phtab[i].VAddr; + ret->LoadSections[j].MemSize = phtab[i].MemSize; + ret->LoadSections[j].Flags = 0; + if( !(phtab[i].Flags & SHF_WRITE) ) + ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO; + if( phtab[i].Flags & SHF_EXECINSTR ) + ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC; j ++; - // Count - count = j; j = 0; - for(i=0;i 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S); - tmpRgns[i].S += tmpRgns[i].V & 0xFFF; - if(tmpRgns[i].P != -1) tmpRgns[i].P -= tmpRgns[i].V & 0xFFF; - tmpRgns[i].V &= ~0xFFF; - j += (tmpRgns[i].S + 0xFFF) >> 12; - //LogF(" Elf_Load: %i - 0x%x => 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S); - } - // Reallocate - ret = realloc( ret, sizeof(tBinary) + 3*sizeof(Uint)*j ); - if(!ret) { - Log_Warning("BIN", "ElfLoad: Unable to reallocate return structure"); - return NULL; - } - ret->NumPages = j; - // Split - k = 0; - for(i=0;i> 12; j++,k++ ) { - ret->Pages[k].Flags = tmpRgns[i].F; - ret->Pages[k].Virtual = tmpRgns[i].V + (j<<12); - if(tmpRgns[i].P != -1) { - ret->Pages[k].Physical = tmpRgns[i].P + (j<<12); - } else - ret->Pages[k].Physical = -1; - ret->Pages[k].Size = tmpRgns[i].S - (j << 12); - // Clamp to page size - if(ret->Pages[k].Size > 0x1000) ret->Pages[k].Size = 0x1000; - } - } - // Free Temp - free(tmpRgns); } - #endif // Clean Up free(phtab); diff --git a/Kernel/bin/pe.c b/Kernel/bin/pe.c index a697e9cb..0e7d1acd 100644 --- a/Kernel/bin/pe.c +++ b/Kernel/bin/pe.c @@ -37,8 +37,8 @@ int PE_Install(char **Arguments) */ tBinary *PE_Load(int FP) { - int count, i, j, k; - int iPageCount; + int count, i, j; + int iSectCount; tBinary *ret; tPE_DOS_HEADER dosHdr; tPE_IMAGE_HEADERS peHeaders; @@ -83,7 +83,7 @@ tBinary *PE_Load(int FP) VFS_Read(FP, count, peSections); // Count Pages - iPageCount = 1; // 1st page is headers + iSectCount = 1; // 1st page is headers for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ ) { // Check if the section is loadable @@ -91,30 +91,32 @@ tBinary *PE_Load(int FP) if(peSections[i].RVA + peHeaders.OptHeader.ImageBase == 0) continue; // Moar pages - iPageCount += (peSections[i].VirtualSize + 0xFFF) >> 12; + iSectCount ++; } - LOG("%i Pages", iPageCount); + LOG("%i Sections", iSectCount); // Initialise Executable Information - ret = malloc(sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount); + ret = malloc(sizeof(tBinary) + sizeof(tBinarySection)*iSectCount); ret->Entry = peHeaders.OptHeader.EntryPoint + peHeaders.OptHeader.ImageBase; ret->Base = peHeaders.OptHeader.ImageBase; ret->Interpreter = gsPE_DefaultInterpreter; - ret->NumPages = iPageCount; + ret->NumSections = iSectCount; 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; + ret->LoadSections[0].Virtual = peHeaders.OptHeader.ImageBase; + ret->LoadSections[0].Offset = 0; + ret->LoadSections[0].FileSize = 4096; + ret->LoadSections[0].MemSize = 4096; + ret->LoadSections[0].Flags = 0; // Parse Sections j = 1; // Page Index for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ ) { + tBinarySection *sect = &ret->LoadSections[j]; iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase; // Skip non-loadable sections @@ -127,34 +129,16 @@ tBinary *PE_Load(int FP) // Create Flags iFlags = 0; if(peSections[i].Flags & PE_SECTION_FLAG_MEM_EXECUTE) - iFlags |= BIN_PAGEFLAG_EXEC; + iFlags |= BIN_SECTFLAG_EXEC; if( !(peSections[i].Flags & PE_SECTION_FLAG_MEM_WRITE) ) - iFlags |= BIN_PAGEFLAG_RO; + iFlags |= BIN_SECTFLAG_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; + sect->Virtual = iVA; + sect->Offset = peSections[i].RawOffs; + sect->FileSize = peSections[i].RawSize; + sect->MemSize = peSections[i].VirtualSize; + sect->Flags = iFlags; + j ++; LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x", i, namebuf, diff --git a/Kernel/binary.c b/Kernel/binary.c index 1276f722..f00e8518 100644 --- a/Kernel/binary.c +++ b/Kernel/binary.c @@ -2,7 +2,7 @@ * Acess2 * Common Binary Loader */ -#define DEBUG 0 +#define DEBUG 1 #include #include #include @@ -31,11 +31,11 @@ extern tBinaryType gELF_Info; // === PROTOTYPES === int Proc_Execve(const char *File, const char **ArgV, const char **EnvP); -Uint Binary_Load(const char *file, Uint *entryPoint); -tBinary *Binary_GetInfo(const char *truePath); -Uint Binary_MapIn(tBinary *binary); -Uint Binary_IsMapped(tBinary *binary); -tBinary *Binary_DoLoad(const char *truePath); +tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint); +tBinary *Binary_GetInfo(tMount MountID, tInode InodeID); +tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax); +tVAddr Binary_IsMapped(tBinary *Binary); +tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path); void Binary_Dereference(tBinary *Info); #if 0 Uint Binary_Relocate(void *Base); @@ -44,6 +44,7 @@ Uint Binary_GetSymbolEx(const char *Name, Uint *Value); #if 0 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val); #endif + int Binary_int_CheckMemFree( tVAddr _start, size_t _len ); // === GLOBALS === tShortSpinlock glBinListLock; @@ -104,8 +105,8 @@ int Proc_Execve(const char *File, const char **ArgV, const char **EnvP) char **argenvBuf, *strBuf; char **argvSaved, **envpSaved; char *savedFile; - Uint entry; - Uint bases[2] = {0}; + tVAddr entry; + Uint bases[2] = {0}; // Uint because Proc_StartUser wants it ENTER("sFile pArgV pEnvP", File, ArgV, EnvP); @@ -175,45 +176,51 @@ int Proc_Execve(const char *File, const char **ArgV, const char **EnvP) } /** - * \fn Uint Binary_Load(char *file, Uint *entryPoint) + * \fn tVAddr Binary_Load(char *Path, tVAddr *EntryPoint) * \brief Load a binary into the current address space - * \param file Path to binary to load - * \param entryPoint Pointer for exectuable entry point + * \param Path Path to binary to load + * \param EntryPoint Pointer for exectuable entry point */ -Uint Binary_Load(const char *file, Uint *entryPoint) +tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint) { - char *sTruePath; + tMount mount_id; + tInode inode; tBinary *pBinary; - Uint base = -1; + tVAddr base = -1; - ENTER("sfile pentryPoint", file, entryPoint); + ENTER("sPath pEntryPoint", Path, EntryPoint); // Sanity Check Argument - if(file == NULL) { + if(Path == NULL) { LEAVE('x', 0); return 0; } - // Get True File Path - sTruePath = VFS_GetTruePath(file); - LOG("sTruePath = %p", sTruePath); - - if(sTruePath == NULL) { - Log_Warning("Binary", "%p '%s' does not exist.", file, file); - LEAVE('x', 0); - return 0; + // Check if this path has been loaded before. + #if 0 + // TODO: Implement a list of string/tBinary pairs for loaded bins + #endif + + // Get Inode + { + int fd; + tFInfo info; + fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC); + if( fd == -1 ) { + LOG("%s does not exist", Path); + LEAVE_RET('x', 0); + } + VFS_FInfo(fd, &info, 0); + VFS_Close(fd); + mount_id = info.mount; + inode = info.inode; } - - LOG("sTruePath = '%s'", sTruePath); - - // TODO: Also get modifcation time + + // TODO: Also get modifcation time? // Check if the binary has already been loaded - if( !(pBinary = Binary_GetInfo(sTruePath)) ) - pBinary = Binary_DoLoad(sTruePath); // Else load it - - // Clean Up - free(sTruePath); + if( !(pBinary = Binary_GetInfo(mount_id, inode)) ) + pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it // Error Check if(pBinary == NULL) { @@ -221,15 +228,8 @@ Uint Binary_Load(const char *file, Uint *entryPoint) return 0; } - #if 0 - if( (base = Binary_IsMapped(pBinary)) ) { - LEAVE('x', base); - return base; - } - #endif - // Map into process space - base = Binary_MapIn(pBinary); // If so then map it in + base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST); // Check for errors if(base == 0) { @@ -239,18 +239,18 @@ Uint Binary_Load(const char *file, Uint *entryPoint) // Interpret if(pBinary->Interpreter) { - Uint start; + tVAddr start; if( Binary_Load(pBinary->Interpreter, &start) == 0 ) { LEAVE('x', 0); return 0; } - *entryPoint = start; + *EntryPoint = start; } else - *entryPoint = pBinary->Entry - pBinary->Base + base; + *EntryPoint = pBinary->Entry - pBinary->Base + base; // Return - LOG("*entryPoint = 0x%x", *entryPoint); + LOG("*EntryPoint = 0x%x", *EntryPoint); LEAVE('x', base); return base; // Pass the base as an argument to the user if there is an interpreter } @@ -259,13 +259,13 @@ Uint Binary_Load(const char *file, Uint *entryPoint) * \brief Finds a matching binary entry * \param TruePath File Identifier (True path name) */ -tBinary *Binary_GetInfo(const char *TruePath) +tBinary *Binary_GetInfo(tMount MountID, tInode InodeID) { tBinary *pBinary; pBinary = glLoadedBinaries; while(pBinary) { - if(strcmp(pBinary->TruePath, TruePath) == 0) + if(pBinary->MountID == MountID && pBinary->Inode == InodeID) return pBinary; pBinary = pBinary->Next; } @@ -277,26 +277,25 @@ tBinary *Binary_GetInfo(const char *TruePath) \brief Maps an already-loaded binary into an address space. \param binary Pointer to globally stored data. */ -Uint Binary_MapIn(tBinary *binary) +tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax) { - Uint base; - Uint addr; - int i; - + tVAddr base; + int i, fd; // Reference Executable (Makes sure that it isn't unloaded) - binary->ReferenceCount ++; + Binary->ReferenceCount ++; // Get Binary Base - base = binary->Base; + base = Binary->Base; // Check if base is free if(base != 0) { - for(i=0;iNumPages;i++) + for(i=0;iNumSections;i++) { - if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) { + if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) ) + { base = 0; - LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF); + LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual); break; } } @@ -306,53 +305,60 @@ Uint Binary_MapIn(tBinary *binary) if(base == 0) { // If so, give it a base - base = BIN_HIGHEST; - while(base >= BIN_LOWEST) + base = LoadMax; + while(base >= LoadMin) { - for(i=0;iNumPages;i++) + for( i = 0; i < Binary->NumSections; i ++ ) { - addr = binary->Pages[i].Virtual & ~0xFFF; - addr -= binary->Base; - addr += base; - if( MM_GetPhysAddr( addr ) ) break; + tVAddr addr = Binary->LoadSections[i].Virtual - Binary->Base + base; + if( Binary_int_CheckMemFree( addr, Binary->LoadSections[i].MemSize ) ) + break; } // If space was found, break - if(i == binary->NumPages) break; + if(i == Binary->NumSections) break; // Else decrement pointer and try again base -= BIN_GRANUALITY; } } // Error Check - if(base < BIN_LOWEST) { - Log_Warning("BIN", "Executable '%s' cannot be loaded, no space", binary->TruePath); + if(base < LoadMin) { + Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path); return 0; } // Map Executable In - for(i=0;iNumPages;i++) + fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ); + for( i = 0; i < Binary->NumSections; i ++ ) { - addr = binary->Pages[i].Virtual & ~0xFFF; - addr -= binary->Base; - addr += base; - LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical); - MM_Map( addr, (Uint) (binary->Pages[i].Physical) ); - - // 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_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), binary->TruePath, base); + tBinarySection *sect = &Binary->LoadSections[i]; + Uint protflags, mapflags; + tVAddr addr = sect->Virtual - Binary->Base + base; + LOG("%i - 0x%x to 0x%x", i, addr, sect->Offset); + + protflags = MMAP_PROT_READ; + mapflags = MMAP_MAP_FIXED; + + if( sect->Flags & BIN_SECTFLAG_EXEC ) + protflags |= MMAP_PROT_EXEC; + if( sect->Flags & BIN_SECTFLAG_RO ) { + VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset ); + } + else { + protflags |= MMAP_PROT_WRITE; + VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset ); + } + if( sect->FileSize < sect->MemSize ) { + mapflags |= MMAP_MAP_ANONYMOUS; + VFS_MMap( + (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize, + protflags, MMAP_MAP_PRIVATE|mapflags, + 0, 0 + ); + } + } + + Log_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), Path, base); //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual); @@ -392,17 +398,17 @@ Uint Binary_IsMapped(tBinary *binary) * \brief Loads a binary file into memory * \param truePath Absolute filename of binary */ -tBinary *Binary_DoLoad(const char *truePath) +tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path) { tBinary *pBinary; - int fp, i; + int fp; Uint ident; tBinaryType *bt = gRegBinTypes; - ENTER("struePath", truePath); + ENTER("iMountID XInode sPath", Path); // Open File - fp = VFS_Open(truePath, VFS_OPENFLAG_READ); + fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ); if(fp == -1) { LOG("Unable to load file, access denied"); LEAVE('n'); @@ -412,7 +418,8 @@ tBinary *Binary_DoLoad(const char *truePath) // Read File Type VFS_Read(fp, 4, &ident); VFS_Seek(fp, 0, SEEK_SET); - + + // Determine the type for(; bt; bt = bt->Next) { if( (ident & bt->Mask) != (Uint)bt->Ident ) @@ -420,9 +427,14 @@ tBinary *Binary_DoLoad(const char *truePath) pBinary = bt->Load(fp); break; } + + // Close File + VFS_Close(fp); + + // Catch errors if(!bt) { - Log_Warning("BIN", "'%s' is an unknown file type. (%02x %02x %02x %02x)", - truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF); + Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)", + Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF); LEAVE('n'); return NULL; } @@ -435,87 +447,22 @@ tBinary *Binary_DoLoad(const char *truePath) // Initialise Structure pBinary->ReferenceCount = 0; - pBinary->TruePath = strdup(truePath); + pBinary->MountID = MountID; + pBinary->Inode = Inode; // Debug Information LOG("Interpreter: '%s'", pBinary->Interpreter); LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry); - LOG("NumPages: %i", pBinary->NumPages); - - // Read Data - for(i = 0; i < pBinary->NumPages; i ++) - { - Uint dest; - tPAddr paddr; - paddr = (Uint)MM_AllocPhys(); - if(paddr == 0) { - Log_Warning("BIN", "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%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); - memset( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF) ); - } - else - { - VFS_Seek( fp, pBinary->Pages[i].Physical, 1 ); - // If the address is not aligned, or the page is not full - // sized, copy part of it - if( (dest & 0xFFF) > 0 || pBinary->Pages[i].Size < 0x1000) - { - // Validate the size to prevent Kernel page faults - // Clips to one page and prints a warning - if( pBinary->Pages[i].Size + (dest & 0xFFF) > 0x1000) { - Log_Warning("Binary", "Loader error: Page %i (%p) of '%s' is %i bytes (> 4096)", - i, pBinary->Pages[i].Virtual, truePath, - (dest&0xFFF) + pBinary->Pages[i].Size); - pBinary->Pages[i].Size = 0x1000 - (dest & 0xFFF); - } - LOG("%i - 0x%llx - 0x%x bytes", - i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size); - // Zero from `dest` to the end of the page - memset( (void*)dest, 0, 0x1000 - (dest&0xFFF) ); - // Read in the data - VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest ); - } - // Full page - else - { - // Check if the page is oversized - if(pBinary->Pages[i].Size > 0x1000) - Log_Warning("Binary", "Loader error - Page %i (%p) of '%s' is %i bytes (> 4096)", - i, pBinary->Pages[i].Virtual, truePath, - pBinary->Pages[i].Size); - // Read data - LOG("%i - 0x%x", i, pBinary->Pages[i].Physical); - VFS_Read( fp, 0x1000, (void*)dest ); - } - } - pBinary->Pages[i].Physical = paddr; - MM_FreeTemp( dest ); - } - LOG("Page Count: %i", pBinary->NumPages); - - // Close File - VFS_Close(fp); + LOG("NumSections: %i", pBinary->NumSections); // Add to the list SHORTLOCK(&glBinListLock); pBinary->Next = glLoadedBinaries; glLoadedBinaries = pBinary; SHORTREL(&glBinListLock); - + + // TODO: Register the path with the binary + // Return LEAVE('p', pBinary); return pBinary; @@ -548,8 +495,9 @@ void Binary_Unload(void *Base) // Check the base if(pKBin->Base != Base) continue; // Deallocate Memory - for(i = 0; i < pKBin->Info->NumPages; i++) { - MM_Deallocate( (Uint)Base + (i << 12) ); + for(i = 0; i < pKBin->Info->NumSections; i++) + { + // TODO: VFS_MUnmap(); } // Dereference Binary Binary_Dereference( pKBin->Info ); @@ -624,12 +572,11 @@ char *Binary_RegInterp(char *Path) */ void *Binary_LoadKernel(const char *File) { - char *sTruePath; tBinary *pBinary; tKernelBin *pKBinary; - Uint base = -1; - Uint addr; - int i; + tVAddr base = -1; + tMount mount_id; + tInode inode; ENTER("sFile", File); @@ -639,15 +586,21 @@ void *Binary_LoadKernel(const char *File) return 0; } - // Get True File Path - sTruePath = VFS_GetTruePath(File); - if(sTruePath == NULL) { - LEAVE('n'); - return 0; + { + int fd = VFS_Open(File, VFS_OPENFLAG_READ); + tFInfo info; + if(fd == -1) { + LEAVE('n'); + return NULL; + } + VFS_FInfo(fd, &info, 0); + mount_id = info.mount; + inode = info.inode; + VFS_Close(fd); } // Check if the binary has already been loaded - if( (pBinary = Binary_GetInfo(sTruePath)) ) + if( (pBinary = Binary_GetInfo(mount_id, inode)) ) { for(pKBinary = glLoadedKernelLibs; pKBinary; @@ -660,7 +613,7 @@ void *Binary_LoadKernel(const char *File) } } else - pBinary = Binary_DoLoad(sTruePath); // Else load it + pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it // Error Check if(pBinary == NULL) { @@ -675,76 +628,13 @@ void *Binary_LoadKernel(const char *File) // Reference Executable (Makes sure that it isn't unloaded) pBinary->ReferenceCount ++; - - // Check compiled base - base = pBinary->Base; - // - Sanity Check - if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) { - base = 0; - } - // - Check if it is a valid base address - if(base != 0) - { - for(i=0;iNumPages;i++) - { - if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) { - base = 0; - LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF); - break; - } - } - } - - // Check if the executable has no base or it is not free - if(base == 0) - { - // If so, give it a base - base = KLIB_LOWEST; - while(base < KLIB_HIGHEST) - { - for(i = 0; i < pBinary->NumPages; i++) - { - addr = pBinary->Pages[i].Virtual & ~0xFFF; - addr -= pBinary->Base; - addr += base; - if( MM_GetPhysAddr( addr ) ) break; - } - // If space was found, break - if(i == pBinary->NumPages) break; - // Else decrement pointer and try again - base += KLIB_GRANUALITY; - } - } - - // - Error Check - if(base >= KLIB_HIGHEST) { - Log_Warning("BIN", "Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath); - Binary_Dereference( pBinary ); - LEAVE('n'); - return 0; - } - - LOG("base = 0x%x", base); - - // - Map binary in - LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages); - for(i = 0; i < pBinary->NumPages; i++) - { - addr = pBinary->Pages[i].Virtual & ~0xFFF; - addr -= pBinary->Base; - addr += base; - 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( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only? - MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL ); - } + + Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST); // Relocate Library if( !Binary_Relocate( (void*)base ) ) { - Log_Warning("BIN", "Relocation of '%s' failed, unloading", sTruePath); + Log_Warning("Binary", "Relocation of '%s' failed, unloading", File); Binary_Unload( (void*)base ); Binary_Dereference( pBinary ); LEAVE('n'); @@ -859,6 +749,24 @@ Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val) return 0; } +/** + * \brief Check if a range of memory is fully free + * \return Inverse boolean free (0 if all pages are unmapped) + */ +int Binary_int_CheckMemFree( tVAddr _start, size_t _len ) +{ + _len += _start & (PAGE_SIZE-1); + _start &= ~(PAGE_SIZE-1); + for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) { + if( MM_GetPhysAddr(_start) != 0 ) + return 1; + } + if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 ) + return 1; + return 0; +} + + // === EXPORTS === EXPORT(Binary_FindSymbol); EXPORT(Binary_Unload); diff --git a/Kernel/include/binary.h b/Kernel/include/binary.h index 91a2e224..a5ae974a 100644 --- a/Kernel/include/binary.h +++ b/Kernel/include/binary.h @@ -8,35 +8,30 @@ // === TYPES === /** - * \brief Representation of a page in a binary file + * \brief Representation of a section in a binary file * * Tells the binary loader where the page data resides on disk and where * to load it to (relative to the binary base). Once the data is read, * the \a Physical field contains the physical address of the page. */ -typedef struct sBinaryPage +typedef struct sBinarySection { - /** - * \brief Physical address, or file offset - * - * Physical address of this page or, when the file is not yet - * loaded, this is a file offset (or -1 for uninitialised data) - */ - tPAddr Physical; + Uint64 Offset; tVAddr Virtual; //!< Virtual load address - Uint16 Size; //!< Number of bytes to load from the file - Uint16 Flags; //!< Load Flags -} __attribute__ ((packed)) tBinaryPage; + size_t FileSize; //!< Number of bytes to load from the file + size_t MemSize; //!< Number of bytes in memory + Uint Flags; //!< Load Flags +} tBinarySection; /** - * \brief Flags for ::tBinaryPage.Flags - * \name Binary Page Flags + * \brief Flags for ::tBinarySection.Flags + * \name Binary Section Flags * \{ */ //! \brief Read-only -#define BIN_PAGEFLAG_RO 0x0001 +#define BIN_SECTFLAG_RO 0x0001 //! \brief Executable -#define BIN_PAGEFLAG_EXEC 0x0002 +#define BIN_SECTFLAG_EXEC 0x0002 /** * \} */ @@ -60,12 +55,10 @@ typedef struct sBinaryPage typedef struct sBinary { struct sBinary *Next; //!< Pointer used by the kernel - /** - * \brief True path of the file - * \note Used to uniquely identify the loaded binary to reduce in-memory - * duplication. - */ - const char *TruePath; + + tMount MountID; + tInode Inode; + /** * \brief Interpreter used to load the file * \note This can be either requested by the individual file, or a per-driver option @@ -74,24 +67,24 @@ typedef struct sBinary /** * \brief Entrypoint of the binary (at requested base); */ - Uint Entry; + tVAddr Entry; /** * \brief File's requested load base */ - Uint Base; + tVAddr Base; /** * \brief Number of times this binary has been mapped */ int ReferenceCount; /** - * \brief Number of pages defined in the file + * \brief Number of sections defined in the file */ - int NumPages; + int NumSections; /** - * \brief Array of pages defined by this binary - * \note Contains \a NumPages entries + * \brief Array of sections defined by this binary + * \note Contains \a NumSections entries */ - tBinaryPage Pages[]; + tBinarySection LoadSections[]; } tBinary; /** diff --git a/Kernel/include/vfs_ext.h b/Kernel/include/vfs_ext.h index 060a01c8..d04fcf27 100644 --- a/Kernel/include/vfs_ext.h +++ b/Kernel/include/vfs_ext.h @@ -6,6 +6,9 @@ #ifndef _VFS_EXT_H #define _VFS_EXT_H +typedef Uint64 tInode; +typedef Uint32 tMount; + // === CONSTANTS === //! Maximum size of a Memory Path generated by VFS_GetMemPath #define VFS_MEMPATH_SIZE (3 + (BITS/4)*2) @@ -75,6 +78,15 @@ enum eVFS_SeekDirs * \} */ +#define MMAP_PROT_READ 0x001 +#define MMAP_PROT_WRITE 0x002 +#define MMAP_PROT_EXEC 0x004 + +#define MMAP_MAP_SHARED 0x001 +#define MMAP_MAP_PRIVATE 0x002 +#define MMAP_MAP_FIXED 0x004 +#define MMAP_MAP_ANONYMOUS 0x008 + // -- System Call Structures --- /** * \brief ACL Defintion Structure @@ -96,14 +108,16 @@ typedef struct sVFS_ACL */ typedef struct sFInfo { - Uint uid; //!< Owning User ID - Uint gid; //!< Owning Group ID - Uint flags; //!< File flags + tMount mount; //!< Mountpoint ID + tInode inode; //!< Inode + Uint32 uid; //!< Owning User ID + Uint32 gid; //!< Owning Group ID + Uint32 flags; //!< File flags Uint64 size; //!< File Size Sint64 atime; //!< Last Accessed time Sint64 mtime; //!< Last modified time Sint64 ctime; //!< Creation time - int numacls; //!< Total number of ACL entries + Sint32 numacls; //!< Total number of ACL entries tVFS_ACL acls[]; //!< ACL buffer (size is passed in the \a MaxACLs argument to VFS_FInfo) } tFInfo; @@ -133,6 +147,24 @@ extern int VFS_Init(void); * \return VFS Handle (an integer) or -1 if an error occured */ extern int VFS_Open(const char *Path, Uint Mode); +/** + * \brief Opens a file via an open directory + * \note The file to open must be a direct child of the parent + * \param FD Parent Directory + * \param Name Child name + * \param Mode Open mode + * \return File handle (same as returned from VFS_Open) + */ +extern int VFS_OpenChild(int FD, const char *Name, Uint Mode); +/** + * \brief Opens a file given a mount ID and an inode number + * \param Mount Mount ID returned by FInfo + * \param Inode Inode number from FInfo + * \param Mode Open mode (see VFS_Open) + * \return File handle (same as VFS_Open) + */ +extern int VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode); + /** * \brief Close a currently open file * \param FD Handle returned by ::VFS_Open @@ -281,24 +313,6 @@ extern int VFS_Symlink(const char *Name, const char *Link); * \return Boolean Success */ extern int VFS_ReadDir(int FD, char *Dest); -/** - * \brief Opens a file via an open directory - * \note The file to open must be a direct child of the parent - * \param FD Parent Directory - * \param Name Child name - * \param Mode Open mode - * \return File handle (same as returned from VFS_Open) - */ -extern int VFS_OpenChild(int FD, const char *Name, Uint Mode); - -/** - * \brief Opens a file given a mount ID and an inode number - * \param Mount Mount ID returned by FInfo - * \param Inode Inode number from FInfo - * \param Mode Open mode (see VFS_Open) - * \return File handle (same as VFS_Open) - */ -extern int VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode); /** * \brief Wait for an aciton on a file descriptor * \param MaxHandle Maximum set handle in \a *Handles diff --git a/Kernel/vfs/mmap.c b/Kernel/vfs/mmap.c index 7c3fdf4b..455ac96d 100644 --- a/Kernel/vfs/mmap.c +++ b/Kernel/vfs/mmap.c @@ -2,7 +2,7 @@ * Acess2 VFS * - Open, Close and ChDir */ -#define DEBUG 0 +#define DEBUG 1 #include #include #include -- 2.20.1