From 6f85f02e2587fb4b892bcf0e61e38456cb7edd10 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 5 Nov 2012 12:02:09 +0100 Subject: [PATCH] Module loading fixes - proper module blacklisting, correct some error codes --- Core/FileSystems/DirectoryFileSystem.cpp | 8 +- Core/FileSystems/FileSystem.h | 5 +- Core/FileSystems/ISOFileSystem.cpp | 4 +- Core/HLE/sceKernelModule.cpp | 181 +++++++++++++++-------- Core/Util/BlockAllocator.h | 59 ++++---- 5 files changed, 165 insertions(+), 92 deletions(-) diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index a5e5e9006..14a79241c 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -237,7 +237,13 @@ size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { PSPFileInfo x; - x.size=0; + x.name = filename; + if (!File::Exists(filename)) { + return x; + } + + x.exists = true; + x.type = File::IsDirectory(filename) ? FILETYPE_NORMAL : FILETYPE_DIRECTORY; std::string fullName = GetLocalPath(filename); diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 90863c01b..8024461d1 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -53,10 +53,13 @@ public: struct PSPFileInfo { - PSPFileInfo() {size=0;access=0;type=FILETYPE_NORMAL;isOnSectorSystem=false;} + PSPFileInfo() + : size(0), access(0), exists(false), type(FILETYPE_NORMAL), isOnSectorSystem(false), startSector(0), numSectors(0) {} + std::string name; s64 size; u32 access; //unix 777 + bool exists; FileType type; bool isOnSectorSystem; diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index 3809fc4d6..c0005542c 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -435,13 +435,15 @@ PSPFileInfo ISOFileSystem::GetFileInfo(std::string filename) PSPFileInfo x; if (!entry) { - x.size=0; + x.size = 0; + x.exists = false; } else { x.name = entry->name; x.access = FILEACCESS_READ; x.size = entry->size; + x.exists = true; x.type = entry->isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; x.isOnSectorSystem = true; x.startSector = entry->startingPosition/2048; diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 81bbf65cf..27a89ad4e 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -18,6 +18,7 @@ #include #include "HLE.h" +#include "Common/FileUtil.h" #include "../Host.h" #include "../MIPS/MIPS.h" #include "../MIPS/MIPSAnalyst.h" @@ -40,6 +41,30 @@ enum { PSP_THREAD_ATTR_USER = 0x80000000 }; +static const char *blacklistedModules[] = { + "LIBFONT", + "sc_sascore", + "audiocodec", + "libatrac3plus", + "videocodec", + "mpegbase", + "mpeg", + "psmf", + "pspnet", + "pspnet_adhoc", + "pspnet_adhocctl", + "pspnet_adhoc_matching", + "pspnet_adhoc_download", + "pspnet_apctl", + "pspnet_resolver", + "pspnet_ap_dialog_dummy", + "libparse_uri", + "libparse_http", + "libhttp_rfc", + "libssl", + "libsuppreacc", +}; + struct Module : public KernelObject { const char *GetName() {return name;} @@ -178,12 +203,6 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro else modinfo = (PspModuleInfo *)reader.GetPtr(reader.GetSegmentPaddr(0) + reader.GetSegmentOffset(0)); - // Check for module "blacklist" - if a module has the same name as a HLE'd module, we don't load it. - if (GetModuleIndex(modinfo->name) >= 0) { - ERROR_LOG(LOADER, "The module %s is HLE'd - ignoring in __KernelLoadELFFromPtr()", modinfo->name); - return 0; - } - bool hasSymbols = false; bool dontadd = false; @@ -265,10 +284,8 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro DEBUG_LOG(LOADER,"-------------------------------------------------------------"); } - // Look at the exports, too. -#pragma pack(push, 1) struct PspLibEntEntry { u32 name; /* ent's name (module name) address */ @@ -279,7 +296,6 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro u16 fcount; u32 resident; }; -#pragma pack(pop) int numEnts = (modinfo->libentend - modinfo->libent)/sizeof(PspLibEntEntry); PspLibEntEntry *ent = (PspLibEntEntry *)Memory::GetPointer(modinfo->libent); @@ -366,10 +382,10 @@ bool __KernelLoadPBP(const char *filename, std::string *error_string) { u8 *temp = new u8[1024*1024*8]; in.read((char*)temp, 1024*1024*8); - Module *m = __KernelLoadELFFromPtr(temp, PSP_GetDefaultLoadAddress(), error_string); - if (!m) + Module *module = __KernelLoadELFFromPtr(temp, PSP_GetDefaultLoadAddress(), error_string); + if (!module) return false; - mipsr4k.pc = m->entry_addr; + mipsr4k.pc = module->entry_addr; delete [] temp; } in.close(); @@ -379,7 +395,7 @@ bool __KernelLoadPBP(const char *filename, std::string *error_string) Module *__KernelLoadModule(u8 *fileptr, SceKernelLMOption *options, std::string *error_string) { - Module *m = 0; + Module *module = 0; // Check for PBP if (memcmp(fileptr, "\0PBP", 4) == 0) { @@ -394,14 +410,14 @@ Module *__KernelLoadModule(u8 *fileptr, SceKernelLMOption *options, std::string offsets[0] = offset0; for (int i = 1; i < numfiles; i++) memcpy(&offsets[i], fileptr + 12 + 4*i, 4); - m = __KernelLoadELFFromPtr(fileptr + offsets[5], PSP_GetDefaultLoadAddress(), error_string); + module = __KernelLoadELFFromPtr(fileptr + offsets[5], PSP_GetDefaultLoadAddress(), error_string); } else { - m = __KernelLoadELFFromPtr(fileptr, PSP_GetDefaultLoadAddress(), error_string); + module = __KernelLoadELFFromPtr(fileptr, PSP_GetDefaultLoadAddress(), error_string); } - return m; + return module; } void __KernelStartModule(Module *m, int args, const char *argp, SceKernelSMOption *options) @@ -430,19 +446,14 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std:: { // Wipe kernel here, loadexec should reset the entire system __KernelInit(); - + PSPFileInfo info = pspFileSystem.GetFileInfo(filename); - s64 size = (s64)info.size; - if (!size) - { - ERROR_LOG(LOADER, "File is size 0: %s", filename); - return false; - } + u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); - u8 *temp = new u8[(int)size]; + u8 *temp = new u8[(int)info.size]; - pspFileSystem.ReadFile(handle, temp, (size_t)size); + pspFileSystem.ReadFile(handle, temp, (size_t)info.size); Module *m = __KernelLoadModule(temp, 0, error_string); @@ -475,65 +486,115 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std:: //TODO: second param void sceKernelLoadExec() { - const char *name = Memory::GetCharPointer(PARAM(0)); + const char *filename = Memory::GetCharPointer(PARAM(0)); SceKernelLoadExecParam *param = 0; if (PARAM(1)) { param = (SceKernelLoadExecParam*)Memory::GetPointer(PARAM(1)); } - DEBUG_LOG(HLE,"sceKernelLoadExec(name=%s,...)", name); + + PSPFileInfo info = pspFileSystem.GetFileInfo(filename); + + if (!info.exists) { + ERROR_LOG(LOADER, "sceKernelLoadExec(%s, ...): File does not exist", filename); + RETURN(SCE_KERNEL_ERROR_NOFILE); + return; + } + + s64 size = (s64)info.size; + if (!size) + { + ERROR_LOG(LOADER, "sceKernelLoadExec(%s, ...): File is size 0", filename); + RETURN(SCE_KERNEL_ERROR_ILLEGAL_OBJECT); + return; + } + + DEBUG_LOG(HLE,"sceKernelLoadExec(name=%s,...)", filename); std::string error_string; - if (!__KernelLoadExec(name, param, &error_string)) + if (!__KernelLoadExec(filename, param, &error_string)) { ERROR_LOG(HLE, "sceKernelLoadExec failed: %s", error_string.c_str()); + } } u32 sceKernelLoadModule(const char *name, u32 flags) { - PSPFileInfo info = pspFileSystem.GetFileInfo(name); - std::string error_string; - s64 size = (s64)info.size; - - if (!size) - { - ERROR_LOG(LOADER, "Module file is size 0: %s", name); - return false; - } + PSPFileInfo info = pspFileSystem.GetFileInfo(name); + std::string error_string; + s64 size = (s64)info.size; - u32 handle = pspFileSystem.OpenFile(name, FILEACCESS_READ); + if (!info.exists) { + ERROR_LOG(LOADER, "sceKernelLoadModule(%s, %08x): File does not exist", name, flags); + return SCE_KERNEL_ERROR_NOFILE; + } - u8 *temp = new u8[(int)size]; - - pspFileSystem.ReadFile(handle, temp, (size_t)size); - - Module *m = __KernelLoadELFFromPtr(temp, 0, &error_string); - - if (!m) { - ERROR_LOG(LOADER, "Failed to load module %s", name); - return false; - } - - delete [] temp; - - pspFileSystem.CloseFile(handle); + if (!size) + { + ERROR_LOG(LOADER, "sceKernelLoadModule(%s, %08x): Module file is size 0", name, flags); + return SCE_KERNEL_ERROR_ILLEGAL_OBJECT; + } + SceKernelLMOption *lmoption = 0; + int position = 0; + // TODO: Use position to decide whether to load high or low if (PARAM(2)) { - SceKernelLMOption *lmoption= (SceKernelLMOption *)Memory::GetPointer(PARAM(2)); + SceKernelLMOption *lmoption = (SceKernelLMOption *)Memory::GetPointer(PARAM(2)); + } - //TODO: Check if module name is in "blacklist" (HLE:d list) - //If it is, don't load it. - //Else, actually do load it and resolve pointers! + std::string fn(name); + int slashPos = fn.rfind('/'); + if (slashPos != -1) + fn = fn.substr(slashPos + 1); + + // Check for module blacklist - we don't allow games to load these modules from disc + // as we have HLE implementations and the originals won't run in the emu because they + // directly access hardware or for other reasons. + bool blacklisted = false; + std::string guessedModuleName = fn.substr(0, fn.size() - 4); + if (GetModuleIndex(guessedModuleName.c_str()) >= 0) { + blacklisted = true; + } + for (int i = 0; i < ARRAY_SIZE(blacklistedModules); i++) { + if (guessedModuleName == blacklistedModules[i]) { + blacklisted = true; + break; + } + } - INFO_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,%08x(...))", - m->GetUID(),name,flags, + Module *module = 0; + if (!blacklisted) { + u8 *temp = new u8[(int)size]; + u32 handle = pspFileSystem.OpenFile(name, FILEACCESS_READ); + pspFileSystem.ReadFile(handle, temp, (size_t)size); + module = __KernelLoadELFFromPtr(temp, 0, &error_string); + delete [] temp; + pspFileSystem.CloseFile(handle); + } + + if (!module) { + // Lie about successfully loading blacklisted modules. + // Plus: Temporary hack until we have decryption: Lie that we succeeded. Helps compat. + if (error_string == "Executable encrypted - not yet supported" || blacklisted) + { + NOTICE_LOG(LOADER, "Module %s is blacklisted or encrypted - we lie about success", name); + return 1; + } + + ERROR_LOG(LOADER, "Failed to load module %s", name); + return SCE_KERNEL_ERROR_ILLEGAL_OBJECT; + } + + if (lmoption) { + INFO_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,position = %08x)", + module->GetUID(),name,flags, lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position); } else { - INFO_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,(...))", m->GetUID(), name, flags); + INFO_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,(...))", module->GetUID(), name, flags); } - return m->GetUID(); + return module->GetUID(); } void sceKernelStartModule() diff --git a/Core/Util/BlockAllocator.h b/Core/Util/BlockAllocator.h index 7974b6733..072efdae3 100644 --- a/Core/Util/BlockAllocator.h +++ b/Core/Util/BlockAllocator.h @@ -13,6 +13,36 @@ class BlockAllocator { +public: + BlockAllocator(); + ~BlockAllocator(); + + void Init(u32 _rangeStart, u32 _rangeSize); + void Shutdown(); + + void ListBlocks(); + + // WARNING: size can be modified upwards! + u32 Alloc(u32 &size, bool fromTop = false, const char *tag = 0); + u32 AllocAt(u32 position, u32 size, const char *tag = 0); + + void Free(u32 position); + bool IsBlockFree(u32 position) { + Block *b = GetBlockFromAddress(position); + if (b) + return !b->taken; + else + return false; + } + + void MergeFreeBlocks(); + + u32 GetBlockStartFromAddress(u32 addr); + u32 GetBlockSizeFromAddress(u32 addr); + u32 GetLargestFreeBlockSize(); + u32 GetTotalFreeBytes(); + +private: struct Block { Block(u32 _start, u32 _size, bool _taken) : start(_start), size(_size), taken(_taken) @@ -35,33 +65,4 @@ class BlockAllocator Block *GetBlockFromAddress(u32 addr); std::list::iterator GetBlockIterFromAddress(u32 addr); - -public: - BlockAllocator(); - ~BlockAllocator(); - - void Init(u32 _rangeStart, u32 _rangeSize); - void Shutdown(); - - void ListBlocks(); - - // WARNING: size can be modified upwards! - u32 Alloc(u32 &size, bool fromEnd = false, const char *tag = 0); - u32 AllocAt(u32 position, u32 size, const char *tag = 0); - - void Free(u32 position); - bool IsBlockFree(u32 position) { - Block *b = GetBlockFromAddress(position); - if (b) - return !b->taken; - else - return false; - } - - void MergeFreeBlocks(); - - u32 GetBlockStartFromAddress(u32 addr); - u32 GetBlockSizeFromAddress(u32 addr); - u32 GetLargestFreeBlockSize(); - u32 GetTotalFreeBytes(); };