From 36069d1446bff73b6691b62be5af7f5f4a90d8b5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Jun 2017 12:47:38 -0700 Subject: [PATCH] GE Debugger: Simple framework to load dumps. This tries to execute them within the context of the emulator as much as possible, so we don't have weird bugs. Going with a file type so we can easily load the dump by opening the file directly. --- CMakeLists.txt | 2 + Core/Core.vcxproj | 5 +- Core/Core.vcxproj.filters | 8 +- Core/FileSystems/BlobFileSystem.cpp | 137 ++++++++++++++++++++++++++++ Core/FileSystems/BlobFileSystem.h | 61 +++++++++++++ Core/HLE/HLETables.cpp | 1 + Core/HLE/HLETables.h | 1 + Core/HLE/sceKernelModule.cpp | 89 ++++++++++++------ Core/HLE/sceKernelModule.h | 2 + Core/Loaders.cpp | 26 +++--- Core/Loaders.h | 2 + Core/PSPLoaders.cpp | 19 +++- Core/PSPLoaders.h | 1 + GPU/Debugger/Record.cpp | 46 ++++++++++ GPU/Debugger/Record.h | 2 + UWP/CoreUWP/CoreUWP.vcxproj | 2 + UWP/CoreUWP/CoreUWP.vcxproj.filters | 6 ++ android/jni/Android.mk | 1 + 18 files changed, 363 insertions(+), 48 deletions(-) create mode 100644 Core/FileSystems/BlobFileSystem.cpp create mode 100644 Core/FileSystems/BlobFileSystem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3396b64866..6293e25b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1348,6 +1348,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/ELF/ParamSFO.cpp Core/ELF/ParamSFO.h Core/FileSystems/tlzrc.cpp + Core/FileSystems/BlobFileSystem.cpp + Core/FileSystems/BlobFileSystem.h Core/FileSystems/BlockDevices.cpp Core/FileSystems/BlockDevices.h Core/FileSystems/DirectoryFileSystem.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index ce2cb5033b..e02438f7f9 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -21,7 +21,8 @@ {533F1D30-D04D-47CC-AD71-20F658907E36} Core - + + @@ -183,6 +184,7 @@ + @@ -524,6 +526,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 234ff2172a..79da4d1df0 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -680,6 +680,9 @@ HLE\Libraries + + FileSystems + @@ -1250,10 +1253,13 @@ HLE\Libraries + + FileSystems + - + \ No newline at end of file diff --git a/Core/FileSystems/BlobFileSystem.cpp b/Core/FileSystems/BlobFileSystem.cpp new file mode 100644 index 0000000000..059e79199f --- /dev/null +++ b/Core/FileSystems/BlobFileSystem.cpp @@ -0,0 +1,137 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program 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, version 2.0 or later versions. + +// This program 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Core/FileSystems/BlobFileSystem.h" + +BlobFileSystem::BlobFileSystem(IHandleAllocator *hAlloc, FileLoader *fileLoader, std::string alias) +: alloc_(hAlloc), fileLoader_(fileLoader), alias_(alias) { +} + +BlobFileSystem::~BlobFileSystem() { + // TODO: Who deletes fileLoader? +} + +void BlobFileSystem::DoState(PointerWrap &p) { + // Not used in real emulation. +} + +std::vector BlobFileSystem::GetDirListing(std::string path) { + std::vector listing; + listing.push_back(GetFileInfo(alias_)); + return listing; +} + +u32 BlobFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) { + u32 newHandle = alloc_->GetNewHandle(); + entries_[newHandle] = 0; + return newHandle; +} + +void BlobFileSystem::CloseFile(u32 handle) { + alloc_->FreeHandle(handle); + entries_.erase(handle); +} + +size_t BlobFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { + auto entry = entries_.find(handle); + if (entry != entries_.end()) { + size_t readSize = fileLoader_->ReadAt(entry->second, size, pointer); + entry->second += readSize; + return readSize; + } + return 0; +} + +size_t BlobFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { + usec = 0; + return ReadFile(handle, pointer, size); +} + +size_t BlobFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) { + return 0; +} + +size_t BlobFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) { + return 0; +} + +size_t BlobFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { + auto entry = entries_.find(handle); + if (entry != entries_.end()) { + switch (type) { + case FILEMOVE_BEGIN: + entry->second = position; + break; + case FILEMOVE_CURRENT: + entry->second += position; + break; + case FILEMOVE_END: + entry->second = fileLoader_->FileSize() + position; + break; + } + return (size_t)entry->second; + } + return 0; +} + +PSPFileInfo BlobFileSystem::GetFileInfo(std::string filename) { + PSPFileInfo info{}; + info.name = alias_; + info.size = fileLoader_->FileSize(); + info.access = 0666; + info.exists = true; + info.type = FILETYPE_NORMAL; + return info; +} + +bool BlobFileSystem::OwnsHandle(u32 handle) { + auto entry = entries_.find(handle); + return entry != entries_.end(); +} + +int BlobFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) { + return -1; +} + +int BlobFileSystem::DevType(u32 handle) { + return -1; +} + +bool BlobFileSystem::MkDir(const std::string &dirname) { + return false; +} + +bool BlobFileSystem::RmDir(const std::string &dirname) { + return false; +} + +int BlobFileSystem::RenameFile(const std::string &from, const std::string &to) { + return -1; +} + +bool BlobFileSystem::RemoveFile(const std::string &filename) { + return false; +} + +bool BlobFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) { + outpath = fileLoader_->Path(); + return true; +} + +u64 BlobFileSystem::FreeSpace(const std::string &path) { + return 0; +} diff --git a/Core/FileSystems/BlobFileSystem.h b/Core/FileSystems/BlobFileSystem.h new file mode 100644 index 0000000000..c26f596dee --- /dev/null +++ b/Core/FileSystems/BlobFileSystem.h @@ -0,0 +1,61 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program 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, version 2.0 or later versions. + +// This program 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +// This is used for opening a debug file as a blob, and mounting it. + +#include +#include +#include "Core/Loaders.h" +#include "Core/FileSystems/FileSystem.h" + +class BlobFileSystem : public IFileSystem { +public: + BlobFileSystem(IHandleAllocator *hAlloc, FileLoader *fileLoader, std::string alias); + ~BlobFileSystem(); + + void DoState(PointerWrap &p) override; + std::vector GetDirListing(std::string path) override; + u32 OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override; + void CloseFile(u32 handle) override; + size_t ReadFile(u32 handle, u8 *pointer, s64 size) override; + size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override; + size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override; + size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override; + size_t SeekFile(u32 handle, s32 position, FileMove type) override; + PSPFileInfo GetFileInfo(std::string filename) override; + bool OwnsHandle(u32 handle) override; + int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; + int DevType(u32 handle) override; + int Flags() override { return 0; } + + bool MkDir(const std::string &dirname) override; + bool RmDir(const std::string &dirname) override; + int RenameFile(const std::string &from, const std::string &to) override; + bool RemoveFile(const std::string &filename) override; + bool GetHostPath(const std::string &inpath, std::string &outpath) override; + u64 FreeSpace(const std::string &path) override; + +private: + // File positions. + std::map entries_; + + IHandleAllocator *alloc_; + FileLoader *fileLoader_; + std::string alias_; +}; diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index b3efc7faac..16444c6e7d 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -92,6 +92,7 @@ const HLEFunction FakeSysCalls[] = { {NID_EXTENDRETURN, __KernelReturnFromExtendStack, "__KernelReturnFromExtendStack"}, {NID_MODULERETURN, __KernelReturnFromModuleFunc, "__KernelReturnFromModuleFunc"}, {NID_IDLE, __KernelIdle, "_sceKernelIdle"}, + {NID_GPUREPLAY, __KernelGPUReplay, "__KernelGPUReplay"}, }; const HLEFunction UtilsForUser[] = diff --git a/Core/HLE/HLETables.h b/Core/HLE/HLETables.h index 4349747a2c..2bc280f7fe 100644 --- a/Core/HLE/HLETables.h +++ b/Core/HLE/HLETables.h @@ -23,5 +23,6 @@ #define NID_EXTENDRETURN 0xbad0b0c9 #define NID_MODULERETURN 0xbad0d318 #define NID_IDLE 0x1d7e1d7e +#define NID_GPUREPLAY 0x9e45bd95 void RegisterAllModules(); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 85b8449c76..c654bd38ee 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -24,6 +24,7 @@ #include "Common/FileUtil.h" #include "Common/StringUtils.h" #include "Core/Config.h" +#include "Core/Core.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/HLETables.h" @@ -57,6 +58,7 @@ #include "Core/HLE/KernelWaitHelpers.h" #include "Core/ELF/ParamSFO.h" +#include "GPU/Debugger/Record.h" #include "GPU/GPU.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" @@ -1513,8 +1515,36 @@ u32 __KernelGetModuleGP(SceUID uid) } } -bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string) -{ +void __KernelLoadReset() { + // Wipe kernel here, loadexec should reset the entire system + if (__KernelIsRunning()) { + u32 error; + while (!loadedModules.empty()) { + SceUID moduleID = *loadedModules.begin(); + Module *module = kernelObjects.Get(moduleID, error); + if (module) { + module->Cleanup(); + } else { + // An invalid module. We need to remove it or we'll loop forever. + WARN_LOG(LOADER, "Invalid module still marked as loaded on loadexec"); + loadedModules.erase(moduleID); + } + } + + Replacement_Shutdown(); + __KernelShutdown(); + // HLE needs to be reset here + HLEShutdown(); + Replacement_Init(); + HLEInit(); + gpu->Reinitialize(); + } + + __KernelModuleInit(); + __KernelInit(); +} + +bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string) { SceKernelLoadExecParam param; if (paramPtr) @@ -1536,33 +1566,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str Memory::Memcpy(param_key, keyAddr, (u32)keylen); } - // Wipe kernel here, loadexec should reset the entire system - if (__KernelIsRunning()) - { - u32 error; - while (!loadedModules.empty()) { - SceUID moduleID = *loadedModules.begin(); - Module *module = kernelObjects.Get(moduleID, error); - if (module) { - module->Cleanup(); - } else { - // An invalid module. We need to remove it or we'll loop forever. - WARN_LOG(LOADER, "Invalid module still marked as loaded on loadexec"); - loadedModules.erase(moduleID); - } - } - - Replacement_Shutdown(); - __KernelShutdown(); - //HLE needs to be reset here - HLEShutdown(); - Replacement_Init(); - HLEInit(); - gpu->Reinitialize(); - } - - __KernelModuleInit(); - __KernelInit(); + __KernelLoadReset(); PSPFileInfo info = pspFileSystem.GetFileInfo(filename); if (!info.exists) { @@ -1635,6 +1639,33 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str return true; } +bool __KernelLoadGEDump(std::string *error_string) { + __KernelLoadReset(); + + mipsr4k.pc = PSP_GetUserMemoryBase(); + + const static u32_le runDumpCode[] = { + MIPS_MAKE_LUI(MIPS_REG_RA, mipsr4k.pc >> 16), + MIPS_MAKE_JR_RA(), + MIPS_MAKE_SYSCALL("FakeSysCalls", "__KernelGPUReplay"), + MIPS_MAKE_BREAK(0), + }; + + for (size_t i = 0; i < ARRAY_SIZE(runDumpCode); ++i) { + Memory::WriteUnchecked_U32(runDumpCode[i], mipsr4k.pc + (int)i * sizeof(u32_le)); + } + + __KernelStartIdleThreads(0); + return true; +} + +void __KernelGPUReplay() { + if (!GPURecord::RunMountedReplay()) { + Core_Stop(); + } + hleEatCycles(msToCycles(1001.0f / 60.0f)); +} + int sceKernelLoadExec(const char *filename, u32 paramPtr) { std::string exec_filename = filename; diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 70509d9f22..1c58a02548 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -39,7 +39,9 @@ void __KernelModuleDoState(PointerWrap &p); void __KernelModuleShutdown(); u32 __KernelGetModuleGP(SceUID module); +bool __KernelLoadGEDump(std::string *error_string); bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string); +void __KernelGPUReplay(); void __KernelReturnFromModuleFunc(); u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr, bool WithStatus); diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 20b7c5e346..ace145457d 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -69,31 +69,30 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { } std::string extension = fileLoader->Extension(); - if (!strcasecmp(extension.c_str(), ".iso")) - { + if (!strcasecmp(extension.c_str(), ".iso")) { // may be a psx iso, they have 2352 byte sectors. You never know what some people try to open - if ((fileLoader->FileSize() % 2352) == 0) - { + if ((fileLoader->FileSize() % 2352) == 0) { unsigned char sync[12]; fileLoader->ReadAt(0, 12, sync); // each sector in a mode2 image starts with these 12 bytes - if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00",12) == 0) - { + if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12) == 0) { return IdentifiedFileType::ISO_MODE2; } // maybe it also just happened to have that size, } return IdentifiedFileType::PSP_ISO; - } - else if (!strcasecmp(extension.c_str(),".cso")) - { + } else if (!strcasecmp(extension.c_str(), ".cso")) { return IdentifiedFileType::PSP_ISO; - } - else if (!strcasecmp(extension.c_str(),".ppst")) - { + } else if (!strcasecmp(extension.c_str(), ".ppst")) { return IdentifiedFileType::PPSSPP_SAVESTATE; + } else if (!strcasecmp(extension.c_str(), ".ppdmp")) { + char data[8]{}; + fileLoader->ReadAt(0, 8, data); + if (memcmp(data, "PPSSPPGE", 8) == 0) { + return IdentifiedFileType::PPSSPP_GE_DUMP; + } } // First, check if it's a directory with an EBOOT.PBP in it. @@ -337,6 +336,9 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { *error_string = "This is save data, not a game."; // Actually, we could make it load it... break; + case IdentifiedFileType::PPSSPP_GE_DUMP: + return Load_PSP_GE_Dump(fileLoader, error_string); + case IdentifiedFileType::UNKNOWN_BIN: case IdentifiedFileType::UNKNOWN_ELF: case IdentifiedFileType::UNKNOWN: diff --git a/Core/Loaders.h b/Core/Loaders.h index e6678c0bd0..faf9f78cc1 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -49,6 +49,8 @@ enum class IdentifiedFileType { PSP_SAVEDATA_DIRECTORY, PPSSPP_SAVESTATE, + PPSSPP_GE_DUMP, + UNKNOWN, }; diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 9f8066005d..193fe52b72 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -27,11 +27,12 @@ #include "Core/ELF/ElfReader.h" #include "Core/ELF/ParamSFO.h" -#include "FileSystems/BlockDevices.h" -#include "FileSystems/DirectoryFileSystem.h" -#include "FileSystems/ISOFileSystem.h" -#include "FileSystems/MetaFileSystem.h" -#include "FileSystems/VirtualDiscFileSystem.h" +#include "Core/FileSystems/BlockDevices.h" +#include "Core/FileSystems/BlobFileSystem.h" +#include "Core/FileSystems/DirectoryFileSystem.h" +#include "Core/FileSystems/ISOFileSystem.h" +#include "Core/FileSystems/MetaFileSystem.h" +#include "Core/FileSystems/VirtualDiscFileSystem.h" #include "Core/Loaders.h" #include "Core/MemMap.h" @@ -355,3 +356,11 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { return __KernelLoadExec(finalName.c_str(), 0, error_string); } + +bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) { + BlobFileSystem *umd = new BlobFileSystem(&pspFileSystem, fileLoader, "data.ppdmp"); + pspFileSystem.Mount("disc0:", umd); + + __KernelLoadGEDump(error_string); + return true; +} diff --git a/Core/PSPLoaders.h b/Core/PSPLoaders.h index 400df80d65..34f33ca177 100644 --- a/Core/PSPLoaders.h +++ b/Core/PSPLoaders.h @@ -23,5 +23,6 @@ class FileLoader; bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string); bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string); +bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string); void InitMemoryForGameISO(FileLoader *fileLoader); void InitMemoryForGamePBP(FileLoader *fileLoader); diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index c492378cd0..1ec72781a4 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -21,7 +21,10 @@ #include "base/stringutil.h" #include "Common/Common.h" #include "Common/FileUtil.h" +#include "Common/Log.h" +#include "Core/Core.h" #include "Core/ELF/ParamSFO.h" +#include "Core/FileSystems/MetaFileSystem.h" #include "Core/MemMap.h" #include "Core/System.h" #include "GPU/GPUState.h" @@ -412,4 +415,47 @@ void NotifyFrame() { } } +bool RunMountedReplay() { + _assert_msg_(SYSTEM, !active && !nextFrame, "Cannot run replay while recording."); + + u32 fp = pspFileSystem.OpenFile("disc0:/data.ppdmp", FILEACCESS_READ); + u8 header[8]{}; + int version = 0; + pspFileSystem.ReadFile(fp, header, sizeof(header)); + pspFileSystem.ReadFile(fp, (u8 *)&version, sizeof(version)); + + if (memcmp(header, HEADER, sizeof(HEADER)) != 0 || version != VERSION) { + ERROR_LOG(SYSTEM, "Invalid GE dump or unsupported version"); + return false; + } + + int sz = 0; + pspFileSystem.ReadFile(fp, (u8 *)&sz, sizeof(sz)); + int bufsz = 0; + pspFileSystem.ReadFile(fp, (u8 *)&bufsz, sizeof(bufsz)); + + commands.resize(sz); + for (int i = 0; i < sz; ++i) { + size_t read = 0; + read += pspFileSystem.ReadFile(fp, (u8 *)&commands[i].type, sizeof(commands[i].type)); + read += pspFileSystem.ReadFile(fp, (u8 *)&commands[i].sz, sizeof(commands[i].sz)); + read += pspFileSystem.ReadFile(fp, (u8 *)&commands[i].ptr, sizeof(commands[i].ptr)); + if (read != sizeof(commands[i].type) + sizeof(commands[i].sz) + sizeof(commands[i].ptr)) { + ERROR_LOG(SYSTEM, "Truncated GE dump"); + return false; + } + } + + pushbuf.resize(bufsz); + if (pspFileSystem.ReadFile(fp, pushbuf.data(), bufsz) != bufsz) { + ERROR_LOG(SYSTEM, "Truncated GE dump"); + return false; + } + + pspFileSystem.CloseFile(fp); + + // TODO: Execute commands. + return true; +} + }; diff --git a/GPU/Debugger/Record.h b/GPU/Debugger/Record.h index 9803671ecb..81a6c1bb8e 100644 --- a/GPU/Debugger/Record.h +++ b/GPU/Debugger/Record.h @@ -29,4 +29,6 @@ void NotifyMemset(u32 dest, int v, u32 sz); void NotifyUpload(u32 dest, u32 sz); void NotifyFrame(); +bool RunMountedReplay(); + }; diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 17d35ebbdc..9bb7322606 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -330,6 +330,7 @@ + @@ -521,6 +522,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index 2b20fc1219..0d7268912a 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -166,6 +166,9 @@ MIPS\x86 + + FileSystems + FileSystems @@ -674,6 +677,9 @@ MIPS\x86 + + FileSystems + FileSystems diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 501d2445cb..58242a4527 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -364,6 +364,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/HLE/sceGameUpdate.cpp \ $(SRC)/Core/HLE/sceNp.cpp \ $(SRC)/Core/HLE/scePauth.cpp \ + $(SRC)/Core/FileSystems/BlobFileSystem.cpp \ $(SRC)/Core/FileSystems/BlockDevices.cpp \ $(SRC)/Core/FileSystems/ISOFileSystem.cpp \ $(SRC)/Core/FileSystems/FileSystem.cpp \