diff --git a/common/string_util.h b/common/string_util.h new file mode 100755 index 0000000..4dcaad5 --- /dev/null +++ b/common/string_util.h @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project +// SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include "common_types.h" + +namespace Common { + +/// Make a string lowercase +[[nodiscard]] std::string ToLower(std::string str); + +/// Make a string uppercase +[[nodiscard]] std::string ToUpper(std::string str); + +[[nodiscard]] std::string StringFromBuffer(std::span data); +[[nodiscard]] std::string StringFromBuffer(std::span data); + +[[nodiscard]] std::string StripSpaces(const std::string& s); +[[nodiscard]] std::string StripQuotes(const std::string& s); + +[[nodiscard]] std::string StringFromBool(bool value); + +[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in); + +void SplitString(const std::string& str, char delim, std::vector& output); + +// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" +bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, + std::string* _pExtension); + +[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src, + const std::string& dest); + +[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input); +[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input); +[[nodiscard]] std::u32string UTF8ToUTF32(std::string_view input); + +#ifdef _WIN32 +[[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input); +[[nodiscard]] std::wstring UTF8ToUTF16W(std::string_view str); + +#endif + +[[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length); + +/** + * Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string + * `other` for equality. + */ +template +[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) { + for (; begin != end && *other != '\0'; ++begin, ++other) { + if (*begin != *other) { + return false; + } + } + // Only return true if both strings finished at the same point + return (begin == end) == (*other == '\0'); +} + +/** + * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't + * NUL-terminated then the string ends at max_len characters. + */ +[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, + std::size_t max_len); + +/** + * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't + * null-terminated, then the string ends at the greatest multiple of two less then or equal to + * max_len_bytes. + */ +[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, + std::size_t max_len); + +} // namespace Common diff --git a/common/uuid.h b/common/uuid.h new file mode 100755 index 0000000..420f459 --- /dev/null +++ b/common/uuid.h @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +#include "common_types.h" + +namespace Common { + +struct UUID { + std::array uuid; + + constexpr UUID() = default; + + /// Constructs a UUID from a reference to a 128 bit array. + constexpr explicit UUID(const std::array& uuid_) : uuid{uuid_} {} + + /** + * Constructs a UUID from either: + * 1. A 32 hexadecimal character string representing the bytes of the UUID + * 2. A RFC 4122 formatted UUID string, in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + * + * The input string may contain uppercase or lowercase characters, but they must: + * 1. Contain valid hexadecimal characters (0-9, a-f, A-F) + * 2. Not contain the "0x" hexadecimal prefix + * + * Should the input string not meet the above requirements, + * an assert will be triggered and an invalid UUID is set instead. + */ + explicit UUID(std::string_view uuid_string); + + /** + * Returns whether the stored UUID is valid or not. + * + * @returns True if the stored UUID is valid, false otherwise. + */ + constexpr bool IsValid() const { + return uuid != std::array{}; + } + + /** + * Returns whether the stored UUID is invalid or not. + * + * @returns True if the stored UUID is invalid, false otherwise. + */ + constexpr bool IsInvalid() const { + return !IsValid(); + } + + /** + * Returns a 32 hexadecimal character string representing the bytes of the UUID. + * + * @returns A 32 hexadecimal character string of the UUID. + */ + std::string RawString() const; + + /** + * Returns a RFC 4122 formatted UUID string in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. + * + * @returns A RFC 4122 formatted UUID string. + */ + std::string FormattedString() const; + + /** + * Returns a 64-bit hash of the UUID for use in hash table data structures. + * + * @returns A 64-bit hash of the UUID. + */ + size_t Hash() const noexcept; + + /// DO NOT USE. Copies the contents of the UUID into a u128. + u128 AsU128() const; + + /** + * Creates a default UUID "yuzu Default UID". + * + * @returns A UUID with its bytes set to the ASCII values of "yuzu Default UID". + */ + static constexpr UUID MakeDefault() { + return UUID{ + {'y', 'u', 'z', 'u', ' ', 'D', 'e', 'f', 'a', 'u', 'l', 't', ' ', 'U', 'I', 'D'}, + }; + } + + /** + * Creates a random UUID. + * + * @returns A random UUID. + */ + static UUID MakeRandom(); + + /** + * Creates a random UUID with a seed. + * + * @param seed A seed to initialize the Mersenne-Twister RNG + * + * @returns A random UUID. + */ + static UUID MakeRandomWithSeed(u32 seed); + + /** + * Creates a random UUID. The generated UUID is RFC 4122 Version 4 compliant. + * + * @returns A random UUID that is RFC 4122 Version 4 compliant. + */ + static UUID MakeRandomRFC4122V4(); + + friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default; +}; +static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size."); +static_assert(std::is_trivial_v); + +/// An invalid UUID. This UUID has all its bytes set to 0. +constexpr UUID InvalidUUID = {}; + +} // namespace Common + +namespace std { + +template <> +struct hash { + size_t operator()(const Common::UUID& uuid) const noexcept { + return uuid.Hash(); + } +}; + +} // namespace std diff --git a/core/core.h b/core/core.h new file mode 100755 index 0000000..b280a1f --- /dev/null +++ b/core/core.h @@ -0,0 +1,471 @@ +// SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/common_types.h" +#include "../core/fs/vfs/vfs_types.h" + +namespace Core::Frontend { +class EmuWindow; +} // namespace Core::Frontend + +namespace FileSys { +class ContentProvider; +class ContentProviderUnion; +enum class ContentProviderUnionSlot; +class VfsFilesystem; +} // namespace FileSys + +namespace Kernel { +class GlobalSchedulerContext; +class KernelCore; +class PhysicalCore; +class KProcess; +class KScheduler; +} // namespace Kernel + +namespace Loader { +class AppLoader; +enum class ResultStatus : u16; +} // namespace Loader + +namespace Core::Memory { +struct CheatEntry; +class Memory; +} // namespace Core::Memory + +namespace Service { + +namespace Account { +class ProfileManager; +} // namespace Account + +namespace AM { +struct FrontendAppletParameters; +class AppletManager; +} // namespace AM + +namespace AM::Frontend { +struct FrontendAppletSet; +class FrontendAppletHolder; +} // namespace AM::Frontend + +namespace APM { +class Controller; +} + +namespace FileSystem { +class FileSystemController; +} // namespace FileSystem + +namespace Glue { +class ARPManager; +} + +class ServerManager; + +namespace SM { +class ServiceManager; +} // namespace SM + +} // namespace Service + +namespace Tegra { +class DebugContext; +class GPU; +namespace Host1x { +class Host1x; +} // namespace Host1x +} // namespace Tegra + +namespace VideoCore { +class RendererBase; +} // namespace VideoCore + +namespace AudioCore { +class AudioCore; +} // namespace AudioCore + +namespace Core::Timing { +class CoreTiming; +} + +namespace Core::HID { +class HIDCore; +} + +namespace Network { +class RoomNetwork; +} + +namespace Tools { +class RenderdocAPI; +} + +namespace Core { + +class CpuManager; +class Debugger; +class DeviceMemory; +class ExclusiveMonitor; +class GPUDirtyMemoryManager; +class PerfStats; +class Reporter; +class SpeedLimiter; +class TelemetrySession; + +struct PerfStatsResults; + +FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, + const std::string& path); + +/// Enumeration representing the return values of the System Initialize and Load process. +enum class SystemResultStatus : u32 { + Success, ///< Succeeded + ErrorNotInitialized, ///< Error trying to use core prior to initialization + ErrorGetLoader, ///< Error finding the correct application loader + ErrorSystemFiles, ///< Error in finding system files + ErrorSharedFont, ///< Error in finding shared font + ErrorVideoCore, ///< Error in the video core + ErrorUnknown, ///< Any other error + ErrorLoader, ///< The base for loader errors (too many to repeat) +}; + +class System { +public: + using CurrentBuildProcessID = std::array; + + explicit System(); + + ~System(); + + System(const System&) = delete; + System& operator=(const System&) = delete; + + System(System&&) = delete; + System& operator=(System&&) = delete; + + /** + * Initializes the system + * This function will initialize core functionality used for system emulation + */ + void Initialize(); + + /** + * Run the OS and Application + * This function will start emulation and run the relevant devices + */ + void Run(); + + /** + * Pause the OS and Application + * This function will pause emulation and stop the relevant devices + */ + void Pause(); + + /// Check if the core is currently paused. + [[nodiscard]] bool IsPaused() const; + + /// Shutdown the main emulated process. + void ShutdownMainProcess(); + + /// Check if the core is shutting down. + [[nodiscard]] bool IsShuttingDown() const; + + /// Set the shutting down state. + void SetShuttingDown(bool shutting_down); + + /// Forcibly detach the debugger if it is running. + void DetachDebugger(); + + std::unique_lock StallApplication(); + void UnstallApplication(); + + void SetNVDECActive(bool is_nvdec_active); + [[nodiscard]] bool GetNVDECActive(); + + /** + * Initialize the debugger. + */ + void InitializeDebugger(); + + /** + * Load an executable application. + * @param emu_window Reference to the host-system window used for video output and keyboard + * input. + * @param filepath String path to the executable application to load on the host file system. + * @param program_index Specifies the index within the container of the program to launch. + * @returns SystemResultStatus code, indicating if the operation succeeded. + */ + [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window, + const std::string& filepath, + Service::AM::FrontendAppletParameters& params); + + /** + * Indicates if the emulated system is powered on (all subsystems initialized and able to run an + * application). + * @returns True if the emulated system is powered on, otherwise false. + */ + [[nodiscard]] bool IsPoweredOn() const; + + /// Gets a reference to the telemetry session for this emulation session. + [[nodiscard]] Core::TelemetrySession& TelemetrySession(); + + /// Gets a reference to the telemetry session for this emulation session. + [[nodiscard]] const Core::TelemetrySession& TelemetrySession() const; + + /// Prepare the core emulation for a reschedule + void PrepareReschedule(u32 core_index); + + std::span GetGPUDirtyMemoryManager(); + + void GatherGPUDirtyMemory(std::function& callback); + + [[nodiscard]] size_t GetCurrentHostThreadID() const; + + /// Gets and resets core performance statistics + [[nodiscard]] PerfStatsResults GetAndResetPerfStats(); + + /// Gets the physical core for the CPU core that is currently running + [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); + + /// Gets the physical core for the CPU core that is currently running + [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const; + + /// Gets a reference to the underlying CPU manager. + [[nodiscard]] CpuManager& GetCpuManager(); + + /// Gets a const reference to the underlying CPU manager + [[nodiscard]] const CpuManager& GetCpuManager() const; + + /// Gets a mutable reference to the system memory instance. + [[nodiscard]] Core::Memory::Memory& ApplicationMemory(); + + /// Gets a constant reference to the system memory instance. + [[nodiscard]] const Core::Memory::Memory& ApplicationMemory() const; + + /// Gets a mutable reference to the GPU interface + [[nodiscard]] Tegra::GPU& GPU(); + + /// Gets an immutable reference to the GPU interface. + [[nodiscard]] const Tegra::GPU& GPU() const; + + /// Gets a mutable reference to the Host1x interface + [[nodiscard]] Tegra::Host1x::Host1x& Host1x(); + + /// Gets an immutable reference to the Host1x interface. + [[nodiscard]] const Tegra::Host1x::Host1x& Host1x() const; + + /// Gets a mutable reference to the renderer. + [[nodiscard]] VideoCore::RendererBase& Renderer(); + + /// Gets an immutable reference to the renderer. + [[nodiscard]] const VideoCore::RendererBase& Renderer() const; + + /// Gets a mutable reference to the audio interface + [[nodiscard]] AudioCore::AudioCore& AudioCore(); + + /// Gets an immutable reference to the audio interface. + [[nodiscard]] const AudioCore::AudioCore& AudioCore() const; + + /// Gets the global scheduler + [[nodiscard]] Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); + + /// Gets the global scheduler + [[nodiscard]] const Kernel::GlobalSchedulerContext& GlobalSchedulerContext() const; + + /// Gets the manager for the guest device memory + [[nodiscard]] Core::DeviceMemory& DeviceMemory(); + + /// Gets the manager for the guest device memory + [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const; + + /// Provides a pointer to the application process + [[nodiscard]] Kernel::KProcess* ApplicationProcess(); + + /// Provides a constant pointer to the application process. + [[nodiscard]] const Kernel::KProcess* ApplicationProcess() const; + + /// Provides a reference to the core timing instance. + [[nodiscard]] Timing::CoreTiming& CoreTiming(); + + /// Provides a constant reference to the core timing instance. + [[nodiscard]] const Timing::CoreTiming& CoreTiming() const; + + /// Provides a reference to the kernel instance. + [[nodiscard]] Kernel::KernelCore& Kernel(); + + /// Provides a constant reference to the kernel instance. + [[nodiscard]] const Kernel::KernelCore& Kernel() const; + + /// Gets a mutable reference to the HID interface. + [[nodiscard]] HID::HIDCore& HIDCore(); + + /// Gets an immutable reference to the HID interface. + [[nodiscard]] const HID::HIDCore& HIDCore() const; + + /// Provides a reference to the internal PerfStats instance. + [[nodiscard]] Core::PerfStats& GetPerfStats(); + + /// Provides a constant reference to the internal PerfStats instance. + [[nodiscard]] const Core::PerfStats& GetPerfStats() const; + + /// Provides a reference to the speed limiter; + [[nodiscard]] Core::SpeedLimiter& SpeedLimiter(); + + /// Provides a constant reference to the speed limiter + [[nodiscard]] const Core::SpeedLimiter& SpeedLimiter() const; + + [[nodiscard]] u64 GetApplicationProcessProgramID() const; + + /// Gets the name of the current game + [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const; + + void SetStatus(SystemResultStatus new_status, const char* details); + + [[nodiscard]] const std::string& GetStatusDetails() const; + + [[nodiscard]] Loader::AppLoader& GetAppLoader(); + [[nodiscard]] const Loader::AppLoader& GetAppLoader() const; + + [[nodiscard]] Service::SM::ServiceManager& ServiceManager(); + [[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const; + + void SetFilesystem(FileSys::VirtualFilesystem vfs); + + [[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const; + + void RegisterCheatList(const std::vector& list, + const std::array& build_id, u64 main_region_begin, + u64 main_region_size); + + void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); + + [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder(); + [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder() + const; + + [[nodiscard]] Service::AM::AppletManager& GetAppletManager(); + + void SetContentProvider(std::unique_ptr provider); + + [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); + [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const; + + [[nodiscard]] FileSys::ContentProviderUnion& GetContentProviderUnion(); + [[nodiscard]] const FileSys::ContentProviderUnion& GetContentProviderUnion() const; + + [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController(); + [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const; + + void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, + FileSys::ContentProvider* provider); + + void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); + + [[nodiscard]] const Reporter& GetReporter() const; + + [[nodiscard]] Service::Glue::ARPManager& GetARPManager(); + [[nodiscard]] const Service::Glue::ARPManager& GetARPManager() const; + + [[nodiscard]] Service::APM::Controller& GetAPMController(); + [[nodiscard]] const Service::APM::Controller& GetAPMController() const; + + [[nodiscard]] Service::Account::ProfileManager& GetProfileManager(); + [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const; + + [[nodiscard]] Core::Debugger& GetDebugger(); + [[nodiscard]] const Core::Debugger& GetDebugger() const; + + /// Gets a mutable reference to the Room Network. + [[nodiscard]] Network::RoomNetwork& GetRoomNetwork(); + + /// Gets an immutable reference to the Room Network. + [[nodiscard]] const Network::RoomNetwork& GetRoomNetwork() const; + + [[nodiscard]] Tools::RenderdocAPI& GetRenderdocAPI(); + + void SetExitLocked(bool locked); + bool GetExitLocked() const; + + void SetExitRequested(bool requested); + bool GetExitRequested() const; + + void SetApplicationProcessBuildID(const CurrentBuildProcessID& id); + [[nodiscard]] const CurrentBuildProcessID& GetApplicationProcessBuildID() const; + + /// Register a host thread as an emulated CPU Core. + void RegisterCoreThread(std::size_t id); + + /// Register a host thread as an auxiliary thread. + void RegisterHostThread(); + + /// Enter CPU Microprofile + void EnterCPUProfile(); + + /// Exit CPU Microprofile + void ExitCPUProfile(); + + /// Tells if system is running on multicore. + [[nodiscard]] bool IsMulticore() const; + + /// Tells if the system debugger is enabled. + [[nodiscard]] bool DebuggerEnabled() const; + + /// Runs a server instance until shutdown. + void RunServer(std::unique_ptr&& server_manager); + + /// Type used for the frontend to designate a callback for System to re-launch the application + /// using a specified program index. + using ExecuteProgramCallback = std::function; + + /** + * Registers a callback from the frontend for System to re-launch the application using a + * specified program index. + * @param callback Callback from the frontend to relaunch the application. + */ + void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback); + + /** + * Instructs the frontend to re-launch the application using the specified program_index. + * @param program_index Specifies the index within the application of the program to launch. + */ + void ExecuteProgram(std::size_t program_index); + + /** + * Gets a reference to the user channel stack. + * It is used to transfer data between programs. + */ + [[nodiscard]] std::deque>& GetUserChannel(); + + /// Type used for the frontend to designate a callback for System to exit the application. + using ExitCallback = std::function; + + /** + * Registers a callback from the frontend for System to exit the application. + * @param callback Callback from the frontend to exit the application. + */ + void RegisterExitCallback(ExitCallback&& callback); + + /// Instructs the frontend to exit the application. + void Exit(); + + /// Applies any changes to settings to this core instance. + void ApplySettings(); + +private: + struct Impl; + std::unique_ptr impl; +}; + +} // namespace Core diff --git a/core/crypto/xts_encryption_layer.h b/core/crypto/xts_encryption_layer.h new file mode 100755 index 0000000..d56b6b1 --- /dev/null +++ b/core/crypto/xts_encryption_layer.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "aes_util.h" +#include "encryption_layer.h" +#include "key_manager.h" + +namespace Core::Crypto { + +// Sits on top of a VirtualFile and provides XTS-mode AES description. +class XTSEncryptionLayer : public EncryptionLayer { +public: + XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key); + + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; + +private: + // Must be mutable as operations modify cipher contexts. + mutable AESCipher cipher; +}; + +} // namespace Core::Crypto diff --git a/core/fs/romfs.cpp b/core/fs/romfs.cpp index 39bcbf4..0bb7c8f 100644 --- a/core/fs/romfs.cpp +++ b/core/fs/romfs.cpp @@ -3,17 +3,17 @@ #include -#include "common/assert.h" -#include "common/common_types.h" -#include "core/fs/fs_string_util.h" -#include "common/swap.h" -#include "core/fs/fsmitm_romfsbuild.h" -#include "core/fs/romfs.h" -#include "core/fs/vfs/vfs.h" -#include "core/fs/vfs/vfs_cached.h" -#include "core/fs/vfs/vfs_concat.h" -#include "core/fs/vfs/vfs_offset.h" -#include "core/fs/vfs/vfs_vector.h" +#include "../common/assert.h" +#include "../common/common_types.h" +#include "fs_string_util.h" +#include "../common/swap.h" +#include "fsmitm_romfsbuild.h" +#include "romfs.h" +#include "../core/fs/vfs/vfs.h" +#include "../core/fs/vfs/vfs_cached.h" +#include "../core/fs/vfs/vfs_concat.h" +#include "../core/fs/vfs/vfs_offset.h" +#include "../core/fs/vfs/vfs_vector.h" namespace FileSys { namespace { diff --git a/core/fs/romfs.h b/core/fs/romfs.h index 81a82ad..590f748 100644 --- a/core/fs/romfs.h +++ b/core/fs/romfs.h @@ -3,7 +3,7 @@ #pragma once -#include "core/fs/vfs/vfs.h" +#include "../core/fs/vfs/vfs.h" namespace FileSys { diff --git a/core/fs/romfs_factory.cpp b/core/fs/romfs_factory.cpp index 35e1499..463db7a 100644 --- a/core/fs/romfs_factory.cpp +++ b/core/fs/romfs_factory.cpp @@ -2,18 +2,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include "common/assert.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/file_sys/common_funcs.h" -#include "core/file_sys/content_archive.h" -#include "core/file_sys/nca_metadata.h" -#include "core/file_sys/patch_manager.h" -#include "core/file_sys/registered_cache.h" -#include "core/file_sys/romfs_factory.h" -#include "core/hle/kernel/k_process.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/loader/loader.h" +#include "../common/assert.h" +#include "../common/common_types.h" +#include "../common/logging/log.h" +#include "../common_funcs.h" +#include "../content_archive.h" +#include "nca_metadata.h" +#include "patch_manager.h" +#include "registered_cache.h" +#include "romfs_factory.h" +#include "../core/hle/kernel/k_process.h" +#include "../core/hle/service/filesystem/filesystem.h" +#include "../core/loader/loader.h" namespace FileSys { diff --git a/core/fs/romfs_factory.h b/core/fs/romfs_factory.h index 11ecfab..a960e97 100644 --- a/core/fs/romfs_factory.h +++ b/core/fs/romfs_factory.h @@ -5,9 +5,9 @@ #include -#include "common/common_types.h" -#include "core/file_sys/vfs/vfs_types.h" -#include "core/hle/result.h" +#include "../common/common_types.h" +#include "../core/fs/vfs/vfs_types.h" +#include "../core/hle/result.h" namespace Loader { class AppLoader; diff --git a/core/fs/savedata_factory.cpp b/core/fs/savedata_factory.cpp index 106922e..2f9060a 100644 --- a/core/fs/savedata_factory.cpp +++ b/core/fs/savedata_factory.cpp @@ -2,13 +2,13 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include "common/assert.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "common/uuid.h" -#include "core/core.h" -#include "core/file_sys/savedata_factory.h" -#include "core/file_sys/vfs/vfs.h" +#include "../common/assert.h" +#include "../common/common_types.h" +#include "../common/logging/log.h" +#include "../common/uuid.h" +#include "../core/core.h" +#include "savedata_factory.h" +#include "../core/fs/vfs/vfs.h" namespace FileSys { diff --git a/core/fs/savedata_factory.h b/core/fs/savedata_factory.h index 15dd4ec..7f92b3d 100644 --- a/core/fs/savedata_factory.h +++ b/core/fs/savedata_factory.h @@ -7,9 +7,9 @@ #include #include "common/common_funcs.h" #include "common/common_types.h" -#include "core/file_sys/fs_save_data_types.h" -#include "core/file_sys/vfs/vfs.h" -#include "core/hle/result.h" +#include "fs_save_data_types.h" +#include "../core/fs/vfs/vfs.h" +#include "../core/hle/result.h" namespace Core { class System; diff --git a/core/fs/submission_package.cpp b/core/fs/submission_package.cpp index 68e8ec2..63de2d5 100644 --- a/core/fs/submission_package.cpp +++ b/core/fs/submission_package.cpp @@ -6,15 +6,15 @@ #include -#include "common/hex_util.h" -#include "common/logging/log.h" -#include "core/crypto/key_manager.h" -#include "core/file_sys/content_archive.h" -#include "core/file_sys/nca_metadata.h" -#include "core/file_sys/partition_filesystem.h" -#include "core/file_sys/program_metadata.h" -#include "core/file_sys/submission_package.h" -#include "core/loader/loader.h" +#include "../common/hex_util.h" +#include "../common/logging/log.h" +#include "../core/crypto/key_manager.h" +#include "content_archive.h" +#include "nca_metadata.h" +#include "partition_filesystem.h" +#include "program_metadata.h" +#include "submission_package.h" +#include "../core/loader/loader.h" namespace FileSys { diff --git a/core/fs/xts_archive.cpp b/core/fs/xts_archive.cpp index 6692211..b7da79f 100644 --- a/core/fs/xts_archive.cpp +++ b/core/fs/xts_archive.cpp @@ -10,16 +10,16 @@ #include #include -#include "common/fs/path_util.h" -#include "common/hex_util.h" -#include "common/string_util.h" -#include "core/crypto/aes_util.h" -#include "core/crypto/key_manager.h" -#include "core/crypto/xts_encryption_layer.h" -#include "core/file_sys/content_archive.h" -#include "core/file_sys/vfs/vfs_offset.h" -#include "core/file_sys/xts_archive.h" -#include "core/loader/loader.h" +#include "../common/fs/path_util.h" +#include "../common/hex_util.h" +#include "../common/string_util.h" +#include "../core/crypto/aes_util.h" +#include "../core/crypto/key_manager.h" +#include "../core/crypto/xts_encryption_layer.h" +#include "content_archive.h" +#include "../core/fs/vfs/vfs_offset.h" +#include "xts_archive.h" +#include "../core/loader/loader.h" namespace FileSys { diff --git a/core/fs/xts_archive.h b/core/fs/xts_archive.h index 7589b7c..4f7fba2 100644 --- a/core/fs/xts_archive.h +++ b/core/fs/xts_archive.h @@ -5,10 +5,10 @@ #include #include -#include "common/common_types.h" -#include "common/swap.h" -#include "core/crypto/key_manager.h" -#include "core/file_sys/vfs/vfs.h" +#include "../common/common_types.h" +#include "../common/swap.h" +#include "../core/crypto/key_manager.h" +#include "../core/fs/vfs/vfs.h" namespace Loader { enum class ResultStatus : u16; diff --git a/core/hle/kernel/k_process.h b/core/hle/kernel/k_process.h new file mode 100755 index 0000000..337f838 --- /dev/null +++ b/core/hle/kernel/k_process.h @@ -0,0 +1,568 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +// #include "core/arm/arm_interface.h" (will make REM do this soon) +// #include (wip) +#include "../core/fs/program_metadata.h" +#include "../core/hle/kernel/code_set.h" +#include "../core/hle/kernel/k_address_arbiter.h" +#include "../core/hle/kernel/k_capabilities.h" +#include "../core/hle/kernel/k_condition_variable.h" +#include "../core/hle/kernel/k_handle_table.h" +#include "../core/hle/kernel/k_page_table_manager.h" +#include "../core/hle/kernel/k_process_page_table.h" +#include "../core/hle/kernel/k_system_resource.h" +#include "../core/hle/kernel/k_thread.h" +#include "../core/hle/kernel/k_thread_local_page.h" +#include "../core/memory.h" + +namespace Kernel { + +enum class DebugWatchpointType : u8 { + None = 0, + Read = 1 << 0, + Write = 1 << 1, + ReadOrWrite = Read | Write, +}; +DECLARE_ENUM_FLAG_OPERATORS(DebugWatchpointType); + +struct DebugWatchpoint { + KProcessAddress start_address; + KProcessAddress end_address; + DebugWatchpointType type; +}; + +class KProcess final : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); + +public: + enum class State { + Created = static_cast(Svc::ProcessState::Created), + CreatedAttached = static_cast(Svc::ProcessState::CreatedAttached), + Running = static_cast(Svc::ProcessState::Running), + Crashed = static_cast(Svc::ProcessState::Crashed), + RunningAttached = static_cast(Svc::ProcessState::RunningAttached), + Terminating = static_cast(Svc::ProcessState::Terminating), + Terminated = static_cast(Svc::ProcessState::Terminated), + DebugBreak = static_cast(Svc::ProcessState::DebugBreak), + }; + + using ThreadList = Common::IntrusiveListMemberTraits<&KThread::m_process_list_node>::ListType; + + static constexpr size_t AslrAlignment = 2_MiB; + +public: + static constexpr u64 InitialProcessIdMin = 1; + static constexpr u64 InitialProcessIdMax = 0x50; + + static constexpr u64 ProcessIdMin = InitialProcessIdMax + 1; + static constexpr u64 ProcessIdMax = std::numeric_limits::max(); + +private: + using SharedMemoryInfoList = Common::IntrusiveListBaseTraits::ListType; + using TLPTree = + Common::IntrusiveRedBlackTreeBaseTraits::TreeType; + using TLPIterator = TLPTree::iterator; + +private: + KProcessPageTable m_page_table; + std::atomic m_used_kernel_memory_size{}; + TLPTree m_fully_used_tlp_tree{}; + TLPTree m_partially_used_tlp_tree{}; + s32 m_ideal_core_id{}; + KResourceLimit* m_resource_limit{}; + KSystemResource* m_system_resource{}; + size_t m_memory_release_hint{}; + State m_state{}; + KLightLock m_state_lock; + KLightLock m_list_lock; + KConditionVariable m_cond_var; + KAddressArbiter m_address_arbiter; + std::array m_entropy{}; + bool m_is_signaled{}; + bool m_is_initialized{}; + bool m_is_application{}; + bool m_is_default_application_system_resource{}; + bool m_is_hbl{}; + std::array m_name{}; + std::atomic m_num_running_threads{}; + Svc::CreateProcessFlag m_flags{}; + KMemoryManager::Pool m_memory_pool{}; + s64 m_schedule_count{}; + KCapabilities m_capabilities{}; + u64 m_program_id{}; + u64 m_process_id{}; + KProcessAddress m_code_address{}; + size_t m_code_size{}; + size_t m_main_thread_stack_size{}; + size_t m_max_process_memory{}; + u32 m_version{}; + KHandleTable m_handle_table; + KProcessAddress m_plr_address{}; + KThread* m_exception_thread{}; + ThreadList m_thread_list{}; + SharedMemoryInfoList m_shared_memory_list{}; + bool m_is_suspended{}; + bool m_is_immortal{}; + bool m_is_handle_table_initialized{}; + std::array, Core::Hardware::NUM_CPU_CORES> + m_arm_interfaces{}; + std::array m_running_threads{}; + std::array m_running_thread_idle_counts{}; + std::array m_running_thread_switch_counts{}; + std::array m_pinned_threads{}; + std::array m_watchpoints{}; + std::map m_debug_page_refcounts{}; + std::atomic m_cpu_time{}; + std::atomic m_num_process_switches{}; + std::atomic m_num_thread_switches{}; + std::atomic m_num_fpu_switches{}; + std::atomic m_num_supervisor_calls{}; + std::atomic m_num_ipc_messages{}; + std::atomic m_num_ipc_replies{}; + std::atomic m_num_ipc_receives{}; +#ifdef HAS_NCE + std::unordered_map m_post_handlers{}; +#endif + std::unique_ptr m_exclusive_monitor; + Core::Memory::Memory m_memory; + +private: + Result StartTermination(); + void FinishTermination(); + + void PinThread(s32 core_id, KThread* thread) { + ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); + ASSERT(thread != nullptr); + ASSERT(m_pinned_threads[core_id] == nullptr); + m_pinned_threads[core_id] = thread; + } + + void UnpinThread(s32 core_id, KThread* thread) { + ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); + ASSERT(thread != nullptr); + ASSERT(m_pinned_threads[core_id] == thread); + m_pinned_threads[core_id] = nullptr; + } + +public: + explicit KProcess(KernelCore& kernel); + ~KProcess() override; + + Result Initialize(const Svc::CreateProcessParameter& params, KResourceLimit* res_limit, + bool is_real); + + Result Initialize(const Svc::CreateProcessParameter& params, const KPageGroup& pg, + std::span caps, KResourceLimit* res_limit, + KMemoryManager::Pool pool, bool immortal); + Result Initialize(const Svc::CreateProcessParameter& params, std::span user_caps, + KResourceLimit* res_limit, KMemoryManager::Pool pool, + KProcessAddress aslr_space_start); + void Exit(); + + const char* GetName() const { + return m_name.data(); + } + + u64 GetProgramId() const { + return m_program_id; + } + + u64 GetProcessId() const { + return m_process_id; + } + + State GetState() const { + return m_state; + } + + u64 GetCoreMask() const { + return m_capabilities.GetCoreMask(); + } + u64 GetPhysicalCoreMask() const { + return m_capabilities.GetPhysicalCoreMask(); + } + u64 GetPriorityMask() const { + return m_capabilities.GetPriorityMask(); + } + + s32 GetIdealCoreId() const { + return m_ideal_core_id; + } + void SetIdealCoreId(s32 core_id) { + m_ideal_core_id = core_id; + } + + bool CheckThreadPriority(s32 prio) const { + return ((1ULL << prio) & this->GetPriorityMask()) != 0; + } + + u32 GetCreateProcessFlags() const { + return static_cast(m_flags); + } + + bool Is64Bit() const { + return True(m_flags & Svc::CreateProcessFlag::Is64Bit); + } + + KProcessAddress GetEntryPoint() const { + return m_code_address; + } + + size_t GetMainStackSize() const { + return m_main_thread_stack_size; + } + + KMemoryManager::Pool GetMemoryPool() const { + return m_memory_pool; + } + + u64 GetRandomEntropy(size_t i) const { + return m_entropy[i]; + } + + bool IsApplication() const { + return m_is_application; + } + + bool IsDefaultApplicationSystemResource() const { + return m_is_default_application_system_resource; + } + + bool IsSuspended() const { + return m_is_suspended; + } + void SetSuspended(bool suspended) { + m_is_suspended = suspended; + } + + Result Terminate(); + + bool IsTerminated() const { + return m_state == State::Terminated; + } + + bool IsPermittedSvc(u32 svc_id) const { + return m_capabilities.IsPermittedSvc(svc_id); + } + + bool IsPermittedInterrupt(s32 interrupt_id) const { + return m_capabilities.IsPermittedInterrupt(interrupt_id); + } + + bool IsPermittedDebug() const { + return m_capabilities.IsPermittedDebug(); + } + + bool CanForceDebug() const { + return m_capabilities.CanForceDebug(); + } + + bool IsHbl() const { + return m_is_hbl; + } + + u32 GetAllocateOption() const { + return m_page_table.GetAllocateOption(); + } + + ThreadList& GetThreadList() { + return m_thread_list; + } + const ThreadList& GetThreadList() const { + return m_thread_list; + } + + bool EnterUserException(); + bool LeaveUserException(); + bool ReleaseUserException(KThread* thread); + + KThread* GetPinnedThread(s32 core_id) const { + ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); + return m_pinned_threads[core_id]; + } + + const Svc::SvcAccessFlagSet& GetSvcPermissions() const { + return m_capabilities.GetSvcPermissions(); + } + + KResourceLimit* GetResourceLimit() const { + return m_resource_limit; + } + + bool ReserveResource(Svc::LimitableResource which, s64 value); + bool ReserveResource(Svc::LimitableResource which, s64 value, s64 timeout); + void ReleaseResource(Svc::LimitableResource which, s64 value); + void ReleaseResource(Svc::LimitableResource which, s64 value, s64 hint); + + KLightLock& GetStateLock() { + return m_state_lock; + } + KLightLock& GetListLock() { + return m_list_lock; + } + + KProcessPageTable& GetPageTable() { + return m_page_table; + } + const KProcessPageTable& GetPageTable() const { + return m_page_table; + } + + KHandleTable& GetHandleTable() { + return m_handle_table; + } + const KHandleTable& GetHandleTable() const { + return m_handle_table; + } + + size_t GetUsedUserPhysicalMemorySize() const; + size_t GetTotalUserPhysicalMemorySize() const; + size_t GetUsedNonSystemUserPhysicalMemorySize() const; + size_t GetTotalNonSystemUserPhysicalMemorySize() const; + + Result AddSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size); + void RemoveSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size); + + Result CreateThreadLocalRegion(KProcessAddress* out); + Result DeleteThreadLocalRegion(KProcessAddress addr); + + KProcessAddress GetProcessLocalRegionAddress() const { + return m_plr_address; + } + + KThread* GetExceptionThread() const { + return m_exception_thread; + } + + void AddCpuTime(s64 diff) { + m_cpu_time += diff; + } + s64 GetCpuTime() { + return m_cpu_time.load(); + } + + s64 GetScheduledCount() const { + return m_schedule_count; + } + void IncrementScheduledCount() { + ++m_schedule_count; + } + + void IncrementRunningThreadCount(); + void DecrementRunningThreadCount(); + + size_t GetRequiredSecureMemorySizeNonDefault() const { + if (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) { + auto* secure_system_resource = static_cast(m_system_resource); + return secure_system_resource->CalculateRequiredSecureMemorySize(); + } + + return 0; + } + + size_t GetRequiredSecureMemorySize() const { + if (m_system_resource->IsSecureResource()) { + auto* secure_system_resource = static_cast(m_system_resource); + return secure_system_resource->CalculateRequiredSecureMemorySize(); + } + + return 0; + } + + size_t GetTotalSystemResourceSize() const { + if (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) { + auto* secure_system_resource = static_cast(m_system_resource); + return secure_system_resource->GetSize(); + } + + return 0; + } + + size_t GetUsedSystemResourceSize() const { + if (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) { + auto* secure_system_resource = static_cast(m_system_resource); + return secure_system_resource->GetUsedSize(); + } + + return 0; + } + + void SetRunningThread(s32 core, KThread* thread, u64 idle_count, u64 switch_count) { + m_running_threads[core] = thread; + m_running_thread_idle_counts[core] = idle_count; + m_running_thread_switch_counts[core] = switch_count; + } + + void ClearRunningThread(KThread* thread) { + for (size_t i = 0; i < m_running_threads.size(); ++i) { + if (m_running_threads[i] == thread) { + m_running_threads[i] = nullptr; + } + } + } + + const KSystemResource& GetSystemResource() const { + return *m_system_resource; + } + + const KMemoryBlockSlabManager& GetMemoryBlockSlabManager() const { + return m_system_resource->GetMemoryBlockSlabManager(); + } + const KBlockInfoManager& GetBlockInfoManager() const { + return m_system_resource->GetBlockInfoManager(); + } + const KPageTableManager& GetPageTableManager() const { + return m_system_resource->GetPageTableManager(); + } + + KThread* GetRunningThread(s32 core) const { + return m_running_threads[core]; + } + u64 GetRunningThreadIdleCount(s32 core) const { + return m_running_thread_idle_counts[core]; + } + u64 GetRunningThreadSwitchCount(s32 core) const { + return m_running_thread_switch_counts[core]; + } + + void RegisterThread(KThread* thread); + void UnregisterThread(KThread* thread); + + Result Run(s32 priority, size_t stack_size); + + Result Reset(); + + void SetDebugBreak() { + if (m_state == State::RunningAttached) { + this->ChangeState(State::DebugBreak); + } + } + + void SetAttached() { + if (m_state == State::DebugBreak) { + this->ChangeState(State::RunningAttached); + } + } + + Result SetActivity(Svc::ProcessActivity activity); + + void PinCurrentThread(); + void UnpinCurrentThread(); + void UnpinThread(KThread* thread); + + void SignalConditionVariable(uintptr_t cv_key, int32_t count) { + return m_cond_var.Signal(cv_key, count); + } + + Result WaitConditionVariable(KProcessAddress address, uintptr_t cv_key, u32 tag, s64 ns) { + R_RETURN(m_cond_var.Wait(address, cv_key, tag, ns)); + } + + Result SignalAddressArbiter(uintptr_t address, Svc::SignalType signal_type, s32 value, + s32 count) { + R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count)); + } + + Result WaitAddressArbiter(uintptr_t address, Svc::ArbitrationType arb_type, s32 value, + s64 timeout) { + R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout)); + } + + Result GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, s32 max_out_count); + + static void Switch(KProcess* cur_process, KProcess* next_process); + +#ifdef HAS_NCE + std::unordered_map& GetPostHandlers() noexcept { + return m_post_handlers; + } +#endif + + Core::ArmInterface* GetArmInterface(size_t core_index) const { + return m_arm_interfaces[core_index].get(); + } + +public: + // Attempts to insert a watchpoint into a free slot. Returns false if none are available. + bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); + + // Attempts to remove the watchpoint specified by the given parameters. + bool RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); + + const std::array& GetWatchpoints() const { + return m_watchpoints; + } + +public: + Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, + KProcessAddress aslr_space_start, bool is_hbl); + + void LoadModule(CodeSet code_set, KProcessAddress base_addr); + + void InitializeInterfaces(); + + Core::Memory::Memory& GetMemory() { + return m_memory; + } + + Core::ExclusiveMonitor& GetExclusiveMonitor() const { + return *m_exclusive_monitor; + } + +public: + // Overridden parent functions. + bool IsInitialized() const override { + return m_is_initialized; + } + + static void PostDestroy(uintptr_t arg) {} + + void Finalize() override; + + u64 GetIdImpl() const { + return this->GetProcessId(); + } + u64 GetId() const override { + return this->GetIdImpl(); + } + + virtual bool IsSignaled() const override { + ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel)); + return m_is_signaled; + } + + void DoWorkerTaskImpl(); + +private: + void ChangeState(State new_state) { + if (m_state != new_state) { + m_state = new_state; + m_is_signaled = true; + this->NotifyAvailable(); + } + } + + Result InitializeHandleTable(s32 size) { + // Try to initialize the handle table. + R_TRY(m_handle_table.Initialize(size)); + + // We succeeded, so note that we did. + m_is_handle_table_initialized = true; + R_SUCCEED(); + } + + void FinalizeHandleTable() { + // Finalize the table. + m_handle_table.Finalize(); + + // Note that the table is finalized. + m_is_handle_table_initialized = false; + } +}; + +} // namespace Kernel