diff options
Diffstat (limited to 'src/core')
44 files changed, 286 insertions, 270 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index fd0786068..89ae79eb3 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -395,7 +395,7 @@ static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_ if (base.size() < begin + length) return false; return std::all_of(base.begin() + begin, base.begin() + begin + length, - [](u8 c) { return std::isdigit(c); }); + [](u8 c) { return std::isxdigit(c); }); } void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { @@ -713,7 +713,6 @@ void KeyManager::DeriveBase() { const auto sbk = GetKey(S128KeyType::SecureBoot); const auto tsec = GetKey(S128KeyType::TSEC); - const auto master_source = GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Master)); for (size_t i = 0; i < revisions.size(); ++i) { if (!revisions[i]) diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index ecdd7505b..1ece55731 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -168,10 +168,6 @@ VirtualDir XCI::GetParentDirectory() const { return file->GetContainingDirectory(); } -bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - return false; -} - Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { if (partitions[static_cast<std::size_t>(part)] == nullptr) { return Loader::ResultStatus::ErrorXCIMissingPartition; diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 48cbef666..8f62571cf 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -94,9 +94,6 @@ public: VirtualDir GetParentDirectory() const override; -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: Loader::ResultStatus AddNCAFromPartition(XCIPartition part); diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 6c356d85d..77e04704e 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -546,7 +546,4 @@ u64 NCA::GetBaseIVFCOffset() const { return ivfc_offset; } -bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - return false; -} } // namespace FileSys diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 1c903cd3f..211946686 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -100,9 +100,6 @@ public: // Returns the base ivfc offset used in BKTR patching. u64 GetBaseIVFCOffset() const; -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: bool CheckSupportedNCA(const NCAHeader& header); bool HandlePotentialHeaderDecryption(); diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index 554eae9bc..999939d5a 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp @@ -99,7 +99,7 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { u16 rle_size{}; if (ips->ReadObject(&rle_size, offset) != sizeof(u16)) return nullptr; - rle_size = Common::swap16(data_size); + rle_size = Common::swap16(rle_size); offset += sizeof(u16); const auto data = ips->ReadByte(offset++); diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 5791c76ff..a5259a593 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -83,7 +83,7 @@ std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const { } std::vector<std::shared_ptr<VfsDirectory>> PartitionFilesystem::GetSubdirectories() const { - return pfs_dirs; + return {}; } std::string PartitionFilesystem::GetName() const { @@ -103,18 +103,4 @@ void PartitionFilesystem::PrintDebugInfo() const { pfs_files[i]->GetName(), pfs_files[i]->GetSize()); } } - -bool PartitionFilesystem::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - const auto iter = std::find(pfs_files.begin(), pfs_files.end(), file); - if (iter == pfs_files.end()) - return false; - - const std::ptrdiff_t offset = std::distance(pfs_files.begin(), iter); - pfs_files[offset] = std::move(pfs_files.back()); - pfs_files.pop_back(); - - pfs_dirs.emplace_back(std::move(dir)); - - return true; -} } // namespace FileSys diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h index 739c63a7f..248fdfdeb 100644 --- a/src/core/file_sys/partition_filesystem.h +++ b/src/core/file_sys/partition_filesystem.h @@ -35,9 +35,6 @@ public: std::shared_ptr<VfsDirectory> GetParentDirectory() const override; void PrintDebugInfo() const; -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: struct Header { u32_le magic; @@ -84,7 +81,6 @@ private: std::size_t content_offset = 0; std::vector<VirtualFile> pfs_files; - std::vector<VirtualDir> pfs_dirs; }; } // namespace FileSys diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 1f4928562..cb457b987 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -61,13 +61,12 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { // Game Updates const auto update_tid = GetUpdateTitleID(title_id); const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); - if (update != nullptr) { - if (update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && - update->GetExeFS() != nullptr) { - LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", - FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); - exefs = update->GetExeFS(); - } + + if (update != nullptr && update->GetExeFS() != nullptr && + update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { + LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", + FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); + exefs = update->GetExeFS(); } return exefs; diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index ab5dc900c..2aaba4179 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp @@ -205,10 +205,6 @@ VirtualDir NSP::GetParentDirectory() const { return file->GetContainingDirectory(); } -bool NSP::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - return false; -} - void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) { exefs = pfs; diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index da3dc5e9f..338080b7e 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h @@ -55,9 +55,6 @@ public: VirtualDir GetParentDirectory() const override; -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files); void ReadNCAs(const std::vector<VirtualFile>& files); diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index bfe50da73..3824c74e0 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -472,10 +472,14 @@ bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t blo std::vector<u8> temp(std::min(block_size, src->GetSize())); for (std::size_t i = 0; i < src->GetSize(); i += block_size) { const auto read = std::min(block_size, src->GetSize() - i); - const auto block = src->Read(temp.data(), read, i); - if (dest->Write(temp.data(), read, i) != read) + if (src->Read(temp.data(), read, i) != read) { return false; + } + + if (dest->Write(temp.data(), read, i) != read) { + return false; + } } return true; diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 7f0d520ca..09dc9f288 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -262,36 +262,8 @@ public: // item name -> type. virtual std::map<std::string, VfsEntryType, std::less<>> GetEntries() const; - // Interprets the file with name file instead as a directory of type directory. - // The directory must have a constructor that takes a single argument of type - // std::shared_ptr<VfsFile>. Allows to reinterpret container files (i.e NCA, zip, XCI, etc) as a - // subdirectory in one call. - template <typename Directory> - bool InterpretAsDirectory(std::string_view file) { - auto file_p = GetFile(file); - - if (file_p == nullptr) { - return false; - } - - return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p)); - } - - bool InterpretAsDirectory(const std::function<VirtualDir(VirtualFile)>& function, - const std::string& file) { - auto file_p = GetFile(file); - if (file_p == nullptr) - return false; - return ReplaceFileWithSubdirectory(file_p, function(file_p)); - } - // Returns the full path of this directory as a string, recursively virtual std::string GetFullPath() const; - -protected: - // Backend for InterpretAsDirectory. - // Removes all references to file and adds a reference to dir in the directory's implementation. - virtual bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) = 0; }; // A convenience partial-implementation of VfsDirectory that stubs out methods that should only work diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp index bfee01725..338e398da 100644 --- a/src/core/file_sys/vfs_layered.cpp +++ b/src/core/file_sys/vfs_layered.cpp @@ -126,7 +126,4 @@ bool LayeredVfsDirectory::Rename(std::string_view name_) { return true; } -bool LayeredVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - return false; -} } // namespace FileSys diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h index d85310f57..8a25c3428 100644 --- a/src/core/file_sys/vfs_layered.h +++ b/src/core/file_sys/vfs_layered.h @@ -39,9 +39,6 @@ public: bool DeleteFile(std::string_view name) override; bool Rename(std::string_view name) override; -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: std::vector<VirtualDir> dirs; std::string name; diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 9defad04c..e21300a7c 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -430,7 +430,4 @@ std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() return out; } -bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - return false; -} } // namespace FileSys diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 5b61db90d..a0a857a31 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -100,9 +100,6 @@ public: std::string GetFullPath() const override; std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override; -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index 389c7e003..808f31e81 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp @@ -132,11 +132,4 @@ void VectorVfsDirectory::AddFile(VirtualFile file) { void VectorVfsDirectory::AddDirectory(VirtualDir dir) { dirs.push_back(std::move(dir)); } - -bool VectorVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - if (!DeleteFile(file->GetName())) - return false; - dirs.emplace_back(std::move(dir)); - return true; -} } // namespace FileSys diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index 48a414c98..3e3f790c3 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h @@ -57,9 +57,6 @@ public: virtual void AddFile(VirtualFile file); virtual void AddDirectory(VirtualDir dir); -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: std::vector<VirtualFile> files; std::vector<VirtualDir> dirs; diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index b2b164368..eec51c64e 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -163,7 +163,4 @@ std::shared_ptr<VfsDirectory> NAX::GetParentDirectory() const { return file->GetContainingDirectory(); } -bool NAX::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - return false; -} } // namespace FileSys diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h index 8fedd8585..7704dee90 100644 --- a/src/core/file_sys/xts_archive.h +++ b/src/core/file_sys/xts_archive.h @@ -51,9 +51,6 @@ public: std::shared_ptr<VfsDirectory> GetParentDirectory() const override; -protected: - bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; - private: Loader::ResultStatus Parse(std::string_view path); diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 419f45896..ed84197b3 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -14,11 +14,6 @@ namespace IPC { /// Size of the command buffer area, in 32-bit words. constexpr std::size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32); -// These errors are commonly returned by invalid IPC translations, so alias them here for -// convenience. -// TODO(yuriks): These will probably go away once translation is implemented inside the kernel. -constexpr auto ERR_INVALID_HANDLE = Kernel::ERR_INVALID_HANDLE_OS; - enum class ControlCommand : u32 { ConvertSessionToDomain = 0, ConvertDomainToSession = 1, diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 885259618..ee698c8a7 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -10,11 +10,6 @@ namespace Kernel { namespace ErrCodes { enum { - // TODO(Subv): Remove these 3DS OS error codes. - SessionClosedByRemote = 26, - NoPendingSessions = 35, - InvalidBufferDescriptor = 48, - // Confirmed Switch OS error codes MaxConnectionsReached = 7, InvalidSize = 101, @@ -26,6 +21,7 @@ enum { InvalidThreadPriority = 112, InvalidProcessorId = 113, InvalidHandle = 114, + InvalidPointer = 115, InvalidCombination = 116, Timeout = 117, SynchronizationCanceled = 118, @@ -33,6 +29,7 @@ enum { InvalidEnumValue = 120, NoSuchEntry = 121, AlreadyRegistered = 122, + SessionClosed = 123, InvalidState = 125, ResourceLimitExceeded = 132, }; @@ -41,18 +38,14 @@ enum { // WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always // double check that the code matches before re-using the constant. -// TODO(bunnei): Replace -1 with correct errors for Switch OS constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); -constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); +constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(ErrorModule::Kernel, ErrCodes::SessionClosed); constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(ErrorModule::Kernel, ErrCodes::MaxConnectionsReached); constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue); -constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1); -constexpr ResultCode ERR_INVALID_COMBINATION(-1); constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(ErrorModule::Kernel, ErrCodes::InvalidCombination); -constexpr ResultCode ERR_OUT_OF_MEMORY(-1); constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress); constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, @@ -65,14 +58,8 @@ constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::Alrea constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, ErrCodes::InvalidThreadPriority); -constexpr ResultCode ERR_INVALID_POINTER(-1); -constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); -constexpr ResultCode ERR_NOT_AUTHORIZED(-1); -/// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths. -constexpr ResultCode ERR_INVALID_HANDLE_OS(-1); +constexpr ResultCode ERR_INVALID_POINTER(ErrorModule::Kernel, ErrCodes::InvalidPointer); constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry); constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout); -/// Returned when Accept() is called on a port with no sessions to be accepted. -constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1); } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 073dd5a7d..420218d59 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -232,6 +232,12 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); + + // Clear instruction cache in CPU JIT + Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); + Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); + Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); + Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); } ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 3792e3e18..d6ceeb2da 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -18,7 +18,7 @@ ServerPort::~ServerPort() = default; ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { if (pending_sessions.empty()) { - return ERR_NO_PENDING_SESSIONS; + return ERR_NOT_FOUND; } auto session = std::move(pending_sessions.back()); @@ -28,7 +28,7 @@ ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { bool ServerPort::ShouldWait(Thread* thread) const { // If there are no pending sessions, we wait until a new one is added. - return pending_sessions.size() == 0; + return pending_sessions.empty(); } void ServerPort::Acquire(Thread* thread) { diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index d061e6155..a016a86b6 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -80,20 +80,19 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet( ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions) { - - MemoryPermission own_other_permissions = + const MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions; // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { - return ERR_INVALID_COMBINATION; + return ERR_INVALID_MEMORY_PERMISSIONS; } // Error out if the requested permissions don't match what the creator process allows. if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", GetObjectId(), address, name); - return ERR_INVALID_COMBINATION; + return ERR_INVALID_MEMORY_PERMISSIONS; } // Error out if the provided permissions are not compatible with what the creator process needs. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9a783d524..a5302d924 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -594,16 +594,17 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { } const auto* const current_process = Core::CurrentProcess(); - SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); - if (!thread) { - return ERR_INVALID_HANDLE; - } // Note: The kernel uses the current process's resource limit instead of // the one from the thread owner's resource limit. const ResourceLimit& resource_limit = current_process->GetResourceLimit(); if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { - return ERR_NOT_AUTHORIZED; + return ERR_INVALID_THREAD_PRIORITY; + } + + SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + if (!thread) { + return ERR_INVALID_HANDLE; } thread->SetPriority(priority); @@ -745,7 +746,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V auto* const current_process = Core::CurrentProcess(); const ResourceLimit& resource_limit = current_process->GetResourceLimit(); if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { - return ERR_NOT_AUTHORIZED; + return ERR_INVALID_THREAD_PRIORITY; } if (processor_id == THREADPROCESSORID_DEFAULT) { diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index e1a34eef1..1a92c8f70 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -143,6 +143,26 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); } +ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const { + // Find the first Free VMA. + const VAddr base = GetASLRRegionBaseAddress(); + const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { + if (vma.second.type != VMAType::Free) + return false; + + const VAddr vma_end = vma.second.base + vma.second.size; + return vma_end > base && vma_end >= base + size; + }); + + if (vma_handle == vma_map.end()) { + // TODO(Subv): Find the correct error code here. + return ResultCode(-1); + } + + const VAddr target = std::max(base, vma_handle->second.base); + return MakeResult<VAddr>(target); +} + ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size, MemoryState state, Memory::MemoryHookPointer mmio_handler) { diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 84c890224..2447cbb8f 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -158,6 +158,14 @@ public: ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); /** + * Finds the first free address that can hold a region of the desired size. + * + * @param size Size of the desired region. + * @return The found free address. + */ + ResultVal<VAddr> FindFreeRegion(u64 size) const; + + /** * Maps a memory-mapped IO region at a given address. * * @param target The guest address to start the mapping at. diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index cf065c2e0..c6437a671 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -21,8 +21,6 @@ namespace Service::Account { -constexpr u32 MAX_JPEG_IMAGE_SIZE = 0x20000; - // TODO: RE this structure struct UserData { INSERT_PADDING_WORDS(1); @@ -34,11 +32,29 @@ struct UserData { }; static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); +// Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg +// used as a backup should the one on disk not exist +constexpr u32 backup_jpeg_size = 107; +constexpr std::array<u8, backup_jpeg_size> backup_jpeg{{ + 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, + 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, + 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, + 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x11, 0x00, 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, + 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, +}}; + static std::string GetImagePath(UUID uuid) { return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; } +static constexpr u32 SanitizeJPEGSize(std::size_t size) { + constexpr std::size_t max_jpeg_image_size = 0x20000; + return static_cast<u32>(std::min(size, max_jpeg_image_size)); +} + class IProfile final : public ServiceFramework<IProfile> { public: explicit IProfile(UUID user_id, ProfileManager& profile_manager) @@ -86,43 +102,29 @@ private: void LoadImage(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "called"); - // smallest jpeg https://github.com/mathiasbynens/small/blob/master/jpeg.jpg - // used as a backup should the one on disk not exist - constexpr u32 backup_jpeg_size = 107; - static constexpr std::array<u8, backup_jpeg_size> backup_jpeg{ - 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, - 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x08, 0x06, 0x06, 0x05, 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, - 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, - 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, - 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x11, 0x00, - 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, - 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, - }; IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); const FileUtil::IOFile image(GetImagePath(user_id), "rb"); - if (!image.IsOpen()) { LOG_WARNING(Service_ACC, "Failed to load user provided image! Falling back to built-in backup..."); ctx.WriteBuffer(backup_jpeg); rb.Push<u32>(backup_jpeg_size); - } else { - const auto size = std::min<u32>(image.GetSize(), MAX_JPEG_IMAGE_SIZE); - std::vector<u8> buffer(size); - image.ReadBytes(buffer.data(), buffer.size()); - - ctx.WriteBuffer(buffer.data(), buffer.size()); - rb.Push<u32>(buffer.size()); + return; } + + const u32 size = SanitizeJPEGSize(image.GetSize()); + std::vector<u8> buffer(size); + image.ReadBytes(buffer.data(), buffer.size()); + + ctx.WriteBuffer(buffer.data(), buffer.size()); + rb.Push<u32>(size); } void GetImageSize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "called"); - constexpr u32 backup_jpeg_size = 107; IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -133,7 +135,7 @@ private: "Failed to load user provided image! Falling back to built-in backup..."); rb.Push<u32>(backup_jpeg_size); } else { - rb.Push<u32>(std::min<u32>(image.GetSize(), MAX_JPEG_IMAGE_SIZE)); + rb.Push<u32>(SanitizeJPEGSize(image.GetSize())); } } diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 06f7d1b15..3cac1b4ff 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include <random> -#include <boost/optional.hpp> + #include "common/file_util.h" #include "core/hle/service/acc/profile_manager.h" #include "core/settings.h" @@ -58,11 +58,11 @@ ProfileManager::~ProfileManager() { /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the /// internal management of the users profiles -boost::optional<std::size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { +std::optional<std::size_t> ProfileManager::AddToProfiles(const ProfileInfo& profile) { if (user_count >= MAX_USERS) { - return boost::none; + return {}; } - profiles[user_count] = user; + profiles[user_count] = profile; return user_count++; } @@ -81,7 +81,7 @@ bool ProfileManager::RemoveProfileAtIndex(std::size_t index) { /// Helper function to register a user to the system ResultCode ProfileManager::AddUser(const ProfileInfo& user) { - if (AddToProfiles(user) == boost::none) { + if (!AddToProfiles(user)) { return ERROR_TOO_MANY_USERS; } return RESULT_SUCCESS; @@ -126,37 +126,40 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) return CreateNewUser(uuid, username_output); } -boost::optional<UUID> ProfileManager::GetUser(std::size_t index) const { - if (index >= MAX_USERS) - return boost::none; +std::optional<UUID> ProfileManager::GetUser(std::size_t index) const { + if (index >= MAX_USERS) { + return {}; + } + return profiles[index].user_uuid; } /// Returns a users profile index based on their user id. -boost::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { +std::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { if (!uuid) { - return boost::none; + return {}; } - auto iter = std::find_if(profiles.begin(), profiles.end(), - [&uuid](const ProfileInfo& p) { return p.user_uuid == uuid; }); + + const auto iter = std::find_if(profiles.begin(), profiles.end(), + [&uuid](const ProfileInfo& p) { return p.user_uuid == uuid; }); if (iter == profiles.end()) { - return boost::none; + return {}; } + return static_cast<std::size_t>(std::distance(profiles.begin(), iter)); } /// Returns a users profile index based on their profile -boost::optional<std::size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const { +std::optional<std::size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const { return GetUserIndex(user.user_uuid); } /// Returns the data structure used by the switch when GetProfileBase is called on acc:* -bool ProfileManager::GetProfileBase(boost::optional<std::size_t> index, - ProfileBase& profile) const { - if (index == boost::none || index >= MAX_USERS) { +bool ProfileManager::GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const { + if (!index || index >= MAX_USERS) { return false; } - const auto& prof_info = profiles[index.get()]; + const auto& prof_info = profiles[*index]; profile.user_uuid = prof_info.user_uuid; profile.username = prof_info.username; profile.timestamp = prof_info.creation_time; @@ -165,7 +168,7 @@ bool ProfileManager::GetProfileBase(boost::optional<std::size_t> index, /// Returns the data structure used by the switch when GetProfileBase is called on acc:* bool ProfileManager::GetProfileBase(UUID uuid, ProfileBase& profile) const { - auto idx = GetUserIndex(uuid); + const auto idx = GetUserIndex(uuid); return GetProfileBase(idx, profile); } @@ -192,7 +195,7 @@ std::size_t ProfileManager::GetOpenUserCount() const { /// Checks if a user id exists in our profile manager bool ProfileManager::UserExists(UUID uuid) const { - return (GetUserIndex(uuid) != boost::none); + return GetUserIndex(uuid) != std::nullopt; } bool ProfileManager::UserExistsIndex(std::size_t index) const { @@ -203,21 +206,23 @@ bool ProfileManager::UserExistsIndex(std::size_t index) const { /// Opens a specific user void ProfileManager::OpenUser(UUID uuid) { - auto idx = GetUserIndex(uuid); - if (idx == boost::none) { + const auto idx = GetUserIndex(uuid); + if (!idx) { return; } - profiles[idx.get()].is_open = true; + + profiles[*idx].is_open = true; last_opened_user = uuid; } /// Closes a specific user void ProfileManager::CloseUser(UUID uuid) { - auto idx = GetUserIndex(uuid); - if (idx == boost::none) { + const auto idx = GetUserIndex(uuid); + if (!idx) { return; } - profiles[idx.get()].is_open = false; + + profiles[*idx].is_open = false; } /// Gets all valid user ids on the system @@ -247,10 +252,10 @@ UUID ProfileManager::GetLastOpenedUser() const { } /// Return the users profile base and the unknown arbitary data. -bool ProfileManager::GetProfileBaseAndData(boost::optional<std::size_t> index, ProfileBase& profile, +bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile, ProfileData& data) const { if (GetProfileBase(index, profile)) { - data = profiles[index.get()].data; + data = profiles[*index].data; return true; } return false; @@ -259,7 +264,7 @@ bool ProfileManager::GetProfileBaseAndData(boost::optional<std::size_t> index, P /// Return the users profile base and the unknown arbitary data. bool ProfileManager::GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const { - auto idx = GetUserIndex(uuid); + const auto idx = GetUserIndex(uuid); return GetProfileBaseAndData(idx, profile, data); } @@ -277,8 +282,8 @@ bool ProfileManager::CanSystemRegisterUser() const { } bool ProfileManager::RemoveUser(UUID uuid) { - auto index = GetUserIndex(uuid); - if (index == boost::none) { + const auto index = GetUserIndex(uuid); + if (!index) { return false; } @@ -289,8 +294,8 @@ bool ProfileManager::RemoveUser(UUID uuid) { } bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { - auto index = GetUserIndex(uuid); - if (profile_new.user_uuid == UUID(INVALID_UUID) || index == boost::none) { + const auto index = GetUserIndex(uuid); + if (!index || profile_new.user_uuid == UUID(INVALID_UUID)) { return false; } diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 235208d56..1cd2e51b2 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -5,8 +5,8 @@ #pragma once #include <array> +#include <optional> -#include "boost/optional.hpp" #include "common/common_types.h" #include "common/swap.h" #include "core/hle/result.h" @@ -96,13 +96,13 @@ public: ResultCode AddUser(const ProfileInfo& user); ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username); ResultCode CreateNewUser(UUID uuid, const std::string& username); - boost::optional<UUID> GetUser(std::size_t index) const; - boost::optional<std::size_t> GetUserIndex(const UUID& uuid) const; - boost::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const; - bool GetProfileBase(boost::optional<std::size_t> index, ProfileBase& profile) const; + std::optional<UUID> GetUser(std::size_t index) const; + std::optional<std::size_t> GetUserIndex(const UUID& uuid) const; + std::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const; + bool GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const; bool GetProfileBase(UUID uuid, ProfileBase& profile) const; bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; - bool GetProfileBaseAndData(boost::optional<std::size_t> index, ProfileBase& profile, + bool GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile, ProfileData& data) const; bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const; bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, @@ -120,16 +120,16 @@ public: bool CanSystemRegisterUser() const; bool RemoveUser(UUID uuid); - bool SetProfileBase(UUID uuid, const ProfileBase& profile); + bool SetProfileBase(UUID uuid, const ProfileBase& profile_new); private: void ParseUserSaveFile(); void WriteUserSaveFile(); + std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); + bool RemoveProfileAtIndex(std::size_t index); std::array<ProfileInfo, MAX_USERS> profiles{}; std::size_t user_count = 0; - boost::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); - bool RemoveProfileAtIndex(std::size_t index); UUID last_opened_user{INVALID_UUID}; }; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 4ed66d817..59aafd616 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -743,7 +743,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { Account::ProfileManager profile_manager{}; const auto uuid = profile_manager.GetUser(Settings::values.current_user); - ASSERT(uuid != boost::none); + ASSERT(uuid != std::nullopt); params.current_user = uuid->uuid; IPC::ResponseBuilder rb{ctx, 2, 0, 1}; diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 428069df2..54305cf05 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -24,8 +24,8 @@ namespace Service::AOC { constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; constexpr u64 DLC_BASE_TO_AOC_ID = 0x1000; -static bool CheckAOCTitleIDMatchesBase(u64 base, u64 aoc) { - return (aoc & DLC_BASE_TITLE_ID_MASK) == base; +static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) { + return (title_id & DLC_BASE_TITLE_ID_MASK) == base; } static std::vector<u64> AccumulateAOCTitleIDs() { @@ -74,7 +74,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); rb.Push<u32>(static_cast<u32>( std::count_if(add_on_content.begin(), add_on_content.end(), - [¤t](u64 tid) { return (tid & DLC_BASE_TITLE_ID_MASK) == current; }))); + [current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); }))); } void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index c87721c39..c1c83a11d 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -273,8 +273,8 @@ public: {0, &IFileSystem::CreateFile, "CreateFile"}, {1, &IFileSystem::DeleteFile, "DeleteFile"}, {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, - {3, nullptr, "DeleteDirectory"}, - {4, nullptr, "DeleteDirectoryRecursively"}, + {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, + {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, {5, &IFileSystem::RenameFile, "RenameFile"}, {6, nullptr, "RenameDirectory"}, {7, &IFileSystem::GetEntryType, "GetEntryType"}, @@ -329,6 +329,30 @@ public: rb.Push(backend.CreateDirectory(name)); } + void DeleteDirectory(Kernel::HLERequestContext& ctx) { + const IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called directory {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectory(name)); + } + + void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { + const IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called directory {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectoryRecursively(name)); + } + void RenameFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index b06e65a77..4b4d1324f 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -108,9 +108,10 @@ void Controller_NPad::OnInit() { styleset_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); - if (!IsControllerActivated()) + if (!IsControllerActivated()) { return; - std::size_t controller{}; + } + if (style.raw == 0) { // We want to support all controllers style.handheld.Assign(1); diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index ec32faf15..d607d985e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -3,9 +3,13 @@ // Refer to the license.txt file included. #include <memory> +#include <fmt/format.h> +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/ldr/ldr.h" #include "core/hle/service/service.h" +#include "core/loader/nro.h" namespace Service::LDR { @@ -59,16 +63,58 @@ public: explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "LoadNro"}, + {0, &RelocatableObject::LoadNro, "LoadNro"}, {1, nullptr, "UnloadNro"}, - {2, nullptr, "LoadNrr"}, + {2, &RelocatableObject::LoadNrr, "LoadNrr"}, {3, nullptr, "UnloadNrr"}, - {4, nullptr, "Initialize"}, + {4, &RelocatableObject::Initialize, "Initialize"}, }; // clang-format on RegisterHandlers(functions); } + + void LoadNrr(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_LDR, "(STUBBED) called"); + } + + void LoadNro(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + rp.Skip(2, false); + const VAddr nro_addr{rp.Pop<VAddr>()}; + const u64 nro_size{rp.Pop<u64>()}; + const VAddr bss_addr{rp.Pop<VAddr>()}; + const u64 bss_size{rp.Pop<u64>()}; + + // Read NRO data from memory + std::vector<u8> nro_data(nro_size); + Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); + + // Load NRO as new executable module + const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)}; + Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr); + + // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party. + // It is currently missing: + // - Signature checks with LoadNRR + // - Checking if a module has already been loaded + // - Using/validating BSS, etc. params (these are used from NRO header instead) + // - Error checking + // - ...Probably other things + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(addr); + LOG_WARNING(Service_LDR, "(STUBBED) called"); + } + + void Initialize(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_LDR, "(STUBBED) called"); + } }; void InstallInterfaces(SM::ServiceManager& sm) { diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 9a4eb9301..c1af878fe 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -328,13 +328,15 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { rb.PushIpcInterface<IUser>(*this); } -void Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { +bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); if (buffer.size() < sizeof(AmiiboFile)) { - return; // Failed to load file + return false; } + std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); nfc_tag_load->Signal(); + return true; } const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { return nfc_tag_load; diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 46370dedd..5c0ae8a54 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -32,7 +32,7 @@ public: static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); void CreateUserInterface(Kernel::HLERequestContext& ctx); - void LoadAmiibo(const std::vector<u8>& buffer); + bool LoadAmiibo(const std::vector<u8>& buffer); const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; const AmiiboFile& GetAmiiboBuffer() const; diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index e7fb5a419..c489da071 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp @@ -67,15 +67,15 @@ public: explicit IClientEpSession() : ServiceFramework{"IClientEpSession"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, + {0, nullptr, "Open"}, + {1, nullptr, "Close"}, + {2, nullptr, "Unknown1"}, + {3, nullptr, "Populate"}, {4, nullptr, "PostBufferAsync"}, - {5, nullptr, "Unknown5"}, - {6, nullptr, "Unknown6"}, - {7, nullptr, "Unknown7"}, - {8, nullptr, "Unknown8"}, + {5, nullptr, "GetXferReport"}, + {6, nullptr, "Unknown2"}, + {7, nullptr, "Unknown3"}, + {8, nullptr, "Unknown4"}, }; // clang-format on @@ -89,15 +89,15 @@ public: // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, - {4, nullptr, "Unknown5"}, + {1, nullptr, "SetInterface"}, + {2, nullptr, "GetInterface"}, + {3, nullptr, "GetAlternateInterface"}, + {4, nullptr, "GetCurrentFrame"}, {5, nullptr, "CtrlXferAsync"}, - {6, nullptr, "Unknown6"}, + {6, nullptr, "Unknown2"}, {7, nullptr, "GetCtrlXferReport"}, - {8, nullptr, "Unknown7"}, - {9, nullptr, "GetClientEpSession"}, + {8, nullptr, "ResetDevice"}, + {9, nullptr, "OpenUsbEp"}, }; // clang-format on @@ -111,13 +111,14 @@ public: // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "BindClientProcess"}, - {1, nullptr, "Unknown1"}, - {2, nullptr, "Unknown2"}, - {3, nullptr, "Unknown3"}, - {4, nullptr, "Unknown4"}, - {5, nullptr, "Unknown5"}, + {1, nullptr, "QueryAllInterfaces"}, + {2, nullptr, "QueryAvailableInterfaces"}, + {3, nullptr, "QueryAcquiredInterfaces"}, + {4, nullptr, "CreateInterfaceAvailableEvent"}, + {5, nullptr, "DestroyInterfaceAvailableEvent"}, {6, nullptr, "GetInterfaceStateChangeEvent"}, - {7, nullptr, "GetClientIfSession"}, + {7, nullptr, "AcquireUsbIf"}, + {8, nullptr, "Unknown1"}, }; // clang-format on diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 243b499f2..bc8e402a8 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -127,18 +127,23 @@ static constexpr u32 PageAlignSize(u32 size) { return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; } -bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { - // Read NSO header - NroHeader nro_header{}; - if (sizeof(NroHeader) != file.ReadObject(&nro_header)) { +/*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, + VAddr load_base) { + + if (data.size() < sizeof(NroHeader)) { return {}; } + + // Read NSO header + NroHeader nro_header{}; + std::memcpy(&nro_header, data.data(), sizeof(NroHeader)); if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { return {}; } // Build program image - std::vector<u8> program_image = file.ReadBytes(PageAlignSize(nro_header.file_size)); + std::vector<u8> program_image(PageAlignSize(nro_header.file_size)); + std::memcpy(program_image.data(), data.data(), program_image.size()); if (program_image.size() != PageAlignSize(nro_header.file_size)) { return {}; } @@ -182,11 +187,15 @@ bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); // Register module with GDBStub - GDBStub::RegisterModule(file.GetName(), load_base, load_base); + GDBStub::RegisterModule(name, load_base, load_base); return true; } +bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { + return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); +} + ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { if (is_loaded) { return ResultStatus::ErrorAlreadyLoaded; diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 50ee5a78a..3e6959302 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -5,6 +5,7 @@ #pragma once #include <string> +#include <vector> #include "common/common_types.h" #include "core/loader/linker.h" #include "core/loader/loader.h" @@ -40,6 +41,8 @@ public: ResultStatus ReadTitle(std::string& title) override; bool IsRomFSUpdatable() const override; + static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base); + private: bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 13e57848d..080d89904 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -36,6 +36,16 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) std::tie(nacp_file, icon_file) = FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca); + + if (nsp->IsExtractedType()) { + secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); + } else { + if (title_id == 0) + return; + + secondary_loader = std::make_unique<AppLoader_NCA>( + nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); + } } AppLoader_NSP::~AppLoader_NSP() = default; @@ -67,26 +77,19 @@ ResultStatus AppLoader_NSP::Load(Kernel::Process& process) { return ResultStatus::ErrorAlreadyLoaded; } - if (nsp->IsExtractedType()) { - secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); - } else { - if (title_id == 0) - return ResultStatus::ErrorNSPMissingProgramNCA; - - secondary_loader = std::make_unique<AppLoader_NCA>( - nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); + if (title_id == 0) + return ResultStatus::ErrorNSPMissingProgramNCA; - if (nsp->GetStatus() != ResultStatus::Success) - return nsp->GetStatus(); + if (nsp->GetStatus() != ResultStatus::Success) + return nsp->GetStatus(); - if (nsp->GetProgramStatus(title_id) != ResultStatus::Success) - return nsp->GetProgramStatus(title_id); + if (nsp->GetProgramStatus(title_id) != ResultStatus::Success) + return nsp->GetProgramStatus(title_id); - if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { - if (!Core::Crypto::KeyManager::KeyFileExists(false)) - return ResultStatus::ErrorMissingProductionKeyFile; - return ResultStatus::ErrorNSPMissingProgramNCA; - } + if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { + if (!Core::Crypto::KeyManager::KeyFileExists(false)) + return ResultStatus::ErrorMissingProductionKeyFile; + return ResultStatus::ErrorNSPMissingProgramNCA; } const auto result = secondary_loader->Load(process); diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index 7d95816fe..c716a462b 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -74,10 +74,6 @@ double PerfStats::GetLastFrameTimeScale() { } void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) { - // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher - // values increase the time needed to recover and limit framerate again after spikes. - constexpr microseconds MAX_LAG_TIME_US = 25000us; - if (!Settings::values.use_frame_limit) { return; } |