diff options
Diffstat (limited to '')
199 files changed, 5444 insertions, 3148 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 73274c2e0..c8e9ebf8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,7 +274,7 @@ if (ENABLE_SDL2) if (YUZU_USE_BUNDLED_SDL2) # Detect toolchain and platform if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64) - set(SDL2_VER "SDL2-2.0.14") + set(SDL2_VER "SDL2-2.0.15-prerelease") else() message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") endif() @@ -292,7 +292,7 @@ if (ENABLE_SDL2) target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}") target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}") else() - find_package(SDL2 2.0.14 QUIET) + find_package(SDL2 2.0.15 QUIET) if (SDL2_FOUND) # Some installations don't set SDL2_LIBRARIES @@ -305,7 +305,7 @@ if (ENABLE_SDL2) add_library(SDL2 INTERFACE) target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}") else() - message(STATUS "SDL2 2.0.14 or newer not found, falling back to externals.") + message(STATUS "SDL2 2.0.15 or newer not found, falling back to externals.") endif() endif() endif() diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index e044d9730..e280e53d7 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -47,7 +47,10 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include) # SDL2 if (NOT SDL2_FOUND AND ENABLE_SDL2) + set(SDL_STATIC ON) + set(SDL_SHARED OFF) add_subdirectory(SDL EXCLUDE_FROM_ALL) + add_library(SDL2 ALIAS SDL2-static) endif() # SoundTouch diff --git a/externals/SDL b/externals/SDL -Subproject 4cd981609b50ed273d80c635c1ca4c1e5518fb2 +Subproject 107db2d89953ee7cc03417d43da1f26bd03aad5 diff --git a/externals/ffmpeg b/externals/ffmpeg -Subproject 6b6b9e593dd4d3aaf75f48d40a13ef03bdef9fd +Subproject 79e8d17024e6c6328a40fcee191ffd70798a9c6 diff --git a/externals/mbedtls b/externals/mbedtls -Subproject eac2416b8fdb2cb9c867a538100bf95326bad75 +Subproject 8c88150ca139e06aa2aae8349df8292a88148ea diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 4ace2cd33..17d1ee86b 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -108,6 +108,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void); } \ } +#define YUZU_NON_COPYABLE(cls) \ + cls(const cls&) = delete; \ + cls& operator=(const cls&) = delete + +#define YUZU_NON_MOVEABLE(cls) \ + cls(cls&&) = delete; \ + cls& operator=(cls&&) = delete + #define R_SUCCEEDED(res) (res.IsSuccess()) /// Evaluates an expression that returns a result, and returns the result if it would fail. @@ -128,4 +136,19 @@ namespace Common { return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24; } +// std::size() does not support zero-size C arrays. We're fixing that. +template <class C> +constexpr auto Size(const C& c) -> decltype(c.size()) { + return std::size(c); +} + +template <class C> +constexpr std::size_t Size(const C& c) { + if constexpr (sizeof(C) == 0) { + return 0; + } else { + return std::size(c); + } +} + } // namespace Common diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h index c0bbcd457..1f696fe80 100644 --- a/src/common/intrusive_red_black_tree.h +++ b/src/common/intrusive_red_black_tree.h @@ -509,7 +509,6 @@ private: private: static constexpr TypedStorage<Derived> DerivedStorage = {}; - static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage)); }; template <auto T, class Derived = impl::GetParentType<T>> diff --git a/src/common/parent_of_member.h b/src/common/parent_of_member.h index d9a14529d..e0f8ab5c8 100644 --- a/src/common/parent_of_member.h +++ b/src/common/parent_of_member.h @@ -133,27 +133,27 @@ template <auto MemberPtr> using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member; template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> -static inline std::ptrdiff_t OffsetOf = [] { +constexpr std::ptrdiff_t OffsetOf() { using DeducedParentType = GetParentType<MemberPtr>; using MemberType = GetMemberType<MemberPtr>; static_assert(std::is_base_of<DeducedParentType, RealParentType>::value || std::is_same<RealParentType, DeducedParentType>::value); return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr); -}(); +}; } // namespace impl template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) { - std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; + std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>(); return *static_cast<RealParentType*>( static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset)); } template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) { - std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; + std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>(); return *static_cast<const RealParentType*>(static_cast<const void*>( static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset)); } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c28abc24c..83da30418 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -144,31 +144,40 @@ add_library(core STATIC hle/kernel/board/nintendo/nx/k_system_control.cpp hle/kernel/board/nintendo/nx/k_system_control.h hle/kernel/board/nintendo/nx/secure_monitor.h - hle/kernel/client_port.cpp - hle/kernel/client_port.h - hle/kernel/client_session.cpp - hle/kernel/client_session.h hle/kernel/code_set.cpp hle/kernel/code_set.h hle/kernel/svc_results.h hle/kernel/global_scheduler_context.cpp hle/kernel/global_scheduler_context.h - hle/kernel/handle_table.cpp - hle/kernel/handle_table.h hle/kernel/hle_ipc.cpp hle/kernel/hle_ipc.h + hle/kernel/init/init_slab_setup.cpp + hle/kernel/init/init_slab_setup.h hle/kernel/k_address_arbiter.cpp hle/kernel/k_address_arbiter.h hle/kernel/k_address_space_info.cpp hle/kernel/k_address_space_info.h + hle/kernel/k_auto_object.cpp + hle/kernel/k_auto_object.h + hle/kernel/k_auto_object_container.cpp + hle/kernel/k_auto_object_container.h hle/kernel/k_affinity_mask.h + hle/kernel/k_class_token.cpp + hle/kernel/k_class_token.h + hle/kernel/k_client_port.cpp + hle/kernel/k_client_port.h + hle/kernel/k_client_session.cpp + hle/kernel/k_client_session.h hle/kernel/k_condition_variable.cpp hle/kernel/k_condition_variable.h hle/kernel/k_event.cpp hle/kernel/k_event.h + hle/kernel/k_handle_table.cpp + hle/kernel/k_handle_table.h hle/kernel/k_light_condition_variable.h hle/kernel/k_light_lock.cpp hle/kernel/k_light_lock.h + hle/kernel/k_linked_list.h hle/kernel/k_memory_block.h hle/kernel/k_memory_block_manager.cpp hle/kernel/k_memory_block_manager.h @@ -185,7 +194,11 @@ add_library(core STATIC hle/kernel/k_page_linked_list.h hle/kernel/k_page_table.cpp hle/kernel/k_page_table.h + hle/kernel/k_port.cpp + hle/kernel/k_port.h hle/kernel/k_priority_queue.h + hle/kernel/k_process.cpp + hle/kernel/k_process.h hle/kernel/k_readable_event.cpp hle/kernel/k_readable_event.h hle/kernel/k_resource_limit.cpp @@ -196,6 +209,12 @@ add_library(core STATIC hle/kernel/k_scoped_lock.h hle/kernel/k_scoped_resource_reservation.h hle/kernel/k_scoped_scheduler_lock_and_sleep.h + hle/kernel/k_server_port.cpp + hle/kernel/k_server_port.h + hle/kernel/k_server_session.cpp + hle/kernel/k_server_session.h + hle/kernel/k_session.cpp + hle/kernel/k_session.h hle/kernel/k_shared_memory.cpp hle/kernel/k_shared_memory.h hle/kernel/k_slab_heap.h @@ -208,28 +227,21 @@ add_library(core STATIC hle/kernel/k_thread.h hle/kernel/k_thread_queue.h hle/kernel/k_trace.h + hle/kernel/k_transfer_memory.cpp + hle/kernel/k_transfer_memory.h hle/kernel/k_writable_event.cpp hle/kernel/k_writable_event.h hle/kernel/kernel.cpp hle/kernel/kernel.h hle/kernel/memory_types.h - hle/kernel/object.cpp - hle/kernel/object.h hle/kernel/physical_core.cpp hle/kernel/physical_core.h hle/kernel/physical_memory.h - hle/kernel/process.cpp - hle/kernel/process.h hle/kernel/process_capability.cpp hle/kernel/process_capability.h - hle/kernel/server_port.cpp - hle/kernel/server_port.h - hle/kernel/server_session.cpp - hle/kernel/server_session.h hle/kernel/service_thread.cpp hle/kernel/service_thread.h - hle/kernel/session.cpp - hle/kernel/session.h + hle/kernel/slab_helpers.h hle/kernel/svc.cpp hle/kernel/svc.h hle/kernel/svc_common.h @@ -237,8 +249,6 @@ add_library(core STATIC hle/kernel/svc_wrap.h hle/kernel/time_manager.cpp hle/kernel/time_manager.h - hle/kernel/transfer_memory.cpp - hle/kernel/transfer_memory.h hle/lock.cpp hle/lock.h hle/result.h diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4ff72abd8..653bb7a77 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -16,8 +16,8 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hardware_properties.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc.h" #include "core/memory.h" diff --git a/src/core/core.cpp b/src/core/core.cpp index d459d6c34..434bf3262 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -27,12 +27,12 @@ #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" #include "core/hardware_interrupt_manager.h" -#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/apm/controller.h" #include "core/hle/service/filesystem/filesystem.h" @@ -166,9 +166,9 @@ struct System::Impl { cpu_manager.SetAsyncGpu(is_async_gpu); core_timing.SetMulticore(is_multicore); - core_timing.Initialize([&system]() { system.RegisterHostThread(); }); kernel.Initialize(); cpu_manager.Initialize(); + core_timing.Initialize([&system]() { system.RegisterHostThread(); }); const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch()); @@ -233,8 +233,11 @@ struct System::Impl { } telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); - auto main_process = - Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); + auto main_process = Kernel::KProcess::Create(system.Kernel()); + ASSERT(Kernel::KProcess::Initialize(main_process, system, "main", + Kernel::KProcess::ProcessType::Userland) + .IsSuccess()); + main_process->Open(); const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); if (load_result != Loader::ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); @@ -244,7 +247,7 @@ struct System::Impl { static_cast<u32>(load_result)); } AddGlueRegistrationForProcess(*app_loader, *main_process); - kernel.MakeCurrentProcess(main_process.get()); + kernel.MakeCurrentProcess(main_process); kernel.InitializeCores(); // Initialize cheat engine @@ -311,6 +314,7 @@ struct System::Impl { gpu_core.reset(); perf_stats.reset(); kernel.Shutdown(); + memory.Reset(); applet_manager.ClearAll(); LOG_DEBUG(Core, "Shutdown OK"); @@ -322,7 +326,7 @@ struct System::Impl { return app_loader->ReadTitle(out); } - void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::Process& process) { + void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) { std::vector<u8> nacp_data; FileSys::NACP nacp; if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) { @@ -513,7 +517,7 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const { return impl->kernel.GlobalSchedulerContext(); } -Kernel::Process* System::CurrentProcess() { +Kernel::KProcess* System::CurrentProcess() { return impl->kernel.CurrentProcess(); } @@ -525,7 +529,7 @@ const Core::DeviceMemory& System::DeviceMemory() const { return *impl->device_memory; } -const Kernel::Process* System::CurrentProcess() const { +const Kernel::KProcess* System::CurrentProcess() const { return impl->kernel.CurrentProcess(); } diff --git a/src/core/core.h b/src/core/core.h index f1068d23f..8b93ba998 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -12,7 +12,6 @@ #include "common/common_types.h" #include "core/file_sys/vfs_types.h" -#include "core/hle/kernel/object.h" namespace Core::Frontend { class EmuWindow; @@ -29,7 +28,7 @@ namespace Kernel { class GlobalSchedulerContext; class KernelCore; class PhysicalCore; -class Process; +class KProcess; class KScheduler; } // namespace Kernel @@ -264,10 +263,10 @@ public: [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const; /// Provides a pointer to the current process - [[nodiscard]] Kernel::Process* CurrentProcess(); + [[nodiscard]] Kernel::KProcess* CurrentProcess(); /// Provides a constant pointer to the current process. - [[nodiscard]] const Kernel::Process* CurrentProcess() const; + [[nodiscard]] const Kernel::KProcess* CurrentProcess() const; /// Provides a reference to the core timing instance. [[nodiscard]] Timing::CoreTiming& CoreTiming(); diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index de6ab721d..aa7f3072f 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp @@ -13,7 +13,7 @@ #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/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index fa68af3a8..f973d1d21 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -9,7 +9,7 @@ #include "core/core.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/vfs.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" namespace FileSys { diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 56cc911d1..d136be452 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -13,12 +13,9 @@ #include "common/assert.h" #include "common/common_types.h" #include "core/hle/ipc.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/result.h" namespace IPC { @@ -72,16 +69,16 @@ public: AlwaysMoveHandles = 1, }; - explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, + explicit ResponseBuilder(Kernel::HLERequestContext& ctx, u32 normal_params_size, u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, Flags flags = Flags::None) - : RequestHelperBase(context), normal_params_size(normal_params_size), + : RequestHelperBase(ctx), normal_params_size(normal_params_size), num_handles_to_copy(num_handles_to_copy), - num_objects_to_move(num_objects_to_move), kernel{context.kernel} { + num_objects_to_move(num_objects_to_move), kernel{ctx.kernel} { memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); - context.ClearIncomingObjects(); + ctx.ClearIncomingObjects(); IPC::CommandHeader header{}; @@ -93,13 +90,13 @@ public: u32 num_domain_objects{}; const bool always_move_handles{ (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0}; - if (!context.Session()->IsDomain() || always_move_handles) { + if (!ctx.Session()->IsDomain() || always_move_handles) { num_handles_to_move = num_objects_to_move; } else { num_domain_objects = num_objects_to_move; } - if (context.Session()->IsDomain()) { + if (ctx.Session()->IsDomain()) { raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; } @@ -119,7 +116,7 @@ public: AlignWithPadding(); - if (context.Session()->IsDomain() && context.HasDomainMessageHeader()) { + if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) { IPC::DomainMessageHeader domain_header{}; domain_header.num_objects = num_domain_objects; PushRaw(domain_header); @@ -137,9 +134,11 @@ public: if (context->Session()->IsDomain()) { context->AddDomainObject(std::move(iface)); } else { - auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName()); - context->AddMoveObject(std::move(client)); - iface->ClientConnected(std::move(server)); + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(nullptr, iface->GetServiceName()); + + context->AddMoveObject(&session->GetClientSession()); + iface->ClientConnected(&session->GetServerSession()); } } @@ -215,10 +214,16 @@ public: void PushRaw(const T& value); template <typename... O> - void PushMoveObjects(std::shared_ptr<O>... pointers); + void PushMoveObjects(O*... pointers); + + template <typename... O> + void PushMoveObjects(O&... pointers); template <typename... O> - void PushCopyObjects(std::shared_ptr<O>... pointers); + void PushCopyObjects(O*... pointers); + + template <typename... O> + void PushCopyObjects(O&... pointers); private: u32 normal_params_size{}; @@ -301,18 +306,34 @@ void ResponseBuilder::Push(const First& first_value, const Other&... other_value } template <typename... O> -inline void ResponseBuilder::PushCopyObjects(std::shared_ptr<O>... pointers) { +inline void ResponseBuilder::PushCopyObjects(O*... pointers) { auto objects = {pointers...}; for (auto& object : objects) { - context->AddCopyObject(std::move(object)); + context->AddCopyObject(object); } } template <typename... O> -inline void ResponseBuilder::PushMoveObjects(std::shared_ptr<O>... pointers) { +inline void ResponseBuilder::PushCopyObjects(O&... pointers) { + auto objects = {&pointers...}; + for (auto& object : objects) { + context->AddCopyObject(object); + } +} + +template <typename... O> +inline void ResponseBuilder::PushMoveObjects(O*... pointers) { auto objects = {pointers...}; for (auto& object : objects) { - context->AddMoveObject(std::move(object)); + context->AddMoveObject(object); + } +} + +template <typename... O> +inline void ResponseBuilder::PushMoveObjects(O&... pointers) { + auto objects = {&pointers...}; + for (auto& object : objects) { + context->AddMoveObject(object); } } @@ -320,9 +341,9 @@ class RequestParser : public RequestHelperBase { public: explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {} - explicit RequestParser(Kernel::HLERequestContext& context) : RequestHelperBase(context) { - ASSERT_MSG(context.GetDataPayloadOffset(), "context is incomplete"); - Skip(context.GetDataPayloadOffset(), false); + explicit RequestParser(Kernel::HLERequestContext& ctx) : RequestHelperBase(ctx) { + ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete"); + Skip(ctx.GetDataPayloadOffset(), false); // Skip the u64 command id, it's already stored in the context static constexpr u32 CommandIdSize = 2; Skip(CommandIdSize, false); @@ -359,12 +380,6 @@ public: template <typename T> T PopRaw(); - template <typename T> - std::shared_ptr<T> GetMoveObject(std::size_t index); - - template <typename T> - std::shared_ptr<T> GetCopyObject(std::size_t index); - template <class T> std::shared_ptr<T> PopIpcInterface() { ASSERT(context->Session()->IsDomain()); @@ -469,14 +484,4 @@ void RequestParser::Pop(First& first_value, Other&... other_values) { Pop(other_values...); } -template <typename T> -std::shared_ptr<T> RequestParser::GetMoveObject(std::size_t index) { - return context->GetMoveObject<T>(index); -} - -template <typename T> -std::shared_ptr<T> RequestParser::GetCopyObject(std::size_t index) { - return context->GetCopyObject<T>(index); -} - } // namespace IPC diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp deleted file mode 100644 index 0b6957e31..000000000 --- a/src/core/hle/kernel/client_port.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/session.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel { - -ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {} -ClientPort::~ClientPort() = default; - -std::shared_ptr<ServerPort> ClientPort::GetServerPort() const { - return server_port; -} - -ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { - if (active_sessions >= max_sessions) { - return ResultMaxConnectionsReached; - } - active_sessions++; - - auto [client, server] = Kernel::Session::Create(kernel, name); - - if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(std::move(server)); - } else { - server_port->AppendPendingSession(std::move(server)); - } - - return MakeResult(std::move(client)); -} - -void ClientPort::ConnectionClosed() { - if (active_sessions == 0) { - return; - } - - --active_sessions; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h deleted file mode 100644 index 77559ebf9..000000000 --- a/src/core/hle/kernel/client_port.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> - -#include "common/common_types.h" -#include "core/hle/kernel/object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class ClientSession; -class KernelCore; -class ServerPort; - -class ClientPort final : public Object { -public: - explicit ClientPort(KernelCore& kernel); - ~ClientPort() override; - - friend class ServerPort; - std::string GetTypeName() const override { - return "ClientPort"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - std::shared_ptr<ServerPort> GetServerPort() const; - - /** - * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's - * list of pending sessions, and signals the ServerPort, causing any threads - * waiting on it to awake. - * @returns ClientSession The client endpoint of the created Session pair, or error code. - */ - ResultVal<std::shared_ptr<ClientSession>> Connect(); - - /** - * Signifies that a previously active connection has been closed, - * decreasing the total number of active connections to this port. - */ - void ConnectionClosed(); - - void Finalize() override {} - -private: - std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port. - u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have - u32 active_sessions = 0; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp deleted file mode 100644 index e230f365a..000000000 --- a/src/core/hle/kernel/client_session.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" -#include "core/hle/kernel/svc_results.h" -#include "core/hle/result.h" - -namespace Kernel { - -ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} - -ClientSession::~ClientSession() { - // This destructor will be called automatically when the last ClientSession handle is closed by - // the emulated application. - if (parent->Server()) { - parent->Server()->ClientDisconnected(); - } -} - -bool ClientSession::IsSignaled() const { - UNIMPLEMENTED(); - return true; -} - -ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name) { - std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)}; - - client_session->name = std::move(name); - client_session->parent = std::move(parent); - - return MakeResult(std::move(client_session)); -} - -ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread, - Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing) { - // Keep ServerSession alive until we're done working with it. - if (!parent->Server()) { - return ResultSessionClosedByRemote; - } - - // Signal the server session that new data is available - return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h deleted file mode 100644 index 85aafeaf4..000000000 --- a/src/core/hle/kernel/client_session.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> - -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/result.h" - -union ResultCode; - -namespace Core::Memory { -class Memory; -} - -namespace Core::Timing { -class CoreTiming; -} - -namespace Kernel { - -class KernelCore; -class Session; -class KThread; - -class ClientSession final : public KSynchronizationObject { -public: - explicit ClientSession(KernelCore& kernel); - ~ClientSession() override; - - friend class Session; - - std::string GetTypeName() const override { - return "ClientSession"; - } - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - ResultCode SendSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing); - - bool IsSignaled() const override; - - void Finalize() override {} - -private: - static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name = "Unknown"); - - /// The parent session, which links to the server endpoint. - std::shared_ptr<Session> parent; - - /// Name of the client session (optional) - std::string name; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index c6838649f..7c87cbada 100644 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp @@ -17,12 +17,12 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel) GlobalSchedulerContext::~GlobalSchedulerContext() = default; -void GlobalSchedulerContext::AddThread(std::shared_ptr<KThread> thread) { +void GlobalSchedulerContext::AddThread(KThread* thread) { std::scoped_lock lock{global_list_guard}; - thread_list.push_back(std::move(thread)); + thread_list.push_back(thread); } -void GlobalSchedulerContext::RemoveThread(std::shared_ptr<KThread> thread) { +void GlobalSchedulerContext::RemoveThread(KThread* thread) { std::scoped_lock lock{global_list_guard}; thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 11592843e..ba8b67fd1 100644 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -38,13 +38,13 @@ public: ~GlobalSchedulerContext(); /// Adds a new thread to the scheduler - void AddThread(std::shared_ptr<KThread> thread); + void AddThread(KThread* thread); /// Removes a thread from the scheduler - void RemoveThread(std::shared_ptr<KThread> thread); + void RemoveThread(KThread* thread); /// Returns a list of all threads managed by the scheduler - [[nodiscard]] const std::vector<std::shared_ptr<KThread>>& GetThreadList() const { + [[nodiscard]] const std::vector<KThread*>& GetThreadList() const { return thread_list; } @@ -79,7 +79,7 @@ private: LockType scheduler_lock; /// Lists all thread ids that aren't deleted/etc. - std::vector<std::shared_ptr<KThread>> thread_list; + std::vector<KThread*> thread_list; Common::SpinLock global_list_guard{}; }; diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp deleted file mode 100644 index f96d34078..000000000 --- a/src/core/hle/kernel/handle_table.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <utility> -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel { -namespace { -constexpr u16 GetSlot(Handle handle) { - return static_cast<u16>(handle >> 15); -} - -constexpr u16 GetGeneration(Handle handle) { - return static_cast<u16>(handle & 0x7FFF); -} -} // Anonymous namespace - -HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} { - Clear(); -} - -HandleTable::~HandleTable() = default; - -ResultCode HandleTable::SetSize(s32 handle_table_size) { - if (static_cast<u32>(handle_table_size) > MAX_COUNT) { - LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT); - return ResultOutOfMemory; - } - - // Values less than or equal to zero indicate to use the maximum allowable - // size for the handle table in the actual kernel, so we ignore the given - // value in that case, since we assume this by default unless this function - // is called. - if (handle_table_size > 0) { - table_size = static_cast<u16>(handle_table_size); - } - - return RESULT_SUCCESS; -} - -ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) { - DEBUG_ASSERT(obj != nullptr); - - const u16 slot = next_free_slot; - if (slot >= table_size) { - LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); - return ResultHandleTableFull; - } - next_free_slot = generations[slot]; - - const u16 generation = next_generation++; - - // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. - // Horizon OS uses zero to represent an invalid handle, so skip to 1. - if (next_generation >= (1 << 15)) { - next_generation = 1; - } - - generations[slot] = generation; - objects[slot] = std::move(obj); - - Handle handle = generation | (slot << 15); - return MakeResult<Handle>(handle); -} - -ResultVal<Handle> HandleTable::Duplicate(Handle handle) { - std::shared_ptr<Object> object = GetGeneric(handle); - if (object == nullptr) { - LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); - return ResultInvalidHandle; - } - return Create(std::move(object)); -} - -ResultCode HandleTable::Close(Handle handle) { - if (!IsValid(handle)) { - LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle); - return ResultInvalidHandle; - } - - const u16 slot = GetSlot(handle); - - if (objects[slot].use_count() == 1) { - objects[slot]->Finalize(); - } - - objects[slot] = nullptr; - - generations[slot] = next_free_slot; - next_free_slot = slot; - return RESULT_SUCCESS; -} - -bool HandleTable::IsValid(Handle handle) const { - const std::size_t slot = GetSlot(handle); - const u16 generation = GetGeneration(handle); - - return slot < table_size && objects[slot] != nullptr && generations[slot] == generation; -} - -std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { - if (handle == CurrentThread) { - return SharedFrom(kernel.CurrentScheduler()->GetCurrentThread()); - } else if (handle == CurrentProcess) { - return SharedFrom(kernel.CurrentProcess()); - } - - if (!IsValid(handle)) { - return nullptr; - } - return objects[GetSlot(handle)]; -} - -void HandleTable::Clear() { - for (u16 i = 0; i < table_size; ++i) { - generations[i] = static_cast<u16>(i + 1); - objects[i] = nullptr; - } - next_free_slot = 0; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h deleted file mode 100644 index c9dab8cdd..000000000 --- a/src/core/hle/kernel/handle_table.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <cstddef> -#include <memory> - -#include "common/common_types.h" -#include "core/hle/kernel/object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class KernelCore; - -enum KernelHandle : Handle { - InvalidHandle = 0, - CurrentThread = 0xFFFF8000, - CurrentProcess = 0xFFFF8001, -}; - -/** - * This class allows the creation of Handles, which are references to objects that can be tested - * for validity and looked up. Here they are used to pass references to kernel objects to/from the - * emulated process. it has been designed so that it follows the same handle format and has - * approximately the same restrictions as the handle manager in the CTR-OS. - * - * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0). - * The slot index is used to index into the arrays in this class to access the data corresponding - * to the Handle. - * - * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter - * is kept and incremented every time a Handle is created. This is the Handle's "generation". The - * value of the counter is stored into the Handle as well as in the handle table (in the - * "generations" array). When looking up a handle, the Handle's generation must match with the - * value stored on the class, otherwise the Handle is considered invalid. - * - * To find free slots when allocating a Handle without needing to scan the entire object array, the - * generations field of unallocated slots is re-purposed as a linked list of indices to free slots. - * When a Handle is created, an index is popped off the list and used for the new Handle. When it - * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is - * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been - * verified and isn't likely to cause any problems. - */ -class HandleTable final : NonCopyable { -public: - /// This is the maximum limit of handles allowed per process in Horizon - static constexpr std::size_t MAX_COUNT = 1024; - - explicit HandleTable(KernelCore& kernel); - ~HandleTable(); - - /** - * Sets the number of handles that may be in use at one time - * for this handle table. - * - * @param handle_table_size The desired size to limit the handle table to. - * - * @returns an error code indicating if initialization was successful. - * If initialization was not successful, then ERR_OUT_OF_MEMORY - * will be returned. - * - * @pre handle_table_size must be within the range [0, 1024] - */ - ResultCode SetSize(s32 handle_table_size); - - /** - * Allocates a handle for the given object. - * @return The created Handle or one of the following errors: - * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. - */ - ResultVal<Handle> Create(std::shared_ptr<Object> obj); - - /** - * Returns a new handle that points to the same object as the passed in handle. - * @return The duplicated Handle or one of the following errors: - * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. - * - Any errors returned by `Create()`. - */ - ResultVal<Handle> Duplicate(Handle handle); - - /** - * Closes a handle, removing it from the table and decreasing the object's ref-count. - * @return `RESULT_SUCCESS` or one of the following errors: - * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. - */ - ResultCode Close(Handle handle); - - /// Checks if a handle is valid and points to an existing object. - bool IsValid(Handle handle) const; - - /** - * Looks up a handle. - * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. - */ - std::shared_ptr<Object> GetGeneric(Handle handle) const; - - /** - * Looks up a handle while verifying its type. - * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its - * type differs from the requested one. - */ - template <class T> - std::shared_ptr<T> Get(Handle handle) const { - return DynamicObjectCast<T>(GetGeneric(handle)); - } - - /// Closes all handles held in this table. - void Clear(); - -private: - /// Stores the Object referenced by the handle or null if the slot is empty. - std::array<std::shared_ptr<Object>, MAX_COUNT> objects; - - /** - * The value of `next_generation` when the handle was created, used to check for validity. For - * empty slots, contains the index of the next free slot in the list. - */ - std::array<u16, MAX_COUNT> generations; - - /** - * The limited size of the handle table. This can be specified by process - * capabilities in order to restrict the overall number of handles that - * can be created in a process instance - */ - u16 table_size = static_cast<u16>(MAX_COUNT); - - /** - * Global counter of the number of created handles. Stored in `generations` when a handle is - * created, and wraps around to 1 when it hits 0x8000. - */ - u16 next_generation = 1; - - /// Head of the free slots linked list. - u16 next_free_slot = 0; - - /// Underlying kernel instance that this handle table operates under. - KernelCore& kernel; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 2b363b1d9..93907f75e 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -14,17 +14,16 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" #include "core/memory.h" @@ -35,28 +34,23 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(std::shared_ptr<ServerSession> server_session) { - server_session->SetHleHandler(shared_from_this()); - connected_sessions.push_back(std::move(server_session)); +void SessionRequestHandler::ClientConnected(KServerSession* session) { + session->SetHleHandler(shared_from_this()); } -void SessionRequestHandler::ClientDisconnected( - const std::shared_ptr<ServerSession>& server_session) { - server_session->SetHleHandler(nullptr); - boost::range::remove_erase(connected_sessions, server_session); +void SessionRequestHandler::ClientDisconnected(KServerSession* session) { + session->SetHleHandler(nullptr); } -HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, - std::shared_ptr<ServerSession> server_session, - std::shared_ptr<KThread> thread) - : server_session(std::move(server_session)), - thread(std::move(thread)), kernel{kernel}, memory{memory} { +HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, + KServerSession* server_session_, KThread* thread_) + : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { cmd_buf[0] = 0; } HLERequestContext::~HLERequestContext() = default; -void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, +void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming) { IPC::RequestParser rp(src_cmdbuf); command_header = rp.PopRaw<IPC::CommandHeader>(); @@ -77,12 +71,12 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_ for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { const u32 copy_handle{rp.Pop<Handle>()}; copy_handles.push_back(copy_handle); - copy_objects.push_back(handle_table.GetGeneric(copy_handle)); + copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe()); } for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { const u32 move_handle{rp.Pop<Handle>()}; move_handles.push_back(move_handle); - move_objects.push_back(handle_table.GetGeneric(move_handle)); + move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe()); } } else { // For responses we just ignore the handles, they're empty and will be populated when @@ -169,7 +163,7 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_ rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. } -ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, +ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf) { ParseCommandBuffer(handle_table, src_cmdbuf, true); if (command_header->type == IPC::CommandType::Close) { @@ -186,12 +180,12 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl return RESULT_SUCCESS; } -ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { - auto& owner_process = *thread.GetOwnerProcess(); +ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) { + auto& owner_process = *requesting_thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; - memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + memory.ReadBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), dst_cmdbuf.size() * sizeof(u32)); // The header was already built in the internal command buffer. Attempt to parse it to verify @@ -223,12 +217,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { // for specific values in each of these descriptors. for (auto& object : copy_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); + R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); } for (auto& object : move_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); + R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); } } @@ -248,7 +242,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { } // Copy the translated command buffer back into the thread's command buffer area. - memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), dst_cmdbuf.size() * sizeof(u32)); return RESULT_SUCCESS; diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 6fba42615..21e384706 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -16,7 +16,8 @@ #include "common/concepts.h" #include "common/swap.h" #include "core/hle/ipc.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/svc_common.h" union ResultCode; @@ -35,13 +36,14 @@ class ServiceFrameworkBase; namespace Kernel { class Domain; -class HandleTable; class HLERequestContext; class KernelCore; -class Process; -class ServerSession; +class KHandleTable; +class KProcess; +class KServerSession; class KThread; class KReadableEvent; +class KSession; class KWritableEvent; enum class ThreadWakeupReason; @@ -71,20 +73,14 @@ public: * associated ServerSession alive for the duration of the connection. * @param server_session Owning pointer to the ServerSession associated with the connection. */ - void ClientConnected(std::shared_ptr<ServerSession> server_session); + void ClientConnected(KServerSession* session); /** * Signals that a client has just disconnected from this HLE handler and releases the * associated ServerSession. * @param server_session ServerSession associated with the connection. */ - void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session); - -protected: - /// List of sessions that are connected to this handler. - /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list - /// for the duration of the connection. - std::vector<std::shared_ptr<ServerSession>> connected_sessions; + void ClientDisconnected(KServerSession* session); }; /** @@ -109,8 +105,7 @@ protected: class HLERequestContext { public: explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, - std::shared_ptr<ServerSession> session, - std::shared_ptr<KThread> thread); + KServerSession* session, KThread* thread); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. @@ -122,16 +117,16 @@ public: * Returns the session through which this request was made. This can be used as a map key to * access per-client data on services. */ - const std::shared_ptr<Kernel::ServerSession>& Session() const { + Kernel::KServerSession* Session() { return server_session; } /// Populates this context with data from the requesting process/thread. - ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, + ResultCode PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf); /// Writes data from this context back to the requesting process/thread. - ResultCode WriteToOutgoingCommandBuffer(KThread& thread); + ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread); u32_le GetCommand() const { return command; @@ -218,22 +213,12 @@ public: return move_handles.at(index); } - template <typename T> - std::shared_ptr<T> GetCopyObject(std::size_t index) { - return DynamicObjectCast<T>(copy_objects.at(index)); - } - - template <typename T> - std::shared_ptr<T> GetMoveObject(std::size_t index) { - return DynamicObjectCast<T>(move_objects.at(index)); + void AddMoveObject(KAutoObject* object) { + move_objects.emplace_back(object); } - void AddMoveObject(std::shared_ptr<Object> object) { - move_objects.emplace_back(std::move(object)); - } - - void AddCopyObject(std::shared_ptr<Object> object) { - copy_objects.emplace_back(std::move(object)); + void AddCopyObject(KAutoObject* object) { + copy_objects.emplace_back(object); } void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { @@ -276,10 +261,6 @@ public: return *thread; } - const KThread& GetThread() const { - return *thread; - } - bool IsThreadWaiting() const { return is_thread_waiting; } @@ -287,16 +268,17 @@ public: private: friend class IPC::ResponseBuilder; - void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); + void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; - std::shared_ptr<Kernel::ServerSession> server_session; - std::shared_ptr<KThread> thread; + Kernel::KServerSession* server_session{}; + KThread* thread; + // TODO(yuriks): Check common usage of this and optimize size accordingly boost::container::small_vector<Handle, 8> move_handles; boost::container::small_vector<Handle, 8> copy_handles; - boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; - boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; + boost::container::small_vector<KAutoObject*, 8> move_objects; + boost::container::small_vector<KAutoObject*, 8> copy_objects; boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; std::optional<IPC::CommandHeader> command_header; diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp new file mode 100644 index 000000000..69ae405e6 --- /dev/null +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -0,0 +1,192 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/core.h" +#include "core/hardware_properties.h" +#include "core/hle/kernel/init/init_slab_setup.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_system_control.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/memory_types.h" +#include "core/memory.h" + +namespace Kernel::Init { + +#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS + +#define FOREACH_SLAB_TYPE(HANDLER, ...) \ + HANDLER(KProcess, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \ + HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ + HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ + HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ + HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ + HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ + HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ + HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) + +namespace { + +#define DEFINE_SLAB_TYPE_ENUM_MEMBER(NAME, COUNT, ...) KSlabType_##NAME, + +enum KSlabType : u32 { + FOREACH_SLAB_TYPE(DEFINE_SLAB_TYPE_ENUM_MEMBER) KSlabType_Count, +}; + +#undef DEFINE_SLAB_TYPE_ENUM_MEMBER + +// Constexpr counts. +constexpr size_t SlabCountKProcess = 80; +constexpr size_t SlabCountKThread = 800; +constexpr size_t SlabCountKEvent = 700; +constexpr size_t SlabCountKInterruptEvent = 100; +constexpr size_t SlabCountKPort = 256 + 0x20; // Extra 0x20 ports over Nintendo for homebrew. +constexpr size_t SlabCountKSharedMemory = 80; +constexpr size_t SlabCountKTransferMemory = 200; +constexpr size_t SlabCountKCodeMemory = 10; +constexpr size_t SlabCountKDeviceAddressSpace = 300; +constexpr size_t SlabCountKSession = 933; +constexpr size_t SlabCountKLightSession = 100; +constexpr size_t SlabCountKObjectName = 7; +constexpr size_t SlabCountKResourceLimit = 5; +constexpr size_t SlabCountKDebug = Core::Hardware::NUM_CPU_CORES; +constexpr size_t SlabCountKAlpha = 1; +constexpr size_t SlabCountKBeta = 6; + +constexpr size_t SlabCountExtraKThread = 160; + +template <typename T> +VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, + size_t num_objects) { + const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*)); + VAddr start = Common::AlignUp(address, alignof(T)); + + if (size > 0) { + const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1); + ASSERT(region != nullptr); + ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); + T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size); + } + + return start + size; +} + +} // namespace + +KSlabResourceCounts KSlabResourceCounts::CreateDefault() { + return { + .num_KProcess = SlabCountKProcess, + .num_KThread = SlabCountKThread, + .num_KEvent = SlabCountKEvent, + .num_KInterruptEvent = SlabCountKInterruptEvent, + .num_KPort = SlabCountKPort, + .num_KSharedMemory = SlabCountKSharedMemory, + .num_KTransferMemory = SlabCountKTransferMemory, + .num_KCodeMemory = SlabCountKCodeMemory, + .num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace, + .num_KSession = SlabCountKSession, + .num_KLightSession = SlabCountKLightSession, + .num_KObjectName = SlabCountKObjectName, + .num_KResourceLimit = SlabCountKResourceLimit, + .num_KDebug = SlabCountKDebug, + .num_KAlpha = SlabCountKAlpha, + .num_KBeta = SlabCountKBeta, + }; +} + +void InitializeSlabResourceCounts(KernelCore& kernel) { + kernel.SlabResourceCounts() = KSlabResourceCounts::CreateDefault(); + if (KSystemControl::Init::ShouldIncreaseThreadResourceLimit()) { + kernel.SlabResourceCounts().num_KThread += SlabCountExtraKThread; + } +} + +size_t CalculateTotalSlabHeapSize(const KernelCore& kernel) { + size_t size = 0; + +#define ADD_SLAB_SIZE(NAME, COUNT, ...) \ + { \ + size += alignof(NAME); \ + size += Common::AlignUp(sizeof(NAME) * (COUNT), alignof(void*)); \ + }; + + // Add the size required for each slab. + FOREACH_SLAB_TYPE(ADD_SLAB_SIZE) + +#undef ADD_SLAB_SIZE + + // Add the reserved size. + size += KernelSlabHeapGapsSize; + + return size; +} + +void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { + auto& kernel = system.Kernel(); + + // Get the start of the slab region, since that's where we'll be working. + VAddr address = memory_layout.GetSlabRegionAddress(); + + // Initialize slab type array to be in sorted order. + std::array<KSlabType, KSlabType_Count> slab_types; + for (size_t i = 0; i < slab_types.size(); i++) { + slab_types[i] = static_cast<KSlabType>(i); + } + + // N shuffles the slab type array with the following simple algorithm. + for (size_t i = 0; i < slab_types.size(); i++) { + const size_t rnd = KSystemControl::GenerateRandomRange(0, slab_types.size() - 1); + std::swap(slab_types[i], slab_types[rnd]); + } + + // Create an array to represent the gaps between the slabs. + const size_t total_gap_size = KernelSlabHeapGapsSize; + std::array<size_t, slab_types.size()> slab_gaps; + for (size_t i = 0; i < slab_gaps.size(); i++) { + // Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange + // is inclusive. However, Nintendo also has the off-by-one error, and it's "harmless", so we + // will include it ourselves. + slab_gaps[i] = KSystemControl::GenerateRandomRange(0, total_gap_size); + } + + // Sort the array, so that we can treat differences between values as offsets to the starts of + // slabs. + for (size_t i = 1; i < slab_gaps.size(); i++) { + for (size_t j = i; j > 0 && slab_gaps[j - 1] > slab_gaps[j]; j--) { + std::swap(slab_gaps[j], slab_gaps[j - 1]); + } + } + + for (size_t i = 0; i < slab_types.size(); i++) { + // Add the random gap to the address. + address += (i == 0) ? slab_gaps[0] : slab_gaps[i] - slab_gaps[i - 1]; + +#define INITIALIZE_SLAB_HEAP(NAME, COUNT, ...) \ + case KSlabType_##NAME: \ + address = InitializeSlabHeap<NAME>(system, memory_layout, address, COUNT); \ + break; + + // Initialize the slabheap. + switch (slab_types[i]) { + // For each of the slab types, we want to initialize that heap. + FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP) + // If we somehow get an invalid type, abort. + default: + UNREACHABLE(); + } + } +} + +} // namespace Kernel::Init diff --git a/src/core/hle/kernel/init/init_slab_setup.h b/src/core/hle/kernel/init/init_slab_setup.h new file mode 100644 index 000000000..a8f7e0918 --- /dev/null +++ b/src/core/hle/kernel/init/init_slab_setup.h @@ -0,0 +1,43 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Core { +class System; +} // namespace Core + +namespace Kernel { +class KernelCore; +class KMemoryLayout; +} // namespace Kernel + +namespace Kernel::Init { + +struct KSlabResourceCounts { + static KSlabResourceCounts CreateDefault(); + + size_t num_KProcess; + size_t num_KThread; + size_t num_KEvent; + size_t num_KInterruptEvent; + size_t num_KPort; + size_t num_KSharedMemory; + size_t num_KTransferMemory; + size_t num_KCodeMemory; + size_t num_KDeviceAddressSpace; + size_t num_KSession; + size_t num_KLightSession; + size_t num_KObjectName; + size_t num_KResourceLimit; + size_t num_KDebug; + size_t num_KAlpha; + size_t num_KBeta; +}; + +void InitializeSlabResourceCounts(KernelCore& kernel); +size_t CalculateTotalSlabHeapSize(const KernelCore& kernel); +void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout); + +} // namespace Kernel::Init diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp new file mode 100644 index 000000000..dbe237f09 --- /dev/null +++ b/src/core/hle/kernel/k_auto_object.cpp @@ -0,0 +1,14 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_auto_object.h" + +namespace Kernel { + +KAutoObject* KAutoObject::Create(KAutoObject* obj) { + obj->m_ref_count = 1; + return obj; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h new file mode 100644 index 000000000..bc18582be --- /dev/null +++ b/src/core/hle/kernel/k_auto_object.h @@ -0,0 +1,302 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> +#include <string> + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/intrusive_red_black_tree.h" +#include "core/hle/kernel/k_class_token.h" + +namespace Kernel { + +class KernelCore; +class KProcess; + +#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ + YUZU_NON_COPYABLE(CLASS); \ + YUZU_NON_MOVEABLE(CLASS); \ + \ +private: \ + friend class ::Kernel::KClassTokenGenerator; \ + static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \ + static constexpr inline const char* const TypeName = #CLASS; \ + static constexpr inline ClassTokenType ClassToken() { \ + return ::Kernel::ClassToken<CLASS>; \ + } \ + \ +public: \ + using BaseClass = BASE_CLASS; \ + static constexpr TypeObj GetStaticTypeObj() { \ + constexpr ClassTokenType Token = ClassToken(); \ + return TypeObj(TypeName, Token); \ + } \ + static constexpr const char* GetStaticTypeName() { \ + return TypeName; \ + } \ + virtual TypeObj GetTypeObj() const { \ + return GetStaticTypeObj(); \ + } \ + virtual const char* GetTypeName() const { \ + return GetStaticTypeName(); \ + } \ + \ +private: \ + constexpr bool operator!=(const TypeObj& rhs) + +class KAutoObject { +protected: + class TypeObj { + public: + constexpr explicit TypeObj(const char* n, ClassTokenType tok) + : m_name(n), m_class_token(tok) {} + + constexpr const char* GetName() const { + return m_name; + } + constexpr ClassTokenType GetClassToken() const { + return m_class_token; + } + + constexpr bool operator==(const TypeObj& rhs) const { + return this->GetClassToken() == rhs.GetClassToken(); + } + + constexpr bool operator!=(const TypeObj& rhs) const { + return this->GetClassToken() != rhs.GetClassToken(); + } + + constexpr bool IsDerivedFrom(const TypeObj& rhs) const { + return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken(); + } + + private: + const char* m_name; + ClassTokenType m_class_token; + }; + +private: + KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); + +public: + explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {} + virtual ~KAutoObject() = default; + + static KAutoObject* Create(KAutoObject* ptr); + + // Destroy is responsible for destroying the auto object's resources when ref_count hits zero. + virtual void Destroy() { + UNIMPLEMENTED(); + } + + // Finalize is responsible for cleaning up resource, but does not destroy the object. + virtual void Finalize() {} + + virtual KProcess* GetOwner() const { + return nullptr; + } + + u32 GetReferenceCount() const { + return m_ref_count.load(); + } + + bool IsDerivedFrom(const TypeObj& rhs) const { + return this->GetTypeObj().IsDerivedFrom(rhs); + } + + bool IsDerivedFrom(const KAutoObject& rhs) const { + return this->IsDerivedFrom(rhs.GetTypeObj()); + } + + template <typename Derived> + Derived DynamicCast() { + static_assert(std::is_pointer_v<Derived>); + using DerivedType = std::remove_pointer_t<Derived>; + + if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { + return static_cast<Derived>(this); + } else { + return nullptr; + } + } + + template <typename Derived> + const Derived DynamicCast() const { + static_assert(std::is_pointer_v<Derived>); + using DerivedType = std::remove_pointer_t<Derived>; + + if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { + return static_cast<Derived>(this); + } else { + return nullptr; + } + } + + bool Open() { + // Atomically increment the reference count, only if it's positive. + u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire); + do { + if (cur_ref_count == 0) { + return false; + } + ASSERT(cur_ref_count < cur_ref_count + 1); + } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1, + std::memory_order_relaxed)); + + return true; + } + + void Close() { + // Atomically decrement the reference count, not allowing it to become negative. + u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire); + do { + ASSERT(cur_ref_count > 0); + } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1, + std::memory_order_relaxed)); + + // If ref count hits zero, destroy the object. + if (cur_ref_count - 1 == 0) { + this->Destroy(); + } + } + +protected: + KernelCore& kernel; + std::string name; + +private: + std::atomic<u32> m_ref_count{}; +}; + +class KAutoObjectWithListContainer; + +class KAutoObjectWithList : public KAutoObject { +public: + explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {} + + static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) { + const u64 lid = lhs.GetId(); + const u64 rid = rhs.GetId(); + + if (lid < rid) { + return -1; + } else if (lid > rid) { + return 1; + } else { + return 0; + } + } + +public: + virtual u64 GetId() const { + return reinterpret_cast<u64>(this); + } + + virtual const std::string& GetName() const { + return name; + } + +private: + friend class KAutoObjectWithListContainer; + + Common::IntrusiveRedBlackTreeNode list_node; +}; + +template <typename T> +class KScopedAutoObject { + YUZU_NON_COPYABLE(KScopedAutoObject); + +public: + constexpr KScopedAutoObject() = default; + + constexpr KScopedAutoObject(T* o) : m_obj(o) { + if (m_obj != nullptr) { + m_obj->Open(); + } + } + + ~KScopedAutoObject() { + if (m_obj != nullptr) { + m_obj->Close(); + } + m_obj = nullptr; + } + + template <typename U> + requires(std::derived_from<T, U> || + std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) { + if constexpr (std::derived_from<U, T>) { + // Upcast. + m_obj = rhs.m_obj; + rhs.m_obj = nullptr; + } else { + // Downcast. + T* derived = nullptr; + if (rhs.m_obj != nullptr) { + derived = rhs.m_obj->template DynamicCast<T*>(); + if (derived == nullptr) { + rhs.m_obj->Close(); + } + } + + m_obj = derived; + rhs.m_obj = nullptr; + } + } + + constexpr KScopedAutoObject<T>& operator=(KScopedAutoObject<T>&& rhs) { + rhs.Swap(*this); + return *this; + } + + constexpr T* operator->() { + return m_obj; + } + constexpr T& operator*() { + return *m_obj; + } + + constexpr void Reset(T* o) { + KScopedAutoObject(o).Swap(*this); + } + + constexpr T* GetPointerUnsafe() { + return m_obj; + } + + constexpr T* GetPointerUnsafe() const { + return m_obj; + } + + constexpr T* ReleasePointerUnsafe() { + T* ret = m_obj; + m_obj = nullptr; + return ret; + } + + constexpr bool IsNull() const { + return m_obj == nullptr; + } + constexpr bool IsNotNull() const { + return m_obj != nullptr; + } + +private: + template <typename U> + friend class KScopedAutoObject; + +private: + T* m_obj{}; + +private: + constexpr void Swap(KScopedAutoObject& rhs) noexcept { + std::swap(m_obj, rhs.m_obj); + } +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp new file mode 100644 index 000000000..fc0c28874 --- /dev/null +++ b/src/core/hle/kernel/k_auto_object_container.cpp @@ -0,0 +1,28 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_auto_object_container.h" + +namespace Kernel { + +void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) { + KScopedLightLock lk(m_lock); + + m_object_list.insert(*obj); +} + +void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { + KScopedLightLock lk(m_lock); + + m_object_list.erase(m_object_list.iterator_to(*obj)); +} + +size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { + KScopedLightLock lk(m_lock); + + return std::count_if(m_object_list.begin(), m_object_list.end(), + [&](const auto& obj) { return obj.GetOwner() == owner; }); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h new file mode 100644 index 000000000..ff40cf5a7 --- /dev/null +++ b/src/core/hle/kernel/k_auto_object_container.h @@ -0,0 +1,70 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/intrusive_red_black_tree.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_light_lock.h" + +namespace Kernel { + +class KernelCore; +class KProcess; + +class KAutoObjectWithListContainer { + YUZU_NON_COPYABLE(KAutoObjectWithListContainer); + YUZU_NON_MOVEABLE(KAutoObjectWithListContainer); + +public: + using ListType = Common::IntrusiveRedBlackTreeMemberTraits< + &KAutoObjectWithList::list_node>::TreeType<KAutoObjectWithList>; + +public: + class ListAccessor : public KScopedLightLock { + public: + explicit ListAccessor(KAutoObjectWithListContainer* container) + : KScopedLightLock(container->m_lock), m_list(container->m_object_list) {} + explicit ListAccessor(KAutoObjectWithListContainer& container) + : KScopedLightLock(container.m_lock), m_list(container.m_object_list) {} + + typename ListType::iterator begin() const { + return m_list.begin(); + } + + typename ListType::iterator end() const { + return m_list.end(); + } + + typename ListType::iterator find(typename ListType::const_reference ref) const { + return m_list.find(ref); + } + + private: + ListType& m_list; + }; + + friend class ListAccessor; + +public: + KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {} + + void Initialize() {} + void Finalize() {} + + void Register(KAutoObjectWithList* obj); + void Unregister(KAutoObjectWithList* obj); + size_t GetOwnedCount(KProcess* owner); + +private: + KLightLock m_lock; + ListType m_object_list; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_class_token.cpp b/src/core/hle/kernel/k_class_token.cpp new file mode 100644 index 000000000..beb8a2a05 --- /dev/null +++ b/src/core/hle/kernel/k_class_token.cpp @@ -0,0 +1,133 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_class_token.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/k_writable_event.h" + +namespace Kernel { + +// Ensure that we generate correct class tokens for all types. + +// Ensure that the absolute token values are correct. +static_assert(ClassToken<KAutoObject> == 0b00000000'00000000); +static_assert(ClassToken<KSynchronizationObject> == 0b00000000'00000001); +static_assert(ClassToken<KReadableEvent> == 0b00000000'00000011); +// static_assert(ClassToken<KInterruptEvent> == 0b00000111'00000011); +// static_assert(ClassToken<KDebug> == 0b00001011'00000001); +static_assert(ClassToken<KThread> == 0b00010011'00000001); +static_assert(ClassToken<KServerPort> == 0b00100011'00000001); +static_assert(ClassToken<KServerSession> == 0b01000011'00000001); +static_assert(ClassToken<KClientPort> == 0b10000011'00000001); +static_assert(ClassToken<KClientSession> == 0b00001101'00000000); +static_assert(ClassToken<KProcess> == 0b00010101'00000001); +static_assert(ClassToken<KResourceLimit> == 0b00100101'00000000); +// static_assert(ClassToken<KLightSession> == 0b01000101'00000000); +static_assert(ClassToken<KPort> == 0b10000101'00000000); +static_assert(ClassToken<KSession> == 0b00011001'00000000); +static_assert(ClassToken<KSharedMemory> == 0b00101001'00000000); +static_assert(ClassToken<KEvent> == 0b01001001'00000000); +static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000); +// static_assert(ClassToken<KLightClientSession> == 0b00110001'00000000); +// static_assert(ClassToken<KLightServerSession> == 0b01010001'00000000); +static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000); +// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000); +// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000); +// static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000); + +// Ensure that the token hierarchy is correct. + +// Base classes +static_assert(ClassToken<KAutoObject> == (0b00000000)); +static_assert(ClassToken<KSynchronizationObject> == (0b00000001 | ClassToken<KAutoObject>)); +static_assert(ClassToken<KReadableEvent> == (0b00000010 | ClassToken<KSynchronizationObject>)); + +// Final classes +// static_assert(ClassToken<KInterruptEvent> == ((0b00000111 << 8) | ClassToken<KReadableEvent>)); +// static_assert(ClassToken<KDebug> == ((0b00001011 << 8) | ClassToken<KSynchronizationObject>)); +static_assert(ClassToken<KThread> == ((0b00010011 << 8) | ClassToken<KSynchronizationObject>)); +static_assert(ClassToken<KServerPort> == ((0b00100011 << 8) | ClassToken<KSynchronizationObject>)); +static_assert(ClassToken<KServerSession> == + ((0b01000011 << 8) | ClassToken<KSynchronizationObject>)); +static_assert(ClassToken<KClientPort> == ((0b10000011 << 8) | ClassToken<KSynchronizationObject>)); +static_assert(ClassToken<KClientSession> == ((0b00001101 << 8) | ClassToken<KAutoObject>)); +static_assert(ClassToken<KProcess> == ((0b00010101 << 8) | ClassToken<KSynchronizationObject>)); +static_assert(ClassToken<KResourceLimit> == ((0b00100101 << 8) | ClassToken<KAutoObject>)); +// static_assert(ClassToken<KLightSession> == ((0b01000101 << 8) | ClassToken<KAutoObject>)); +static_assert(ClassToken<KPort> == ((0b10000101 << 8) | ClassToken<KAutoObject>)); +static_assert(ClassToken<KSession> == ((0b00011001 << 8) | ClassToken<KAutoObject>)); +static_assert(ClassToken<KSharedMemory> == ((0b00101001 << 8) | ClassToken<KAutoObject>)); +static_assert(ClassToken<KEvent> == ((0b01001001 << 8) | ClassToken<KAutoObject>)); +static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAutoObject>)); +// static_assert(ClassToken<KLightClientSession> == ((0b00110001 << 8) | ClassToken<KAutoObject>)); +// static_assert(ClassToken<KLightServerSession> == ((0b01010001 << 8) | ClassToken<KAutoObject>)); +static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>)); +// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>)); +// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>)); +// static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>)); + +// Ensure that the token hierarchy reflects the class hierarchy. + +// Base classes. +static_assert(!std::is_final<KSynchronizationObject>::value && + std::is_base_of<KAutoObject, KSynchronizationObject>::value); +static_assert(!std::is_final<KReadableEvent>::value && + std::is_base_of<KSynchronizationObject, KReadableEvent>::value); + +// Final classes +// static_assert(std::is_final<KInterruptEvent>::value && +// std::is_base_of<KReadableEvent, KInterruptEvent>::value); +// static_assert(std::is_final<KDebug>::value && +// std::is_base_of<KSynchronizationObject, KDebug>::value); +static_assert(std::is_final<KThread>::value && + std::is_base_of<KSynchronizationObject, KThread>::value); +static_assert(std::is_final<KServerPort>::value && + std::is_base_of<KSynchronizationObject, KServerPort>::value); +static_assert(std::is_final<KServerSession>::value && + std::is_base_of<KSynchronizationObject, KServerSession>::value); +static_assert(std::is_final<KClientPort>::value && + std::is_base_of<KSynchronizationObject, KClientPort>::value); +static_assert(std::is_final<KClientSession>::value && + std::is_base_of<KAutoObject, KClientSession>::value); +static_assert(std::is_final<KProcess>::value && + std::is_base_of<KSynchronizationObject, KProcess>::value); +static_assert(std::is_final<KResourceLimit>::value && + std::is_base_of<KAutoObject, KResourceLimit>::value); +// static_assert(std::is_final<KLightSession>::value && +// std::is_base_of<KAutoObject, KLightSession>::value); +static_assert(std::is_final<KPort>::value && std::is_base_of<KAutoObject, KPort>::value); +static_assert(std::is_final<KSession>::value && std::is_base_of<KAutoObject, KSession>::value); +static_assert(std::is_final<KSharedMemory>::value && + std::is_base_of<KAutoObject, KSharedMemory>::value); +static_assert(std::is_final<KEvent>::value && std::is_base_of<KAutoObject, KEvent>::value); +static_assert(std::is_final<KWritableEvent>::value && + std::is_base_of<KAutoObject, KWritableEvent>::value); +// static_assert(std::is_final<KLightClientSession>::value && +// std::is_base_of<KAutoObject, KLightClientSession>::value); +// static_assert(std::is_final<KLightServerSession>::value && +// std::is_base_of<KAutoObject, KLightServerSession>::value); +static_assert(std::is_final<KTransferMemory>::value && + std::is_base_of<KAutoObject, KTransferMemory>::value); +// static_assert(std::is_final<KDeviceAddressSpace>::value && +// std::is_base_of<KAutoObject, KDeviceAddressSpace>::value); +// static_assert(std::is_final<KSessionRequest>::value && +// std::is_base_of<KAutoObject, KSessionRequest>::value); +// static_assert(std::is_final<KCodeMemory>::value && +// std::is_base_of<KAutoObject, KCodeMemory>::value); + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_class_token.h b/src/core/hle/kernel/k_class_token.h new file mode 100644 index 000000000..c28db49ec --- /dev/null +++ b/src/core/hle/kernel/k_class_token.h @@ -0,0 +1,131 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> + +#include "common/assert.h" +#include "common/bit_util.h" +#include "common/common_types.h" + +namespace Kernel { + +class KAutoObject; + +class KClassTokenGenerator { +public: + using TokenBaseType = u16; + +public: + static constexpr size_t BaseClassBits = 8; + static constexpr size_t FinalClassBits = (sizeof(TokenBaseType) * CHAR_BIT) - BaseClassBits; + // One bit per base class. + static constexpr size_t NumBaseClasses = BaseClassBits; + // Final classes are permutations of three bits. + static constexpr size_t NumFinalClasses = [] { + TokenBaseType index = 0; + for (size_t i = 0; i < FinalClassBits; i++) { + for (size_t j = i + 1; j < FinalClassBits; j++) { + for (size_t k = j + 1; k < FinalClassBits; k++) { + index++; + } + } + } + return index; + }(); + +private: + template <TokenBaseType Index> + static constexpr inline TokenBaseType BaseClassToken = 1U << Index; + + template <TokenBaseType Index> + static constexpr inline TokenBaseType FinalClassToken = [] { + TokenBaseType index = 0; + for (size_t i = 0; i < FinalClassBits; i++) { + for (size_t j = i + 1; j < FinalClassBits; j++) { + for (size_t k = j + 1; k < FinalClassBits; k++) { + if ((index++) == Index) { + return static_cast<TokenBaseType>(((1ULL << i) | (1ULL << j) | (1ULL << k)) + << BaseClassBits); + } + } + } + } + }(); + + template <typename T> + static constexpr inline TokenBaseType GetClassToken() { + static_assert(std::is_base_of<KAutoObject, T>::value); + if constexpr (std::is_same<T, KAutoObject>::value) { + static_assert(T::ObjectType == ObjectType::KAutoObject); + return 0; + } else if constexpr (!std::is_final<T>::value) { + static_assert(ObjectType::BaseClassesStart <= T::ObjectType && + T::ObjectType < ObjectType::BaseClassesEnd); + constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) - + static_cast<TokenBaseType>(ObjectType::BaseClassesStart); + return BaseClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>(); + } else if constexpr (ObjectType::FinalClassesStart <= T::ObjectType && + T::ObjectType < ObjectType::FinalClassesEnd) { + constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) - + static_cast<TokenBaseType>(ObjectType::FinalClassesStart); + return FinalClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>(); + } else { + static_assert(!std::is_same<T, T>::value, "GetClassToken: Invalid Type"); + } + }; + +public: + enum class ObjectType { + KAutoObject, + + BaseClassesStart, + + KSynchronizationObject = BaseClassesStart, + KReadableEvent, + + BaseClassesEnd, + + FinalClassesStart = BaseClassesEnd, + + KInterruptEvent = FinalClassesStart, + KDebug, + KThread, + KServerPort, + KServerSession, + KClientPort, + KClientSession, + KProcess, + KResourceLimit, + KLightSession, + KPort, + KSession, + KSharedMemory, + KEvent, + KWritableEvent, + KLightClientSession, + KLightServerSession, + KTransferMemory, + KDeviceAddressSpace, + KSessionRequest, + KCodeMemory, + + // NOTE: True order for these has not been determined yet. + KAlpha, + KBeta, + + FinalClassesEnd = FinalClassesStart + NumFinalClasses, + }; + + template <typename T> + static constexpr inline TokenBaseType ClassToken = GetClassToken<T>(); +}; + +using ClassTokenType = KClassTokenGenerator::TokenBaseType; + +template <typename T> +static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken<T>; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp new file mode 100644 index 000000000..e14b915b9 --- /dev/null +++ b/src/core/hle/kernel/k_client_port.cpp @@ -0,0 +1,125 @@ +// Copyright 2021 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/scope_exit.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} +KClientPort::~KClientPort() = default; + +void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) { + // Set member variables. + num_sessions = 0; + peak_sessions = 0; + parent = parent_; + max_sessions = max_sessions_; + name = std::move(name_); +} + +void KClientPort::OnSessionFinalized() { + KScopedSchedulerLock sl{kernel}; + + const auto prev = num_sessions--; + if (prev == max_sessions) { + this->NotifyAvailable(); + } +} + +void KClientPort::OnServerClosed() {} + +bool KClientPort::IsLight() const { + return this->GetParent()->IsLight(); +} + +bool KClientPort::IsServerClosed() const { + return this->GetParent()->IsServerClosed(); +} + +void KClientPort::Destroy() { + // Note with our parent that we're closed. + parent->OnClientClosed(); + + // Close our reference to our parent. + parent->Close(); +} + +bool KClientPort::IsSignaled() const { + return num_sessions < max_sessions; +} + +ResultCode KClientPort::CreateSession(KClientSession** out) { + // Reserve a new session from the resource limit. + KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), + LimitableResource::Sessions); + R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); + + // Update the session counts. + { + // Atomically increment the number of sessions. + s32 new_sessions; + { + const auto max = max_sessions; + auto cur_sessions = num_sessions.load(std::memory_order_acquire); + do { + R_UNLESS(cur_sessions < max, ResultOutOfSessions); + new_sessions = cur_sessions + 1; + } while (!num_sessions.compare_exchange_weak(cur_sessions, new_sessions, + std::memory_order_relaxed)); + } + + // Atomically update the peak session tracking. + { + auto peak = peak_sessions.load(std::memory_order_acquire); + do { + if (peak >= new_sessions) { + break; + } + } while (!peak_sessions.compare_exchange_weak(peak, new_sessions, + std::memory_order_relaxed)); + } + } + + // Create a new session. + KSession* session = KSession::Create(kernel); + if (session == nullptr) { + /* Decrement the session count. */ + const auto prev = num_sessions--; + if (prev == max_sessions) { + this->NotifyAvailable(); + } + + return ResultOutOfResource; + } + + // Initialize the session. + session->Initialize(this, parent->GetName()); + + // Commit the session reservation. + session_reservation.Commit(); + + // Register the session. + KSession::Register(kernel, session); + auto session_guard = SCOPE_GUARD({ + session->GetClientSession().Close(); + session->GetServerSession().Close(); + }); + + // Enqueue the session with our parent. + R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession()))); + + // We succeeded, so set the output. + session_guard.Cancel(); + *out = std::addressof(session->GetClientSession()); + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h new file mode 100644 index 000000000..d00ce3ddd --- /dev/null +++ b/src/core/hle/kernel/k_client_port.h @@ -0,0 +1,61 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> + +#include "common/common_types.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KClientSession; +class KernelCore; +class KPort; + +class KClientPort final : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); + +public: + explicit KClientPort(KernelCore& kernel_); + virtual ~KClientPort() override; + + void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_); + void OnSessionFinalized(); + void OnServerClosed(); + + const KPort* GetParent() const { + return parent; + } + + s32 GetNumSessions() const { + return num_sessions; + } + s32 GetPeakSessions() const { + return peak_sessions; + } + s32 GetMaxSessions() const { + return max_sessions; + } + + bool IsLight() const; + bool IsServerClosed() const; + + // Overridden virtual functions. + virtual void Destroy() override; + virtual bool IsSignaled() const override; + + ResultCode CreateSession(KClientSession** out); + +private: + std::atomic<s32> num_sessions{}; + std::atomic<s32> peak_sessions{}; + s32 max_sessions{}; + KPort* parent{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp new file mode 100644 index 000000000..8ad1be762 --- /dev/null +++ b/src/core/hle/kernel/k_client_session.cpp @@ -0,0 +1,32 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/result.h" + +namespace Kernel { + +KClientSession::KClientSession(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_} {} +KClientSession::~KClientSession() = default; + +void KClientSession::Destroy() { + parent->OnClientClosed(); + parent->Close(); +} + +void KClientSession::OnServerClosed() {} + +ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { + // Signal the server session that new data is available + return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h new file mode 100644 index 000000000..720a8c243 --- /dev/null +++ b/src/core/hle/kernel/k_client_session.h @@ -0,0 +1,61 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> + +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +union ResultCode; + +namespace Core::Memory { +class Memory; +} + +namespace Core::Timing { +class CoreTiming; +} + +namespace Kernel { + +class KernelCore; +class KSession; +class KThread; + +class KClientSession final + : public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); + +public: + explicit KClientSession(KernelCore& kernel_); + virtual ~KClientSession(); + + void Initialize(KSession* parent_, std::string&& name_) { + // Set member variables. + parent = parent_; + name = std::move(name_); + } + + virtual void Destroy() override; + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + KSession* GetParent() const { + return parent; + } + + ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing); + + void OnServerClosed(); + +private: + KSession* parent{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 170d8fa0d..ce3bade60 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -7,12 +7,13 @@ #include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_linked_list.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_results.h" #include "core/memory.h" @@ -107,8 +108,8 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val // Wait for the address. { - std::shared_ptr<KThread> owner_thread; - ASSERT(!owner_thread); + KScopedAutoObject<KThread> owner_thread; + ASSERT(owner_thread.IsNull()); { KScopedSchedulerLock sl(kernel); cur_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); @@ -126,8 +127,10 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS); // Get the lock owner thread. - owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle); - R_UNLESS(owner_thread, ResultInvalidHandle); + owner_thread = + kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle<KThread>( + handle); + R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle); // Update the lock. cur_thread->SetAddressKey(addr, value); @@ -137,7 +140,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val cur_thread->SetMutexWaitAddressForDebugging(addr); } } - ASSERT(owner_thread); + ASSERT(owner_thread.IsNotNull()); } // Remove the thread as a waiter from the lock owner. @@ -176,19 +179,22 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { KThread* thread_to_close = nullptr; if (can_access) { - if (prev_tag == InvalidHandle) { + if (prev_tag == Svc::InvalidHandle) { // If nobody held the lock previously, we're all good. thread->SetSyncedObject(nullptr, RESULT_SUCCESS); thread->Wakeup(); } else { // Get the previous owner. - auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>( - prev_tag & ~Svc::HandleWaitMask); + KThread* owner_thread = kernel.CurrentProcess() + ->GetHandleTable() + .GetObjectWithoutPseudoHandle<KThread>( + static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask)) + .ReleasePointerUnsafe(); if (owner_thread) { // Add the thread as a waiter on the owner. owner_thread->AddWaiter(thread); - thread_to_close = owner_thread.get(); + thread_to_close = owner_thread; } else { // The lock was tagged with a thread that doesn't exist. thread->SetSyncedObject(nullptr, ResultInvalidState); @@ -208,9 +214,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // Prepare for signaling. constexpr int MaxThreads = 16; - // TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using - // std::shared_ptr. - std::vector<std::shared_ptr<KThread>> thread_list; + KLinkedList<KThread> thread_list{kernel}; std::array<KThread*, MaxThreads> thread_array; s32 num_to_close{}; @@ -228,7 +232,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { if (num_to_close < MaxThreads) { thread_array[num_to_close++] = thread; } else { - thread_list.push_back(SharedFrom(thread)); + thread_list.push_back(*thread); } } @@ -251,7 +255,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // Close threads in the list. for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { - (*it)->Close(); + (*it).Close(); } } diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp index bb2fa4ad5..0720efece 100644 --- a/src/core/hle/kernel/k_event.cpp +++ b/src/core/hle/kernel/k_event.cpp @@ -3,30 +3,54 @@ // Refer to the license.txt file included. #include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_resource_limit.h" namespace Kernel { -KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {} +KEvent::KEvent(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_}, readable_event{kernel_}, writable_event{ + kernel_} {} KEvent::~KEvent() = default; -std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) { - return std::make_shared<KEvent>(kernel, std::move(name)); -} +void KEvent::Initialize(std::string&& name_) { + // Increment reference count. + // Because reference count is one on creation, this will result + // in a reference count of two. Thus, when both readable and + // writable events are closed this object will be destroyed. + Open(); -void KEvent::Initialize() { // Create our sub events. - readable_event = std::make_shared<KReadableEvent>(kernel, GetName() + ":Readable"); - writable_event = std::make_shared<KWritableEvent>(kernel, GetName() + ":Writable"); + KAutoObject::Create(std::addressof(readable_event)); + KAutoObject::Create(std::addressof(writable_event)); // Initialize our sub sessions. - readable_event->Initialize(this); - writable_event->Initialize(this); + readable_event.Initialize(this, name_ + ":Readable"); + writable_event.Initialize(this, name_ + ":Writable"); + + // Set our owner process. + owner = kernel.CurrentProcess(); + if (owner) { + owner->Open(); + } // Mark initialized. + name = std::move(name_); initialized = true; } +void KEvent::Finalize() { + KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList>::Finalize(); +} + +void KEvent::PostDestroy(uintptr_t arg) { + // Release the event count resource the owner process holds. + KProcess* owner = reinterpret_cast<KProcess*>(arg); + if (owner) { + owner->GetResourceLimit()->Release(LimitableResource::Events, 1); + owner->Close(); + } +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index 2fb887129..9a59ffb70 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -4,53 +4,54 @@ #pragma once -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/kernel/slab_helpers.h" namespace Kernel { class KernelCore; class KReadableEvent; class KWritableEvent; +class KProcess; -class KEvent final : public Object { -public: - explicit KEvent(KernelCore& kernel, std::string&& name); - ~KEvent() override; +class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject); - static std::shared_ptr<KEvent> Create(KernelCore& kernel, std::string&& name); +public: + explicit KEvent(KernelCore& kernel_); + virtual ~KEvent(); - void Initialize(); + void Initialize(std::string&& name); - void Finalize() override {} + virtual void Finalize() override; - std::string GetTypeName() const override { - return "KEvent"; + virtual bool IsInitialized() const override { + return initialized; } - static constexpr HandleType HANDLE_TYPE = HandleType::Event; - HandleType GetHandleType() const override { - return HANDLE_TYPE; + virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast<uintptr_t>(owner); } - std::shared_ptr<KReadableEvent>& GetReadableEvent() { - return readable_event; - } + static void PostDestroy(uintptr_t arg); - std::shared_ptr<KWritableEvent>& GetWritableEvent() { - return writable_event; + virtual KProcess* GetOwner() const override { + return owner; } - const std::shared_ptr<KReadableEvent>& GetReadableEvent() const { + KReadableEvent& GetReadableEvent() { return readable_event; } - const std::shared_ptr<KWritableEvent>& GetWritableEvent() const { + KWritableEvent& GetWritableEvent() { return writable_event; } private: - std::shared_ptr<KReadableEvent> readable_event; - std::shared_ptr<KWritableEvent> writable_event; + KReadableEvent readable_event; + KWritableEvent writable_event; + KProcess* owner{}; bool initialized{}; }; diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp new file mode 100644 index 000000000..0378447f6 --- /dev/null +++ b/src/core/hle/kernel/k_handle_table.cpp @@ -0,0 +1,135 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_handle_table.h" + +namespace Kernel { + +KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {} +KHandleTable ::~KHandleTable() = default; + +ResultCode KHandleTable::Finalize() { + // Get the table and clear our record of it. + u16 saved_table_size = 0; + { + KScopedSpinLock lk(m_lock); + + std::swap(m_table_size, saved_table_size); + } + + // Close and free all entries. + for (size_t i = 0; i < saved_table_size; i++) { + if (KAutoObject* obj = m_objects[i]; obj != nullptr) { + obj->Close(); + } + } + + return RESULT_SUCCESS; +} + +bool KHandleTable::Remove(Handle handle) { + // Don't allow removal of a pseudo-handle. + if (Svc::IsPseudoHandle(handle)) { + return false; + } + + // Handles must not have reserved bits set. + const auto handle_pack = HandlePack(handle); + if (handle_pack.reserved != 0) { + return false; + } + + // Find the object and free the entry. + KAutoObject* obj = nullptr; + { + KScopedSpinLock lk(m_lock); + + if (this->IsValidHandle(handle)) { + const auto index = handle_pack.index; + + obj = m_objects[index]; + this->FreeEntry(index); + } else { + return false; + } + } + + // Close the object. + obj->Close(); + return true; +} + +ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { + KScopedSpinLock lk(m_lock); + + // Never exceed our capacity. + R_UNLESS(m_count < m_table_size, ResultOutOfHandles); + + // Allocate entry, set output handle. + { + const auto linear_id = this->AllocateLinearId(); + const auto index = this->AllocateEntry(); + + m_entry_infos[index].info = {.linear_id = linear_id, .type = type}; + m_objects[index] = obj; + + obj->Open(); + + *out_handle = EncodeHandle(static_cast<u16>(index), linear_id); + } + + return RESULT_SUCCESS; +} + +ResultCode KHandleTable::Reserve(Handle* out_handle) { + KScopedSpinLock lk(m_lock); + + // Never exceed our capacity. + R_UNLESS(m_count < m_table_size, ResultOutOfHandles); + + *out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId()); + return RESULT_SUCCESS; +} + +void KHandleTable::Unreserve(Handle handle) { + KScopedSpinLock lk(m_lock); + + // Unpack the handle. + const auto handle_pack = HandlePack(handle); + const auto index = handle_pack.index; + const auto linear_id = handle_pack.linear_id; + const auto reserved = handle_pack.reserved; + ASSERT(reserved == 0); + ASSERT(linear_id != 0); + + if (index < m_table_size) { + // NOTE: This code does not check the linear id. + ASSERT(m_objects[index] == nullptr); + this->FreeEntry(index); + } +} + +void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { + KScopedSpinLock lk(m_lock); + + // Unpack the handle. + const auto handle_pack = HandlePack(handle); + const auto index = handle_pack.index; + const auto linear_id = handle_pack.linear_id; + const auto reserved = handle_pack.reserved; + ASSERT(reserved == 0); + ASSERT(linear_id != 0); + + if (index < m_table_size) { + // Set the entry. + ASSERT(m_objects[index] == nullptr); + + m_entry_infos[index].info = {.linear_id = static_cast<u16>(linear_id), .type = type}; + m_objects[index] = obj; + + obj->Open(); + } +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h new file mode 100644 index 000000000..ba9dd061d --- /dev/null +++ b/src/core/hle/kernel/k_handle_table.h @@ -0,0 +1,310 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> + +#include "common/assert.h" +#include "common/bit_field.h" +#include "common/bit_util.h" +#include "common/common_types.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_spin_lock.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_common.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KernelCore; + +class KHandleTable { + YUZU_NON_COPYABLE(KHandleTable); + YUZU_NON_MOVEABLE(KHandleTable); + +public: + static constexpr size_t MaxTableSize = 1024; + +public: + explicit KHandleTable(KernelCore& kernel_); + ~KHandleTable(); + + ResultCode Initialize(s32 size) { + R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); + + // Initialize all fields. + m_max_count = 0; + m_table_size = static_cast<u16>((size <= 0) ? MaxTableSize : size); + m_next_linear_id = MinLinearId; + m_count = 0; + m_free_head_index = -1; + + // Free all entries. + for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) { + m_objects[i] = nullptr; + m_entry_infos[i].next_free_index = i - 1; + m_free_head_index = i; + } + + return RESULT_SUCCESS; + } + + size_t GetTableSize() const { + return m_table_size; + } + size_t GetCount() const { + return m_count; + } + size_t GetMaxCount() const { + return m_max_count; + } + + ResultCode Finalize(); + bool Remove(Handle handle); + + template <typename T = KAutoObject> + KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { + // Lock and look up in table. + KScopedSpinLock lk(m_lock); + + if constexpr (std::is_same_v<T, KAutoObject>) { + return this->GetObjectImpl(handle); + } else { + if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) { + return obj->DynamicCast<T*>(); + } else { + return nullptr; + } + } + } + + template <typename T = KAutoObject> + KScopedAutoObject<T> GetObject(Handle handle) const { + // Handle pseudo-handles. + if constexpr (std::derived_from<KProcess, T>) { + if (handle == Svc::PseudoHandle::CurrentProcess) { + auto* const cur_process = kernel.CurrentProcess(); + ASSERT(cur_process != nullptr); + return cur_process; + } + } else if constexpr (std::derived_from<KThread, T>) { + if (handle == Svc::PseudoHandle::CurrentThread) { + auto* const cur_thread = GetCurrentThreadPointer(kernel); + ASSERT(cur_thread != nullptr); + return cur_thread; + } + } + + return this->template GetObjectWithoutPseudoHandle<T>(handle); + } + + ResultCode Reserve(Handle* out_handle); + void Unreserve(Handle handle); + + template <typename T> + ResultCode Add(Handle* out_handle, T* obj) { + static_assert(std::is_base_of_v<KAutoObject, T>); + return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken()); + } + + template <typename T> + void Register(Handle handle, T* obj) { + static_assert(std::is_base_of_v<KAutoObject, T>); + return this->Register(handle, obj, obj->GetTypeObj().GetClassToken()); + } + + template <typename T> + bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const { + // Try to convert and open all the handles. + size_t num_opened; + { + // Lock the table. + KScopedSpinLock lk(m_lock); + for (num_opened = 0; num_opened < num_handles; num_opened++) { + // Get the current handle. + const auto cur_handle = handles[num_opened]; + + // Get the object for the current handle. + KAutoObject* cur_object = this->GetObjectImpl(cur_handle); + if (cur_object == nullptr) { + break; + } + + // Cast the current object to the desired type. + T* cur_t = cur_object->DynamicCast<T*>(); + if (cur_t == nullptr) { + break; + } + + // Open a reference to the current object. + cur_t->Open(); + out[num_opened] = cur_t; + } + } + + // If we converted every object, succeed. + if (num_opened == num_handles) { + return true; + } + + // If we didn't convert entry object, close the ones we opened. + for (size_t i = 0; i < num_opened; i++) { + out[i]->Close(); + } + + return false; + } + +private: + ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); + void Register(Handle handle, KAutoObject* obj, u16 type); + + s32 AllocateEntry() { + ASSERT(m_count < m_table_size); + + const auto index = m_free_head_index; + + m_free_head_index = m_entry_infos[index].GetNextFreeIndex(); + + m_max_count = std::max(m_max_count, ++m_count); + + return index; + } + + void FreeEntry(s32 index) { + ASSERT(m_count > 0); + + m_objects[index] = nullptr; + m_entry_infos[index].next_free_index = m_free_head_index; + + m_free_head_index = index; + + --m_count; + } + + u16 AllocateLinearId() { + const u16 id = m_next_linear_id++; + if (m_next_linear_id > MaxLinearId) { + m_next_linear_id = MinLinearId; + } + return id; + } + + bool IsValidHandle(Handle handle) const { + // Unpack the handle. + const auto handle_pack = HandlePack(handle); + const auto raw_value = handle_pack.raw; + const auto index = handle_pack.index; + const auto linear_id = handle_pack.linear_id; + const auto reserved = handle_pack.reserved; + ASSERT(reserved == 0); + + // Validate our indexing information. + if (raw_value == 0) { + return false; + } + if (linear_id == 0) { + return false; + } + if (index >= m_table_size) { + return false; + } + + // Check that there's an object, and our serial id is correct. + if (m_objects[index] == nullptr) { + return false; + } + if (m_entry_infos[index].GetLinearId() != linear_id) { + return false; + } + + return true; + } + + KAutoObject* GetObjectImpl(Handle handle) const { + // Handles must not have reserved bits set. + const auto handle_pack = HandlePack(handle); + if (handle_pack.reserved != 0) { + return nullptr; + } + + if (this->IsValidHandle(handle)) { + return m_objects[handle_pack.index]; + } else { + return nullptr; + } + } + + KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const { + + // Index must be in bounds. + if (index >= m_table_size) { + return nullptr; + } + + // Ensure entry has an object. + if (KAutoObject* obj = m_objects[index]; obj != nullptr) { + *out_handle = EncodeHandle(static_cast<u16>(index), m_entry_infos[index].GetLinearId()); + return obj; + } else { + return nullptr; + } + } + +private: + union HandlePack { + HandlePack() = default; + HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {} + + u32 raw; + BitField<0, 15, u32> index; + BitField<15, 15, u32> linear_id; + BitField<30, 2, u32> reserved; + }; + + static constexpr u16 MinLinearId = 1; + static constexpr u16 MaxLinearId = 0x7FFF; + + static constexpr Handle EncodeHandle(u16 index, u16 linear_id) { + HandlePack handle{}; + handle.index.Assign(index); + handle.linear_id.Assign(linear_id); + handle.reserved.Assign(0); + return handle.raw; + } + + union EntryInfo { + struct { + u16 linear_id; + u16 type; + } info; + s32 next_free_index; + + constexpr u16 GetLinearId() const { + return info.linear_id; + } + constexpr u16 GetType() const { + return info.type; + } + constexpr s32 GetNextFreeIndex() const { + return next_free_index; + } + }; + +private: + std::array<EntryInfo, MaxTableSize> m_entry_infos{}; + std::array<KAutoObject*, MaxTableSize> m_objects{}; + s32 m_free_head_index{-1}; + u16 m_table_size{}; + u16 m_max_count{}; + u16 m_next_linear_id{MinLinearId}; + u16 m_count{}; + mutable KSpinLock m_lock; + KernelCore& kernel; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h new file mode 100644 index 000000000..540e518cd --- /dev/null +++ b/src/core/hle/kernel/k_linked_list.h @@ -0,0 +1,238 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <boost/intrusive/list.hpp> + +#include "common/assert.h" +#include "core/hle/kernel/slab_helpers.h" + +namespace Kernel { + +class KernelCore; + +class KLinkedListNode : public boost::intrusive::list_base_hook<>, + public KSlabAllocated<KLinkedListNode> { + +public: + KLinkedListNode() = default; + + void Initialize(void* it) { + m_item = it; + } + + void* GetItem() const { + return m_item; + } + +private: + void* m_item = nullptr; +}; + +template <typename T> +class KLinkedList : private boost::intrusive::list<KLinkedListNode> { +private: + using BaseList = boost::intrusive::list<KLinkedListNode>; + +public: + template <bool Const> + class Iterator; + + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = Iterator<false>; + using const_iterator = Iterator<true>; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + template <bool Const> + class Iterator { + private: + using BaseIterator = BaseList::iterator; + friend class KLinkedList; + + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename KLinkedList::value_type; + using difference_type = typename KLinkedList::difference_type; + using pointer = std::conditional_t<Const, KLinkedList::const_pointer, KLinkedList::pointer>; + using reference = + std::conditional_t<Const, KLinkedList::const_reference, KLinkedList::reference>; + + public: + explicit Iterator(BaseIterator it) : m_base_it(it) {} + + pointer GetItem() const { + return static_cast<pointer>(m_base_it->GetItem()); + } + + bool operator==(const Iterator& rhs) const { + return m_base_it == rhs.m_base_it; + } + + bool operator!=(const Iterator& rhs) const { + return !(*this == rhs); + } + + pointer operator->() const { + return this->GetItem(); + } + + reference operator*() const { + return *this->GetItem(); + } + + Iterator& operator++() { + ++m_base_it; + return *this; + } + + Iterator& operator--() { + --m_base_it; + return *this; + } + + Iterator operator++(int) { + const Iterator it{*this}; + ++(*this); + return it; + } + + Iterator operator--(int) { + const Iterator it{*this}; + --(*this); + return it; + } + + operator Iterator<true>() const { + return Iterator<true>(m_base_it); + } + + private: + BaseIterator m_base_it; + }; + +public: + constexpr KLinkedList(KernelCore& kernel_) : BaseList(), kernel{kernel_} {} + + ~KLinkedList() { + // Erase all elements. + for (auto it = begin(); it != end(); it = erase(it)) { + } + + // Ensure we succeeded. + ASSERT(this->empty()); + } + + // Iterator accessors. + iterator begin() { + return iterator(BaseList::begin()); + } + + const_iterator begin() const { + return const_iterator(BaseList::begin()); + } + + iterator end() { + return iterator(BaseList::end()); + } + + const_iterator end() const { + return const_iterator(BaseList::end()); + } + + const_iterator cbegin() const { + return this->begin(); + } + + const_iterator cend() const { + return this->end(); + } + + reverse_iterator rbegin() { + return reverse_iterator(this->end()); + } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(this->end()); + } + + reverse_iterator rend() { + return reverse_iterator(this->begin()); + } + + const_reverse_iterator rend() const { + return const_reverse_iterator(this->begin()); + } + + const_reverse_iterator crbegin() const { + return this->rbegin(); + } + + const_reverse_iterator crend() const { + return this->rend(); + } + + // Content management. + using BaseList::empty; + using BaseList::size; + + reference back() { + return *(--this->end()); + } + + const_reference back() const { + return *(--this->end()); + } + + reference front() { + return *this->begin(); + } + + const_reference front() const { + return *this->begin(); + } + + iterator insert(const_iterator pos, reference ref) { + KLinkedListNode* node = KLinkedListNode::Allocate(kernel); + ASSERT(node != nullptr); + node->Initialize(std::addressof(ref)); + return iterator(BaseList::insert(pos.m_base_it, *node)); + } + + void push_back(reference ref) { + this->insert(this->end(), ref); + } + + void push_front(reference ref) { + this->insert(this->begin(), ref); + } + + void pop_back() { + this->erase(--this->end()); + } + + void pop_front() { + this->erase(this->begin()); + } + + iterator erase(const iterator pos) { + KLinkedListNode* freed_node = std::addressof(*pos.m_base_it); + iterator ret = iterator(BaseList::erase(pos.m_base_it)); + KLinkedListNode::Free(kernel, freed_node); + + return ret; + } + +private: + KernelCore& kernel; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index c5b9c5e85..a7fdb5fb8 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -134,6 +134,10 @@ enum class KMemoryPermission : u8 { }; DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); +constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) { + return static_cast<KMemoryPermission>(perm); +} + enum class KMemoryAttribute : u8 { None = 0x00, Mask = 0x7F, diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp index 4a2d88008..44bfeb0d5 100644 --- a/src/core/hle/kernel/k_memory_block_manager.cpp +++ b/src/core/hle/kernel/k_memory_block_manager.cpp @@ -17,8 +17,8 @@ KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr) KMemoryBlockManager::iterator KMemoryBlockManager::FindIterator(VAddr addr) { auto node{memory_block_tree.begin()}; while (node != end()) { - const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()}; - if (node->GetAddress() <= addr && end_addr - 1 >= addr) { + const VAddr node_end_addr{node->GetNumPages() * PageSize + node->GetAddress()}; + if (node->GetAddress() <= addr && node_end_addr - 1 >= addr) { return node; } node = std::next(node); @@ -67,7 +67,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState KMemoryPermission prev_perm, KMemoryAttribute prev_attribute, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attribute) { - const VAddr end_addr{addr + num_pages * PageSize}; + const VAddr update_end_addr{addr + num_pages * PageSize}; iterator node{memory_block_tree.begin()}; prev_attribute |= KMemoryAttribute::IpcAndDeviceMapped; @@ -78,7 +78,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState const VAddr cur_addr{block->GetAddress()}; const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - if (addr < cur_end_addr && cur_addr < end_addr) { + if (addr < cur_end_addr && cur_addr < update_end_addr) { if (!block->HasProperties(prev_state, prev_perm, prev_attribute)) { node = next_node; continue; @@ -89,8 +89,8 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState memory_block_tree.insert(node, block->Split(addr)); } - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); + if (update_end_addr < cur_end_addr) { + new_node = memory_block_tree.insert(node, block->Split(update_end_addr)); } new_node->Update(state, perm, attribute); @@ -98,7 +98,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState MergeAdjacent(new_node, next_node); } - if (cur_end_addr - 1 >= end_addr - 1) { + if (cur_end_addr - 1 >= update_end_addr - 1) { break; } @@ -108,7 +108,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attribute) { - const VAddr end_addr{addr + num_pages * PageSize}; + const VAddr update_end_addr{addr + num_pages * PageSize}; iterator node{memory_block_tree.begin()}; while (node != memory_block_tree.end()) { @@ -117,15 +117,15 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState const VAddr cur_addr{block->GetAddress()}; const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - if (addr < cur_end_addr && cur_addr < end_addr) { + if (addr < cur_end_addr && cur_addr < update_end_addr) { iterator new_node{node}; if (addr > cur_addr) { memory_block_tree.insert(node, block->Split(addr)); } - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); + if (update_end_addr < cur_end_addr) { + new_node = memory_block_tree.insert(node, block->Split(update_end_addr)); } new_node->Update(state, perm, attribute); @@ -133,7 +133,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState MergeAdjacent(new_node, next_node); } - if (cur_end_addr - 1 >= end_addr - 1) { + if (cur_end_addr - 1 >= update_end_addr - 1) { break; } @@ -143,7 +143,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, KMemoryPermission perm) { - const VAddr end_addr{addr + num_pages * PageSize}; + const VAddr update_end_addr{addr + num_pages * PageSize}; iterator node{memory_block_tree.begin()}; while (node != memory_block_tree.end()) { @@ -152,15 +152,15 @@ void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc const VAddr cur_addr{block->GetAddress()}; const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - if (addr < cur_end_addr && cur_addr < end_addr) { + if (addr < cur_end_addr && cur_addr < update_end_addr) { iterator new_node{node}; if (addr > cur_addr) { memory_block_tree.insert(node, block->Split(addr)); } - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); + if (update_end_addr < cur_end_addr) { + new_node = memory_block_tree.insert(node, block->Split(update_end_addr)); } lock_func(new_node, perm); @@ -168,7 +168,7 @@ void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc MergeAdjacent(new_node, next_node); } - if (cur_end_addr - 1 >= end_addr - 1) { + if (cur_end_addr - 1 >= update_end_addr - 1) { break; } diff --git a/src/core/hle/kernel/k_memory_region.h b/src/core/hle/kernel/k_memory_region.h index a861c04ab..90ab8fd62 100644 --- a/src/core/hle/kernel/k_memory_region.h +++ b/src/core/hle/kernel/k_memory_region.h @@ -82,9 +82,9 @@ public: type_id = type; } - constexpr bool Contains(u64 address) const { + constexpr bool Contains(u64 addr) const { ASSERT(this->GetEndAddress() != 0); - return this->GetAddress() <= address && address <= this->GetLastAddress(); + return this->GetAddress() <= addr && addr <= this->GetLastAddress(); } constexpr bool IsDerivedFrom(u32 type) const { diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index d09d5ce48..d4ce98ee3 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -11,11 +11,11 @@ #include "core/hle/kernel/k_memory_block_manager.h" #include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/memory.h" @@ -420,7 +420,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { remaining_size); if (!memory_reservation.Succeeded()) { LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } KPageLinkedList page_linked_list; @@ -578,7 +578,7 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { AddRegionToPages(dst_addr, num_pages, dst_pages); if (!dst_pages.IsEqual(src_pages)) { - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } { @@ -641,6 +641,45 @@ ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, K return RESULT_SUCCESS; } +ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) { + VAddr cur_addr{addr}; + + for (const auto& node : page_linked_list.Nodes()) { + const std::size_t num_pages{(addr - cur_addr) / PageSize}; + if (const auto result{ + Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)}; + result.IsError()) { + return result; + } + + cur_addr += node.GetNumPages() * PageSize; + } + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, + KMemoryState state) { + std::lock_guard lock{page_table_lock}; + + const std::size_t num_pages{page_linked_list.GetNumPages()}; + const std::size_t size{num_pages * PageSize}; + + if (!CanContain(addr, size, state)) { + return ResultInvalidCurrentMemory; + } + + if (IsRegionMapped(addr, num_pages * PageSize)) { + return ResultInvalidCurrentMemory; + } + + CASCADE_CODE(UnmapPages(addr, page_linked_list)); + + block_manager->Update(addr, num_pages, state, KMemoryPermission::None); + + return RESULT_SUCCESS; +} + ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm) { @@ -790,7 +829,7 @@ ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) { if (!memory_reservation.Succeeded()) { LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } KPageLinkedList page_linked_list; @@ -1067,7 +1106,7 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const { } } -constexpr bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { +bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { const VAddr end{addr + size}; const VAddr last{end - 1}; const VAddr region_start{GetRegionAddress(state)}; diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 49b824379..8c2cc03eb 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -40,6 +40,7 @@ public: ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, KMemoryPermission perm); + ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); KMemoryInfo QueryInfo(VAddr addr); ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); @@ -63,6 +64,8 @@ public: return page_table_impl; } + bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; + private: enum class OperationType : u32 { Map, @@ -79,6 +82,7 @@ private: ResultCode InitializeMemoryLayout(VAddr start, VAddr end); ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, KMemoryPermission perm); + ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list); void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); bool IsRegionMapped(VAddr address, u64 size); bool IsRegionContiguous(VAddr addr, u64 size) const; @@ -92,7 +96,6 @@ private: OperationType operation, PAddr map_addr = 0); constexpr VAddr GetRegionAddress(KMemoryState state) const; constexpr std::size_t GetRegionSize(KMemoryState state) const; - constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, KMemoryState state, KMemoryPermission perm_mask, @@ -216,8 +219,6 @@ public: constexpr PAddr GetPhysicalAddr(VAddr addr) { return page_table_impl.backing_addr[addr >> PageBits] + addr; } - -private: constexpr bool Contains(VAddr addr) const { return address_space_start <= addr && addr <= address_space_end - 1; } @@ -225,6 +226,8 @@ private: return address_space_start <= addr && addr < addr + size && addr + size - 1 <= address_space_end - 1; } + +private: constexpr bool IsKernel() const { return is_kernel; } diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp new file mode 100644 index 000000000..feb2bb11f --- /dev/null +++ b/src/core/hle/kernel/k_port.cpp @@ -0,0 +1,68 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KPort::KPort(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {} + +KPort::~KPort() = default; + +void KPort::Initialize(s32 max_sessions_, bool is_light_, const std::string& name_) { + // Open a new reference count to the initialized port. + Open(); + + // Create and initialize our server/client pair. + KAutoObject::Create(std::addressof(server)); + KAutoObject::Create(std::addressof(client)); + server.Initialize(this, name_ + ":Server"); + client.Initialize(this, max_sessions_, name_ + ":Client"); + + // Set our member variables. + is_light = is_light_; + name = name_; + state = State::Normal; +} + +void KPort::OnClientClosed() { + KScopedSchedulerLock sl{kernel}; + + if (state == State::Normal) { + state = State::ClientClosed; + } +} + +void KPort::OnServerClosed() { + KScopedSchedulerLock sl{kernel}; + + if (state == State::Normal) { + state = State::ServerClosed; + } +} + +bool KPort::IsServerClosed() const { + KScopedSchedulerLock sl{kernel}; + return state == State::ServerClosed; +} + +ResultCode KPort::EnqueueSession(KServerSession* session) { + KScopedSchedulerLock sl{kernel}; + + R_UNLESS(state == State::Normal, ResultPortClosed); + + if (server.HasHLEHandler()) { + server.GetHLEHandler()->ClientConnected(session); + } else { + server.EnqueueSession(session); + } + + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h new file mode 100644 index 000000000..960f1f3a3 --- /dev/null +++ b/src/core/hle/kernel/k_port.h @@ -0,0 +1,69 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> + +#include "common/common_types.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KServerSession; + +class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KPort, KAutoObject); + +public: + explicit KPort(KernelCore& kernel_); + virtual ~KPort(); + + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + void Initialize(s32 max_sessions_, bool is_light_, const std::string& name_); + void OnClientClosed(); + void OnServerClosed(); + + bool IsLight() const { + return is_light; + } + + bool IsServerClosed() const; + + ResultCode EnqueueSession(KServerSession* session); + + KClientPort& GetClientPort() { + return client; + } + KServerPort& GetServerPort() { + return server; + } + const KClientPort& GetClientPort() const { + return client; + } + const KServerPort& GetServerPort() const { + return server; + } + +private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + +private: + KServerPort server; + KClientPort client; + State state{State::Invalid}; + bool is_light{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/k_process.cpp index e35deb8e2..bdcbaeeaa 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -17,13 +17,14 @@ #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_memory_block_manager.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/lock.h" #include "core/memory.h" @@ -37,17 +38,20 @@ namespace { * @param owner_process The parent process for the main thread * @param priority The priority to give the main thread */ -void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { +void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) { const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); - auto thread_res = - KThread::CreateUserThread(system, ThreadType::User, "main", entry_point, priority, 0, - owner_process.GetIdealCoreId(), stack_top, &owner_process); - std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap(); + KThread* thread = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, + owner_process.GetIdealCoreId(), &owner_process) + .IsSuccess()); // Register 1 must be a handle to the main thread - const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); + Handle thread_handle{}; + owner_process.GetHandleTable().Add(&thread_handle, thread); + + thread->SetName("main"); thread->GetContext32().cpu_registers[0] = 0; thread->GetContext64().cpu_registers[0] = 0; thread->GetContext32().cpu_registers[1] = thread_handle; @@ -114,11 +118,11 @@ private: std::bitset<num_slot_entries> is_slot_used; }; -std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) { +ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name, + ProcessType type) { auto& kernel = system.Kernel(); - std::shared_ptr<Process> process = std::make_shared<Process>(system); - process->name = std::move(name); + process->name = std::move(process_name); process->resource_limit = kernel.GetSystemResourceLimit(); process->status = ProcessStatus::Created; @@ -126,6 +130,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() : kernel.CreateNewUserProcessID(); process->capabilities.InitializeForMetadatalessProcess(); + process->is_initialized = true; std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))); std::uniform_int_distribution<u64> distribution; @@ -133,14 +138,18 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, [&] { return distribution(rng); }); kernel.AppendNewProcess(process); - return process; + + // Open a reference to the resource limit. + process->resource_limit->Open(); + + return RESULT_SUCCESS; } -std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const { +KResourceLimit* KProcess::GetResourceLimit() const { return resource_limit; } -void Process::IncrementThreadCount() { +void KProcess::IncrementThreadCount() { ASSERT(num_threads >= 0); num_created_threads++; @@ -149,7 +158,7 @@ void Process::IncrementThreadCount() { } } -void Process::DecrementThreadCount() { +void KProcess::DecrementThreadCount() { ASSERT(num_threads > 0); if (const auto count = --num_threads; count == 0) { @@ -157,31 +166,34 @@ void Process::DecrementThreadCount() { } } -u64 Process::GetTotalPhysicalMemoryAvailable() const { +u64 KProcess::GetTotalPhysicalMemoryAvailable() const { const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + main_thread_stack_size}; - ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application)); + if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); + capacity != pool_size) { + LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size); + } if (capacity < memory_usage_capacity) { return capacity; } return memory_usage_capacity; } -u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { +u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize(); } -u64 Process::GetTotalPhysicalMemoryUsed() const { +u64 KProcess::GetTotalPhysicalMemoryUsed() const { return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() + GetSystemResourceSize(); } -u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { +u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); } -bool Process::ReleaseUserException(KThread* thread) { +bool KProcess::ReleaseUserException(KThread* thread) { KScopedSchedulerLock sl{kernel}; if (exception_thread == thread) { @@ -206,7 +218,7 @@ bool Process::ReleaseUserException(KThread* thread) { } } -void Process::PinCurrentThread() { +void KProcess::PinCurrentThread() { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Get the current thread. @@ -221,7 +233,7 @@ void Process::PinCurrentThread() { KScheduler::SetSchedulerUpdateNeeded(kernel); } -void Process::UnpinCurrentThread() { +void KProcess::UnpinCurrentThread() { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Get the current thread. @@ -236,15 +248,39 @@ void Process::UnpinCurrentThread() { KScheduler::SetSchedulerUpdateNeeded(kernel); } -void Process::RegisterThread(const KThread* thread) { +ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, + [[maybe_unused]] size_t size) { + // Lock ourselves, to prevent concurrent access. + KScopedLightLock lk(state_lock); + + // TODO(bunnei): Manage KSharedMemoryInfo list here. + + // Open a reference to the shared memory. + shmem->Open(); + + return RESULT_SUCCESS; +} + +void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, + [[maybe_unused]] size_t size) { + // Lock ourselves, to prevent concurrent access. + KScopedLightLock lk(state_lock); + + // TODO(bunnei): Manage KSharedMemoryInfo list here. + + // Close a reference to the shared memory. + shmem->Close(); +} + +void KProcess::RegisterThread(const KThread* thread) { thread_list.push_back(thread); } -void Process::UnregisterThread(const KThread* thread) { +void KProcess::UnregisterThread(const KThread* thread) { thread_list.remove(thread); } -ResultCode Process::Reset() { +ResultCode KProcess::Reset() { // Lock the process and the scheduler. KScopedLightLock lk(state_lock); KScopedSchedulerLock sl{kernel}; @@ -258,8 +294,8 @@ ResultCode Process::Reset() { return RESULT_SUCCESS; } -ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, - std::size_t code_size) { +ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, + std::size_t code_size) { program_id = metadata.GetTitleID(); ideal_core = metadata.GetMainThreadCore(); is_64bit_process = metadata.Is64BitProgram(); @@ -271,7 +307,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, if (!memory_reservation.Succeeded()) { LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", code_size + system_resource_size); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } // Initialize proces address space if (const ResultCode result{ @@ -318,10 +354,10 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, tls_region_address = CreateTLSRegion(); memory_reservation.Commit(); - return handle_table.SetSize(capabilities.GetHandleTableSize()); + return handle_table.Initialize(capabilities.GetHandleTableSize()); } -void Process::Run(s32 main_thread_priority, u64 stack_size) { +void KProcess::Run(s32 main_thread_priority, u64 stack_size) { AllocateMainThreadStack(stack_size); resource_limit->Reserve(LimitableResource::Threads, 1); resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); @@ -331,18 +367,18 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { ChangeStatus(ProcessStatus::Running); - SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); + SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top); } -void Process::PrepareForTermination() { +void KProcess::PrepareForTermination() { ChangeStatus(ProcessStatus::Exiting); - const auto stop_threads = [this](const std::vector<std::shared_ptr<KThread>>& thread_list) { - for (auto& thread : thread_list) { + const auto stop_threads = [this](const std::vector<KThread*>& in_thread_list) { + for (auto& thread : in_thread_list) { if (thread->GetOwnerProcess() != this) continue; - if (thread.get() == kernel.CurrentScheduler()->GetCurrentThread()) + if (thread == kernel.CurrentScheduler()->GetCurrentThread()) continue; // TODO(Subv): When are the other running/ready threads terminated? @@ -353,7 +389,7 @@ void Process::PrepareForTermination() { } }; - stop_threads(system.GlobalSchedulerContext().GetThreadList()); + stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList()); FreeTLSRegion(tls_region_address); tls_region_address = 0; @@ -366,6 +402,16 @@ void Process::PrepareForTermination() { ChangeStatus(ProcessStatus::Exited); } +void KProcess::Finalize() { + // Release memory to the resource limit. + if (resource_limit != nullptr) { + resource_limit->Close(); + } + + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); +} + /** * Attempts to find a TLS page that contains a free slot for * use by a thread. @@ -379,8 +425,8 @@ static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) { [](const auto& page) { return page.HasAvailableSlots(); }); } -VAddr Process::CreateTLSRegion() { - KScopedSchedulerLock lock(system.Kernel()); +VAddr KProcess::CreateTLSRegion() { + KScopedSchedulerLock lock(kernel); if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; tls_page_iter != tls_pages.cend()) { return *tls_page_iter->ReserveSlot(); @@ -391,7 +437,7 @@ VAddr Process::CreateTLSRegion() { const VAddr start{page_table->GetKernelMapRegionStart()}; const VAddr size{page_table->GetKernelMapRegionEnd() - start}; - const PAddr tls_map_addr{system.DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; + const PAddr tls_map_addr{kernel.System().DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; const VAddr tls_page_addr{page_table ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, KMemoryState::ThreadLocal, @@ -410,8 +456,8 @@ VAddr Process::CreateTLSRegion() { return *reserve_result; } -void Process::FreeTLSRegion(VAddr tls_address) { - KScopedSchedulerLock lock(system.Kernel()); +void KProcess::FreeTLSRegion(VAddr tls_address) { + KScopedSchedulerLock lock(kernel); const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); auto iter = std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { @@ -425,33 +471,34 @@ void Process::FreeTLSRegion(VAddr tls_address) { iter->ReleaseSlot(tls_address); } -void Process::LoadModule(CodeSet code_set, VAddr base_addr) { +void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { std::lock_guard lock{HLE::g_hle_lock}; const auto ReprotectSegment = [&](const CodeSet::Segment& segment, KMemoryPermission permission) { page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); }; - system.Memory().WriteBlock(*this, base_addr, code_set.memory.data(), code_set.memory.size()); + kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), + code_set.memory.size()); ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite); } -bool Process::IsSignaled() const { +bool KProcess::IsSignaled() const { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); return is_signaled; } -Process::Process(Core::System& system) - : KSynchronizationObject{system.Kernel()}, page_table{std::make_unique<KPageTable>(system)}, - handle_table{system.Kernel()}, address_arbiter{system}, condition_var{system}, - state_lock{system.Kernel()}, system{system} {} +KProcess::KProcess(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_}, + page_table{std::make_unique<KPageTable>(kernel_.System())}, handle_table{kernel_}, + address_arbiter{kernel_.System()}, condition_var{kernel_.System()}, state_lock{kernel_} {} -Process::~Process() = default; +KProcess::~KProcess() = default; -void Process::ChangeStatus(ProcessStatus new_status) { +void KProcess::ChangeStatus(ProcessStatus new_status) { if (status == new_status) { return; } @@ -461,7 +508,7 @@ void Process::ChangeStatus(ProcessStatus new_status) { NotifyAvailable(); } -ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) { +ResultCode KProcess::AllocateMainThreadStack(std::size_t stack_size) { ASSERT(stack_size); // The kernel always ensures that the given stack size is page aligned. diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/k_process.h index 45eefb90e..123d71cd3 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/k_process.h @@ -11,11 +11,13 @@ #include <unordered_map> #include <vector> #include "common/common_types.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/process_capability.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Core { @@ -60,10 +62,13 @@ enum class ProcessStatus { DebugBreak, }; -class Process final : public KSynchronizationObject { +class KProcess final + : public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject> { + KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); + public: - explicit Process(Core::System& system); - ~Process() override; + explicit KProcess(KernelCore& kernel_); + ~KProcess() override; enum : u64 { /// Lowest allowed process ID for a kernel initial process. @@ -85,20 +90,8 @@ public: static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; - static std::shared_ptr<Process> Create(Core::System& system, std::string name, - ProcessType type); - - std::string GetTypeName() const override { - return "Process"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Process; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } + static ResultCode Initialize(KProcess* process, Core::System& system, std::string process_name, + ProcessType type); /// Gets a reference to the process' page table. KPageTable& PageTable() { @@ -111,12 +104,12 @@ public: } /// Gets a reference to the process' handle table. - HandleTable& GetHandleTable() { + KHandleTable& GetHandleTable() { return handle_table; } /// Gets a const reference to the process' handle table. - const HandleTable& GetHandleTable() const { + const KHandleTable& GetHandleTable() const { return handle_table; } @@ -167,7 +160,7 @@ public: } /// Gets the resource limit descriptor for this process - std::shared_ptr<KResourceLimit> GetResourceLimit() const; + KResourceLimit* GetResourceLimit() const; /// Gets the ideal CPU core ID for this process u8 GetIdealCoreId() const { @@ -338,9 +331,19 @@ public: void LoadModule(CodeSet code_set, VAddr base_addr); - bool IsSignaled() const override; + virtual bool IsInitialized() const override { + return is_initialized; + } + + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + virtual void Finalize(); + + virtual u64 GetId() const override final { + return GetProcessID(); + } - void Finalize() override {} + virtual bool IsSignaled() const override; void PinCurrentThread(); void UnpinCurrentThread(); @@ -349,6 +352,9 @@ public: return state_lock; } + ResultCode AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size); + void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size); + /////////////////////////////////////////////////////////////////////////////////////////////// // Thread-local storage management @@ -399,7 +405,7 @@ private: u32 system_resource_size = 0; /// Resource limit descriptor for this process - std::shared_ptr<KResourceLimit> resource_limit; + KResourceLimit* resource_limit{}; /// The ideal CPU core for this process, threads are scheduled on this core by default. u8 ideal_core = 0; @@ -423,7 +429,7 @@ private: u64 total_process_running_time_ticks = 0; /// Per-process handle table for storing created object handles in. - HandleTable handle_table; + KHandleTable handle_table; /// Per-process address arbiter. KAddressArbiter address_arbiter; @@ -454,14 +460,12 @@ private: /// Process total image size std::size_t image_size{}; - /// Name of this process - std::string name; - /// Schedule count of this process s64 schedule_count{}; bool is_signaled{}; bool is_suspended{}; + bool is_initialized{}; std::atomic<s32> num_created_threads{}; std::atomic<u16> num_threads{}; @@ -474,9 +478,6 @@ private: KThread* exception_thread{}; KLightLock state_lock; - - /// System context - Core::System& system; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_readable_event.cpp b/src/core/hle/kernel/k_readable_event.cpp index 4b4d34857..0ea2d0275 100644 --- a/src/core/hle/kernel/k_readable_event.cpp +++ b/src/core/hle/kernel/k_readable_event.cpp @@ -2,21 +2,18 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <algorithm> #include "common/assert.h" -#include "common/common_funcs.h" -#include "common/logging/log.h" +#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { -KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name) - : KSynchronizationObject{kernel, std::move(name)} {} +KReadableEvent::KReadableEvent(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} + KReadableEvent::~KReadableEvent() = default; bool KReadableEvent::IsSignaled() const { @@ -25,6 +22,12 @@ bool KReadableEvent::IsSignaled() const { return is_signaled; } +void KReadableEvent::Destroy() { + if (parent) { + parent->Close(); + } +} + ResultCode KReadableEvent::Signal() { KScopedSchedulerLock lk{kernel}; diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h index e6f0fd900..33cd1dd3e 100644 --- a/src/core/hle/kernel/k_readable_event.h +++ b/src/core/hle/kernel/k_readable_event.h @@ -4,8 +4,9 @@ #pragma once +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Kernel { @@ -13,31 +14,25 @@ namespace Kernel { class KernelCore; class KEvent; -class KReadableEvent final : public KSynchronizationObject { +class KReadableEvent : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KReadableEvent, KSynchronizationObject); + public: - explicit KReadableEvent(KernelCore& kernel, std::string&& name); + explicit KReadableEvent(KernelCore& kernel_); ~KReadableEvent() override; - std::string GetTypeName() const override { - return "KReadableEvent"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; - HandleType GetHandleType() const override { - return HANDLE_TYPE; + void Initialize(KEvent* parent_, std::string&& name_) { + is_signaled = false; + parent = parent_; + name = std::move(name_); } KEvent* GetParent() const { return parent; } - void Initialize(KEvent* parent_) { - is_signaled = false; - parent = parent_; - } - - bool IsSignaled() const override; - void Finalize() override {} + virtual bool IsSignaled() const override; + virtual void Destroy() override; ResultCode Signal(); ResultCode Clear(); diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index d05b34ea3..bf20bf7d0 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -10,10 +10,16 @@ namespace Kernel { constexpr s64 DefaultTimeout = 10000000000; // 10 seconds -KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_) - : Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {} +KResourceLimit::KResourceLimit(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_}, lock{kernel_}, cond_var{kernel_} {} KResourceLimit::~KResourceLimit() = default; +void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) { + core_timing = core_timing_; +} + +void KResourceLimit::Finalize() {} + s64 KResourceLimit::GetLimitValue(LimitableResource which) const { const auto index = static_cast<std::size_t>(which); s64 value{}; @@ -78,7 +84,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { } bool KResourceLimit::Reserve(LimitableResource which, s64 value) { - return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout); + return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout); } bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { @@ -109,7 +115,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { } if (current_hints[index] + value <= limit_values[index] && - (timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) { + (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) { waiter_count++; cond_var.Wait(&lock, timeout); waiter_count--; diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h index 4542317d0..0debbbb51 100644 --- a/src/core/hle/kernel/k_resource_limit.h +++ b/src/core/hle/kernel/k_resource_limit.h @@ -8,7 +8,6 @@ #include "common/common_types.h" #include "core/hle/kernel/k_light_condition_variable.h" #include "core/hle/kernel/k_light_lock.h" -#include "core/hle/kernel/object.h" union ResultCode; @@ -32,10 +31,16 @@ constexpr bool IsValidResourceType(LimitableResource type) { return type < LimitableResource::Count; } -class KResourceLimit final : public Object { +class KResourceLimit final + : public KAutoObjectWithSlabHeapAndContainer<KResourceLimit, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject); + public: - explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_); - ~KResourceLimit(); + explicit KResourceLimit(KernelCore& kernel_); + virtual ~KResourceLimit(); + + void Initialize(const Core::Timing::CoreTiming* core_timing_); + virtual void Finalize() override; s64 GetLimitValue(LimitableResource which) const; s64 GetCurrentValue(LimitableResource which) const; @@ -49,19 +54,7 @@ public: void Release(LimitableResource which, s64 value); void Release(LimitableResource which, s64 value, s64 hint); - std::string GetTypeName() const override { - return "KResourceLimit"; - } - std::string GetName() const override { - return GetTypeName(); - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - virtual void Finalize() override {} + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} private: using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>; @@ -72,6 +65,6 @@ private: mutable KLightLock lock; s32 waiter_count{}; KLightConditionVariable cond_var; - const Core::Timing::CoreTiming& core_timing; + const Core::Timing::CoreTiming* core_timing{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index d1df97305..e256e9415 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -15,12 +15,12 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/cpu_manager.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -71,7 +71,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { } if (state.should_count_idle) { if (highest_thread != nullptr) { - if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { + if (KProcess* process = highest_thread->GetOwnerProcess(); process != nullptr) { process->SetRunningThread(core_id, highest_thread, state.idle_count); } } else { @@ -104,7 +104,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { if (top_thread != nullptr) { // If the thread has no waiters, we need to check if the process has a thread pinned. if (top_thread->GetNumKernelWaiters() == 0) { - if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) { + if (KProcess* parent = top_thread->GetOwnerProcess(); parent != nullptr) { if (KThread* pinned = parent->GetPinnedThread(static_cast<s32>(core_id)); pinned != nullptr && pinned != top_thread) { // We prefer our parent's pinned thread if possible. However, we also don't @@ -259,7 +259,7 @@ void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread } } -void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { +void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) { ASSERT(system.GlobalSchedulerContext().IsLocked()); // Get a reference to the priority queue. @@ -267,7 +267,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { auto& priority_queue = GetPriorityQueue(kernel); // Rotate the front of the queue to the end. - KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority); + KThread* top_thread = priority_queue.GetScheduledFront(cpu_core_id, priority); KThread* next_thread = nullptr; if (top_thread != nullptr) { next_thread = priority_queue.MoveToScheduledBack(top_thread); @@ -279,7 +279,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { // While we have a suggested thread, try to migrate it! { - KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority); + KThread* suggested = priority_queue.GetSuggestedFront(cpu_core_id, priority); while (suggested != nullptr) { // Check if the suggested thread is the top thread on its core. const s32 suggested_core = suggested->GetActiveCore(); @@ -300,7 +300,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { // to the front of the queue. if (top_on_suggested_core == nullptr || top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { - suggested->SetActiveCore(core_id); + suggested->SetActiveCore(cpu_core_id); priority_queue.ChangeCore(suggested_core, suggested, true); IncrementScheduledCount(suggested); break; @@ -308,22 +308,22 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { } // Get the next suggestion. - suggested = priority_queue.GetSamePriorityNext(core_id, suggested); + suggested = priority_queue.GetSamePriorityNext(cpu_core_id, suggested); } } // Now that we might have migrated a thread with the same priority, check if we can do better. { - KThread* best_thread = priority_queue.GetScheduledFront(core_id); + KThread* best_thread = priority_queue.GetScheduledFront(cpu_core_id); if (best_thread == GetCurrentThread()) { - best_thread = priority_queue.GetScheduledNext(core_id, best_thread); + best_thread = priority_queue.GetScheduledNext(cpu_core_id, best_thread); } // If the best thread we can choose has a priority the same or worse than ours, try to // migrate a higher priority thread. if (best_thread != nullptr && best_thread->GetPriority() >= priority) { - KThread* suggested = priority_queue.GetSuggestedFront(core_id); + KThread* suggested = priority_queue.GetSuggestedFront(cpu_core_id); while (suggested != nullptr) { // If the suggestion's priority is the same as ours, don't bother. if (suggested->GetPriority() >= best_thread->GetPriority()) { @@ -342,7 +342,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { if (top_on_suggested_core == nullptr || top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { - suggested->SetActiveCore(core_id); + suggested->SetActiveCore(cpu_core_id); priority_queue.ChangeCore(suggested_core, suggested, true); IncrementScheduledCount(suggested); break; @@ -350,7 +350,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { } // Get the next suggestion. - suggested = priority_queue.GetSuggestedNext(core_id, suggested); + suggested = priority_queue.GetSuggestedNext(cpu_core_id, suggested); } } } @@ -411,7 +411,7 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { // Get the current thread and process. KThread& cur_thread = Kernel::GetCurrentThread(kernel); - Process& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -450,7 +450,7 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { // Get the current thread and process. KThread& cur_thread = Kernel::GetCurrentThread(kernel); - Process& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -538,7 +538,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) { // Get the current thread and process. KThread& cur_thread = Kernel::GetCurrentThread(kernel); - Process& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -617,7 +617,12 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core state.highest_priority_thread = nullptr; } -KScheduler::~KScheduler() = default; +KScheduler::~KScheduler() { + if (idle_thread) { + idle_thread->Close(); + idle_thread = nullptr; + } +} KThread* KScheduler::GetCurrentThread() const { if (auto result = current_thread.load(); result) { @@ -719,7 +724,7 @@ void KScheduler::ScheduleImpl() { current_thread.store(next_thread); - Process* const previous_process = system.Kernel().CurrentProcess(); + KProcess* const previous_process = system.Kernel().CurrentProcess(); UpdateLastContextSwitchTime(previous_thread, previous_process); @@ -775,7 +780,7 @@ void KScheduler::SwitchToCurrent() { } } -void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) { +void KScheduler::UpdateLastContextSwitchTime(KThread* thread, KProcess* process) { const u64 prev_switch_ticks = last_context_switch_time; const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; @@ -792,13 +797,9 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) } void KScheduler::Initialize() { - std::string name = "Idle Thread Id:" + std::to_string(core_id); - std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::CreateThread( - system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, - static_cast<u32>(core_id), 0, nullptr, std::move(init_func), init_func_parameter); - idle_thread = thread_res.Unwrap().get(); + idle_thread = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeIdleThread(system, idle_thread, core_id).IsSuccess()); + idle_thread->SetName(fmt::format("IdleThread:{}", core_id)); } KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 8e32865aa..13a2414e6 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -24,7 +24,7 @@ class System; namespace Kernel { class KernelCore; -class Process; +class KProcess; class SchedulerLock; class KThread; @@ -141,7 +141,7 @@ private: [[nodiscard]] static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel); - void RotateScheduledQueue(s32 core_id, s32 priority); + void RotateScheduledQueue(s32 cpu_core_id, s32 priority); void Schedule() { ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1); @@ -165,7 +165,7 @@ private: * most recent tick count retrieved. No special arithmetic is * applied to it. */ - void UpdateLastContextSwitchTime(KThread* thread, Process* process); + void UpdateLastContextSwitchTime(KThread* thread, KProcess* process); static void OnSwitch(void* this_scheduler); void SwitchToCurrent(); @@ -173,12 +173,12 @@ private: KThread* prev_thread{}; std::atomic<KThread*> current_thread{}; - KThread* idle_thread; + KThread* idle_thread{}; std::shared_ptr<Common::Fiber> switch_fiber{}; struct SchedulingState { - std::atomic<bool> needs_scheduling; + std::atomic<bool> needs_scheduling{}; bool interrupt_task_thread_runnable{}; bool should_count_idle{}; u64 idle_count{}; diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h index c5deca00b..07272075d 100644 --- a/src/core/hle/kernel/k_scoped_resource_reservation.h +++ b/src/core/hle/kernel/k_scoped_resource_reservation.h @@ -8,15 +8,14 @@ #pragma once #include "common/common_types.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/process.h" namespace Kernel { class KScopedResourceReservation { public: - explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r, - s64 v, s64 timeout) + explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v, s64 timeout) : resource_limit(std::move(l)), value(v), resource(r) { if (resource_limit && value) { success = resource_limit->Reserve(resource, value, timeout); @@ -25,8 +24,7 @@ public: } } - explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r, - s64 v = 1) + explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v = 1) : resource_limit(std::move(l)), value(v), resource(r) { if (resource_limit && value) { success = resource_limit->Reserve(resource, value); @@ -35,10 +33,10 @@ public: } } - explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v, s64 t) + explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v, s64 t) : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {} - explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v = 1) + explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v = 1) : KScopedResourceReservation(p->GetResourceLimit(), r, v) {} ~KScopedResourceReservation() noexcept { @@ -58,7 +56,7 @@ public: } private: - std::shared_ptr<KResourceLimit> resource_limit; + KResourceLimit* resource_limit{}; s64 value; LimitableResource resource; bool success; diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index ebecf0c77..b5d405744 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h @@ -8,7 +8,7 @@ #pragma once #include "common/common_types.h" -#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/time_manager.h" diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp new file mode 100644 index 000000000..8cbde177a --- /dev/null +++ b/src/core/hle/kernel/k_server_port.cpp @@ -0,0 +1,104 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <tuple> +#include "common/assert.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KServerPort::KServerPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} +KServerPort::~KServerPort() = default; + +void KServerPort::Initialize(KPort* parent_, std::string&& name_) { + // Set member variables. + parent = parent_; + name = std::move(name_); +} + +bool KServerPort::IsLight() const { + return this->GetParent()->IsLight(); +} + +void KServerPort::CleanupSessions() { + // Ensure our preconditions are met. + if (this->IsLight()) { + UNIMPLEMENTED(); + } + + // Cleanup the session list. + while (true) { + // Get the last session in the list + KServerSession* session = nullptr; + { + KScopedSchedulerLock sl{kernel}; + if (!session_list.empty()) { + session = std::addressof(session_list.front()); + session_list.pop_front(); + } + } + + // Close the session. + if (session != nullptr) { + session->Close(); + } else { + break; + } + } +} + +void KServerPort::Destroy() { + // Note with our parent that we're closed. + parent->OnServerClosed(); + + // Perform necessary cleanup of our session lists. + this->CleanupSessions(); + + // Close our reference to our parent. + parent->Close(); +} + +bool KServerPort::IsSignaled() const { + if (this->IsLight()) { + UNIMPLEMENTED(); + return false; + } else { + return !session_list.empty(); + } +} + +void KServerPort::EnqueueSession(KServerSession* session) { + ASSERT(!this->IsLight()); + + KScopedSchedulerLock sl{kernel}; + + // Add the session to our queue. + session_list.push_back(*session); + if (session_list.size() == 1) { + this->NotifyAvailable(); + } +} + +KServerSession* KServerPort::AcceptSession() { + ASSERT(!this->IsLight()); + + KScopedSchedulerLock sl{kernel}; + + // Return the first session in the list. + if (session_list.empty()) { + return nullptr; + } + + KServerSession* session = std::addressof(session_list.front()); + session_list.pop_front(); + return session; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h new file mode 100644 index 000000000..e76792253 --- /dev/null +++ b/src/core/hle/kernel/k_server_port.h @@ -0,0 +1,80 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include <boost/intrusive/list.hpp> + +#include "common/common_types.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KernelCore; +class KPort; +class SessionRequestHandler; + +class KServerPort final : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); + +private: + using SessionList = boost::intrusive::list<KServerSession>; + +public: + explicit KServerPort(KernelCore& kernel_); + virtual ~KServerPort() override; + + using HLEHandler = std::shared_ptr<SessionRequestHandler>; + + void Initialize(KPort* parent_, std::string&& name_); + + /// Whether or not this server port has an HLE handler available. + bool HasHLEHandler() const { + return hle_handler != nullptr; + } + + /// Gets the HLE handler for this port. + HLEHandler GetHLEHandler() const { + return hle_handler; + } + + /** + * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port + * will inherit a reference to this handler. + */ + void SetHleHandler(HLEHandler hle_handler_) { + hle_handler = std::move(hle_handler_); + } + + void EnqueueSession(KServerSession* pending_session); + + KServerSession* AcceptSession(); + + const KPort* GetParent() const { + return parent; + } + + bool IsLight() const; + + // Overridden virtual functions. + virtual void Destroy() override; + virtual bool IsSignaled() const override; + +private: + void CleanupSessions(); + +private: + SessionList session_list; + HLEHandler hle_handler; + KPort* parent{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 790dbb998..b28cc2499 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -10,49 +10,39 @@ #include "common/logging/log.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" #include "core/memory.h" namespace Kernel { -ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} +KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} -ServerSession::~ServerSession() { +KServerSession::~KServerSession() { kernel.ReleaseServiceThread(service_thread); } -ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name) { - std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; - - session->name = std::move(name); - session->parent = std::move(parent); - session->service_thread = kernel.CreateServiceThread(session->name); - - return MakeResult(std::move(session)); +void KServerSession::Initialize(KSession* parent_, std::string&& name_) { + // Set member variables. + parent = parent_; + name = std::move(name_); + service_thread = kernel.CreateServiceThread(name); } -bool ServerSession::IsSignaled() const { - // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. - if (!parent->Client()) { - return true; - } +void KServerSession::Destroy() { + parent->OnServerClosed(); - // Wait if we have no pending requests, or if we're currently handling a request. - return !pending_requesting_threads.empty() && currently_handling == nullptr; + parent->Close(); } -void ServerSession::ClientDisconnected() { +void KServerSession::OnClientClosed() { // We keep a shared pointer to the hle handler to keep it alive throughout // the call to ClientDisconnected, as ClientDisconnected invalidates the // hle_handler member itself during the course of the function executing. @@ -60,24 +50,31 @@ void ServerSession::ClientDisconnected() { if (handler) { // Note that after this returns, this server session's hle_handler is // invalidated (set to null). - handler->ClientDisconnected(SharedFrom(this)); + handler->ClientDisconnected(this); + } +} + +bool KServerSession::IsSignaled() const { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // If the client is closed, we're always signaled. + if (parent->IsClientClosed()) { + return true; } - // Clean up the list of client threads with pending requests, they are unneeded now that the - // client endpoint is closed. - pending_requesting_threads.clear(); - currently_handling = nullptr; + // Otherwise, we're signaled if we have a request and aren't handling one. + return false; } -void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { +void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { domain_request_handlers.push_back(std::move(handler)); } -std::size_t ServerSession::NumDomainRequestHandlers() const { +std::size_t KServerSession::NumDomainRequestHandlers() const { return domain_request_handlers.size(); } -ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { +ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { if (!context.HasDomainMessageHeader()) { return RESULT_SUCCESS; } @@ -116,23 +113,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con return RESULT_SUCCESS; } -ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<KThread> thread, - Core::Memory::Memory& memory) { +ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; - auto context = - std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread)); + auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread); context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); if (auto strong_ptr = service_thread.lock()) { - strong_ptr->QueueSyncRequest(*this, std::move(context)); + strong_ptr->QueueSyncRequest(*parent, std::move(context)); return RESULT_SUCCESS; } return RESULT_SUCCESS; } -ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { +ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { ResultCode result = RESULT_SUCCESS; // If the session has been converted to a domain, handle the domain request if (IsDomain() && context.HasDomainMessageHeader()) { @@ -161,10 +156,9 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { return result; } -ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<KThread> thread, - Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing) { - return QueueSyncRequest(std::move(thread), memory); +ResultCode KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { + return QueueSyncRequest(thread, memory); } } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/k_server_session.h index c42d5ee59..597d76d38 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -9,6 +9,8 @@ #include <utility> #include <vector> +#include <boost/intrusive/list.hpp> + #include "common/threadsafe_queue.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/service_thread.h" @@ -27,55 +29,35 @@ namespace Kernel { class HLERequestContext; class KernelCore; -class Session; +class KSession; class SessionRequestHandler; class KThread; -/** - * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS - * primitive for communication between different processes, and are used to implement service calls - * to the various system services. - * - * To make a service call, the client must write the command header and parameters to the buffer - * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest - * SVC call with its ClientSession handle. The kernel will read the command header, using it to - * marshall the parameters to the process at the server endpoint of the session. - * After the server replies to the request, the response is marshalled back to the caller's - * TLS buffer and control is transferred back to it. - */ -class ServerSession final : public KSynchronizationObject { +class KServerSession final : public KSynchronizationObject, + public boost::intrusive::list_base_hook<> { + KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); + friend class ServiceThread; public: - explicit ServerSession(KernelCore& kernel); - ~ServerSession() override; + explicit KServerSession(KernelCore& kernel_); + virtual ~KServerSession() override; - friend class Session; + virtual void Destroy() override; - static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name = "Unknown"); + void Initialize(KSession* parent_, std::string&& name_); - std::string GetTypeName() const override { - return "ServerSession"; + KSession* GetParent() { + return parent; } - std::string GetName() const override { - return name; + const KSession* GetParent() const { + return parent; } - static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } + virtual bool IsSignaled() const override; - Session* GetParent() { - return parent.get(); - } - - const Session* GetParent() const { - return parent.get(); - } + void OnClientClosed(); /** * Sets the HLE handler for the session. This handler will be called to service IPC requests @@ -95,12 +77,9 @@ public: * * @returns ResultCode from the operation. */ - ResultCode HandleSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory, + ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing); - /// Called when a client disconnection occurs. - void ClientDisconnected(); - /// Adds a new domain request handler to the collection of request handlers within /// this ServerSession instance. void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); @@ -124,13 +103,9 @@ public: convert_to_domain = true; } - bool IsSignaled() const override; - - void Finalize() override {} - private: /// Queues a sync request from the emulated application. - ResultCode QueueSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory); + ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); /// Completes a sync request from the emulated application. ResultCode CompleteSyncRequest(HLERequestContext& context); @@ -139,33 +114,20 @@ private: /// object handle. ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); - /// The parent session, which links to the client endpoint. - std::shared_ptr<Session> parent; - /// This session's HLE request handler (applicable when not a domain) std::shared_ptr<SessionRequestHandler> hle_handler; /// This is the list of domain request handlers (after conversion to a domain) std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; - /// List of threads that are pending a response after a sync request. This list is processed in - /// a LIFO manner, thus, the last request will be dispatched first. - /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. - std::vector<std::shared_ptr<KThread>> pending_requesting_threads; - - /// Thread whose request is currently being handled. A request is considered "handled" when a - /// response is sent via svcReplyAndReceive. - /// TODO(Subv): Find a better name for this. - std::shared_ptr<KThread> currently_handling; - /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; - /// The name of this session (optional) - std::string name; - /// Thread to dispatch service requests std::weak_ptr<ServiceThread> service_thread; + + /// KSession that owns this KServerSession + KSession* parent{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp new file mode 100644 index 000000000..025b8b555 --- /dev/null +++ b/src/core/hle/kernel/k_session.cpp @@ -0,0 +1,85 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" + +namespace Kernel { + +KSession::KSession(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {} +KSession::~KSession() = default; + +void KSession::Initialize(KClientPort* port_, const std::string& name_) { + // Increment reference count. + // Because reference count is one on creation, this will result + // in a reference count of two. Thus, when both server and client are closed + // this object will be destroyed. + Open(); + + // Create our sub sessions. + KAutoObject::Create(std::addressof(server)); + KAutoObject::Create(std::addressof(client)); + + // Initialize our sub sessions. + server.Initialize(this, name_ + ":Server"); + client.Initialize(this, name_ + ":Client"); + + // Set state and name. + SetState(State::Normal); + name = name_; + + // Set our owner process. + process = kernel.CurrentProcess(); + process->Open(); + + // Set our port. + port = port_; + if (port != nullptr) { + port->Open(); + } + + // Mark initialized. + initialized = true; +} + +void KSession::Finalize() { + if (port == nullptr) { + return; + } + + port->OnSessionFinalized(); + port->Close(); +} + +void KSession::OnServerClosed() { + if (GetState() != State::Normal) { + return; + } + + SetState(State::ServerClosed); + client.OnServerClosed(); +} + +void KSession::OnClientClosed() { + if (GetState() != State::Normal) { + return; + } + + SetState(State::ClientClosed); + server.OnClientClosed(); +} + +void KSession::PostDestroy(uintptr_t arg) { + // Release the session count resource the owner process holds. + KProcess* owner = reinterpret_cast<KProcess*>(arg); + owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); + owner->Close(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h new file mode 100644 index 000000000..16901e19c --- /dev/null +++ b/src/core/hle/kernel/k_session.h @@ -0,0 +1,96 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> +#include <string> + +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/slab_helpers.h" + +namespace Kernel { + +class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject); + +public: + explicit KSession(KernelCore& kernel_); + virtual ~KSession() override; + + void Initialize(KClientPort* port_, const std::string& name_); + + virtual void Finalize() override; + + virtual bool IsInitialized() const override { + return initialized; + } + + virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast<uintptr_t>(process); + } + + static void PostDestroy(uintptr_t arg); + + void OnServerClosed(); + + void OnClientClosed(); + + bool IsServerClosed() const { + return this->GetState() != State::Normal; + } + + bool IsClientClosed() const { + return this->GetState() != State::Normal; + } + + KClientSession& GetClientSession() { + return client; + } + + KServerSession& GetServerSession() { + return server; + } + + const KClientSession& GetClientSession() const { + return client; + } + + const KServerSession& GetServerSession() const { + return server; + } + + const KClientPort* GetParent() const { + return port; + } + +private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + +private: + void SetState(State state) { + atomic_state = static_cast<u8>(state); + } + + State GetState() const { + return static_cast<State>(atomic_state.load(std::memory_order_relaxed)); + } + +private: + KServerSession server; + KClientSession client; + std::atomic<std::underlying_type_t<State>> atomic_state{ + static_cast<std::underlying_type_t<State>>(State::Invalid)}; + KClientPort* port{}; + KProcess* process{}; + bool initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index 9b14f42b5..7770b1868 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -8,50 +8,74 @@ #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" namespace Kernel { -KSharedMemory::KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) - : Object{kernel}, device_memory{device_memory} {} +KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {} KSharedMemory::~KSharedMemory() { kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size); } -std::shared_ptr<KSharedMemory> KSharedMemory::Create( - KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - KPageLinkedList&& page_list, KMemoryPermission owner_permission, - KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) { +ResultCode KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_, + KPageLinkedList&& page_list_, + Svc::MemoryPermission owner_permission_, + Svc::MemoryPermission user_permission_, + PAddr physical_address_, std::size_t size_, + std::string name_) { + // Set members. + owner_process = owner_process_; + device_memory = &device_memory_; + page_list = std::move(page_list_); + owner_permission = owner_permission_; + user_permission = user_permission_; + physical_address = physical_address_; + size = size_; + name = std::move(name_); - const auto resource_limit = kernel.GetSystemResourceLimit(); - KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, - size); - ASSERT(memory_reservation.Succeeded()); + // Get the resource limit. + KResourceLimit* reslimit = kernel.GetSystemResourceLimit(); - std::shared_ptr<KSharedMemory> shared_memory{ - std::make_shared<KSharedMemory>(kernel, device_memory)}; - - shared_memory->owner_process = owner_process; - shared_memory->page_list = std::move(page_list); - shared_memory->owner_permission = owner_permission; - shared_memory->user_permission = user_permission; - shared_memory->physical_address = physical_address; - shared_memory->size = size; - shared_memory->name = name; + // Reserve memory for ourselves. + KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemory, + size_); + R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); + // Commit our reservation. memory_reservation.Commit(); - return shared_memory; + + // Set our resource limit. + resource_limit = reslimit; + resource_limit->Open(); + + // Mark initialized. + is_initialized = true; + + // Clear all pages in the memory. + std::memset(device_memory_.GetPointer(physical_address_), 0, size_); + + return RESULT_SUCCESS; +} + +void KSharedMemory::Finalize() { + // Release the memory reservation. + resource_limit->Release(LimitableResource::PhysicalMemory, size); + resource_limit->Close(); + + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList>::Finalize(); } -ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size, - KMemoryPermission permissions) { - const u64 page_count{(size + PageSize - 1) / PageSize}; +ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t map_size, + Svc::MemoryPermission permissions) { + const u64 page_count{(map_size + PageSize - 1) / PageSize}; if (page_list.GetNumPages() != page_count) { UNIMPLEMENTED_MSG("Page count does not match"); } - const KMemoryPermission expected = + const Svc::MemoryPermission expected = &target_process == owner_process ? owner_permission : user_permission; if (permissions != expected) { @@ -59,7 +83,17 @@ ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_ } return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared, - permissions); + ConvertToKMemoryPermission(permissions)); +} + +ResultCode KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) { + const u64 page_count{(unmap_size + PageSize - 1) / PageSize}; + + if (page_list.GetNumPages() != page_count) { + UNIMPLEMENTED_MSG("Page count does not match"); + } + + return target_process.PageTable().UnmapPages(address, page_list, KMemoryState::Shared); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 016e34be5..553a56327 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -11,47 +11,44 @@ #include "core/device_memory.h" #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_page_linked_list.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Kernel { class KernelCore; -class KSharedMemory final : public Object { +class KSharedMemory final + : public KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KSharedMemory, KAutoObject); + public: - explicit KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory); + explicit KSharedMemory(KernelCore& kernel_); ~KSharedMemory() override; - static std::shared_ptr<KSharedMemory> Create( - KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - KPageLinkedList&& page_list, KMemoryPermission owner_permission, - KMemoryPermission user_permission, PAddr physical_address, std::size_t size, - std::string name); - - std::string GetTypeName() const override { - return "SharedMemory"; - } - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } + ResultCode Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_, + KPageLinkedList&& page_list_, Svc::MemoryPermission owner_permission_, + Svc::MemoryPermission user_permission_, PAddr physical_address_, + std::size_t size_, std::string name_); /** * Maps a shared memory block to an address in the target process' address space * @param target_process Process on which to map the memory block * @param address Address in system memory to map shared memory block to - * @param size Size of the shared memory block to map + * @param map_size Size of the shared memory block to map * @param permissions Memory block map permissions (specified by SVC field) */ - ResultCode Map(Process& target_process, VAddr address, std::size_t size, - KMemoryPermission permissions); + ResultCode Map(KProcess& target_process, VAddr address, std::size_t map_size, + Svc::MemoryPermission permissions); + + /** + * Unmaps a shared memory block from an address in the target process' address space + * @param target_process Process on which to unmap the memory block + * @param address Address in system memory to unmap shared memory block + * @param unmap_size Size of the shared memory block to unmap + */ + ResultCode Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size); /** * Gets a pointer to the shared memory block @@ -59,7 +56,7 @@ public: * @return A pointer to the shared memory block from the specified offset */ u8* GetPointer(std::size_t offset = 0) { - return device_memory.GetPointer(physical_address + offset); + return device_memory->GetPointer(physical_address + offset); } /** @@ -68,20 +65,26 @@ public: * @return A pointer to the shared memory block from the specified offset */ const u8* GetPointer(std::size_t offset = 0) const { - return device_memory.GetPointer(physical_address + offset); + return device_memory->GetPointer(physical_address + offset); } - void Finalize() override {} + virtual void Finalize() override; + + virtual bool IsInitialized() const override { + return is_initialized; + } + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} private: - Core::DeviceMemory& device_memory; - Process* owner_process{}; + Core::DeviceMemory* device_memory; + KProcess* owner_process{}; KPageLinkedList page_list; - KMemoryPermission owner_permission{}; - KMemoryPermission user_permission{}; + Svc::MemoryPermission owner_permission{}; + Svc::MemoryPermission user_permission{}; PAddr physical_address{}; std::size_t size{}; - std::string name; + KResourceLimit* resource_limit{}; + bool is_initialized{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index aa4471d2f..5ce9a1d7c 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -97,6 +97,7 @@ public: void FreeImpl(void* obj) { // Don't allow freeing an object that wasn't allocated from this heap ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); + impl.Free(obj); } @@ -148,6 +149,14 @@ public: return obj; } + T* AllocateWithKernel(KernelCore& kernel) { + T* obj = static_cast<T*>(AllocateImpl()); + if (obj != nullptr) { + new (obj) T(kernel); + } + return obj; + } + void Free(T* obj) { FreeImpl(obj); } diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index 82f72a0fe..45380dea0 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -13,18 +13,23 @@ namespace Kernel { -ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, +void KSynchronizationObject::Finalize() { + this->OnFinalizeSynchronizationObject(); + KAutoObject::Finalize(); +} + +ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, KSynchronizationObject** objects, const s32 num_objects, s64 timeout) { // Allocate space on stack for thread nodes. std::vector<ThreadListNode> thread_nodes(num_objects); // Prepare for wait. - KThread* thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread(); { // Setup the scheduling lock and sleep. - KScopedSchedulerLockAndSleep slp{kernel, thread, timeout}; + KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout}; // Check if any of the objects are already signaled. for (auto i = 0; i < num_objects; ++i) { @@ -89,13 +94,13 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, thread->SetWaitObjectsForDebugging({}); // Cancel the timer as needed. - kernel.TimeManager().UnscheduleTimeEvent(thread); + kernel_ctx.TimeManager().UnscheduleTimeEvent(thread); // Get the wait result. ResultCode wait_result{RESULT_SUCCESS}; s32 sync_index = -1; { - KScopedSchedulerLock lock(kernel); + KScopedSchedulerLock lock(kernel_ctx); KSynchronizationObject* synced_obj; wait_result = thread->GetWaitResult(std::addressof(synced_obj)); @@ -130,10 +135,8 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, return wait_result; } -KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} - -KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name) - : Object{kernel, std::move(name)} {} +KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) + : KAutoObjectWithList{kernel_} {} KSynchronizationObject::~KSynchronizationObject() = default; diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 5803718fd..a41dd1220 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -6,7 +6,7 @@ #include <vector> -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/result.h" namespace Kernel { @@ -16,7 +16,9 @@ class Synchronization; class KThread; /// Class that represents a Kernel object that a thread can be waiting on -class KSynchronizationObject : public Object { +class KSynchronizationObject : public KAutoObjectWithList { + KERNEL_AUTOOBJECT_TRAITS(KSynchronizationObject, KAutoObject); + public: struct ThreadListNode { ThreadListNode* next{}; @@ -27,15 +29,18 @@ public: KSynchronizationObject** objects, const s32 num_objects, s64 timeout); + virtual void Finalize() override; + [[nodiscard]] virtual bool IsSignaled() const = 0; [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; protected: explicit KSynchronizationObject(KernelCore& kernel); - explicit KSynchronizationObject(KernelCore& kernel, std::string&& name); virtual ~KSynchronizationObject(); + virtual void OnFinalizeSynchronizationObject() {} + void NotifyAvailable(ResultCode result); void NotifyAvailable() { return this->NotifyAvailable(RESULT_SUCCESS); @@ -46,14 +51,4 @@ private: ThreadListNode* thread_list_tail{}; }; -// Specialization of DynamicObjectCast for KSynchronizationObjects -template <> -inline std::shared_ptr<KSynchronizationObject> DynamicObjectCast<KSynchronizationObject>( - std::shared_ptr<Object> object) { - if (object != nullptr && object->IsWaitable()) { - return std::static_pointer_cast<KSynchronizationObject>(object); - } - return nullptr; -} - } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index e0f53287c..e3f08f256 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -18,17 +18,16 @@ #include "core/core.h" #include "core/cpu_manager.h" #include "core/hardware_properties.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" @@ -61,12 +60,12 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, namespace Kernel { -KThread::KThread(KernelCore& kernel) - : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {} +KThread::KThread(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} KThread::~KThread() = default; ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, - s32 virt_core, Process* owner, ThreadType type) { + s32 virt_core, KProcess* owner, ThreadType type) { // Assert parameters are valid. ASSERT((type == ThreadType::Main) || (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); @@ -177,6 +176,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s // Set parent, if relevant. if (owner != nullptr) { parent = owner; + parent->Open(); parent->IncrementThreadCount(); } @@ -209,14 +209,56 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s } ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, - VAddr user_stack_top, s32 prio, s32 core, Process* owner, - ThreadType type) { + VAddr user_stack_top, s32 prio, s32 core, KProcess* owner, + ThreadType type, std::function<void(void*)>&& init_func, + void* init_func_parameter) { // Initialize the thread. R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); + // Initialize host context. + thread->host_context = + std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter); + return RESULT_SUCCESS; } +ResultCode KThread::InitializeDummyThread(KThread* thread) { + return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main); +} + +ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { + return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, + Core::CpuManager::GetIdleThreadStartFunc(), + system.GetCpuManager().GetStartFuncParamater()); +} + +ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, + KThreadFunction func, uintptr_t arg, + s32 virt_core) { + return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority, + Core::CpuManager::GetSuspendThreadStartFunc(), + system.GetCpuManager().GetStartFuncParamater()); +} + +ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread, + KThreadFunction func, uintptr_t arg, VAddr user_stack_top, + s32 prio, s32 virt_core, KProcess* owner) { + system.Kernel().GlobalSchedulerContext().AddThread(thread); + return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, + ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(), + system.GetCpuManager().GetStartFuncParamater()); +} + +void KThread::PostDestroy(uintptr_t arg) { + KProcess* owner = reinterpret_cast<KProcess*>(arg & ~1ULL); + const bool resource_limit_release_hint = (arg & 1); + const s64 hint_value = (resource_limit_release_hint ? 0 : 1); + if (owner != nullptr) { + owner->GetResourceLimit()->Release(LimitableResource::Threads, 1, hint_value); + owner->Close(); + } +} + void KThread::Finalize() { // If the thread has an owner process, unregister it. if (parent != nullptr) { @@ -246,8 +288,10 @@ void KThread::Finalize() { // Decrement the parent process's thread count. if (parent != nullptr) { parent->DecrementThreadCount(); - parent->GetResourceLimit()->Release(LimitableResource::Threads, 1); } + + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize(); } bool KThread::IsSignaled() const { @@ -294,6 +338,9 @@ void KThread::StartTermination() { // Register terminated dpc flag. RegisterDpc(DpcFlag::Terminated); + + // Close the thread. + this->Close(); } void KThread::Pin() { @@ -432,7 +479,7 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m return RESULT_SUCCESS; } -ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) { +ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { ASSERT(parent != nullptr); ASSERT(v_affinity_mask != 0); KScopedLightLock lk{activity_pause_lock}; @@ -444,18 +491,18 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) { ASSERT(num_core_migration_disables >= 0); // If the core id is no-update magic, preserve the ideal core id. - if (core_id == Svc::IdealCoreNoUpdate) { - core_id = virtual_ideal_core_id; - R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, ResultInvalidCombination); + if (cpu_core_id == Svc::IdealCoreNoUpdate) { + cpu_core_id = virtual_ideal_core_id; + R_UNLESS(((1ULL << cpu_core_id) & v_affinity_mask) != 0, ResultInvalidCombination); } // Set the virtual core/affinity mask. - virtual_ideal_core_id = core_id; + virtual_ideal_core_id = cpu_core_id; virtual_affinity_mask = v_affinity_mask; // Translate the virtual core to a physical core. - if (core_id >= 0) { - core_id = Core::Hardware::VirtualToPhysicalCoreMap[core_id]; + if (cpu_core_id >= 0) { + cpu_core_id = Core::Hardware::VirtualToPhysicalCoreMap[cpu_core_id]; } // Translate the virtual affinity mask to a physical one. @@ -470,7 +517,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) { const KAffinityMask old_mask = physical_affinity_mask; // Set our new ideals. - physical_ideal_core_id = core_id; + physical_ideal_core_id = cpu_core_id; physical_affinity_mask.SetAffinityMask(p_affinity_mask); if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { @@ -488,7 +535,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) { } } else { // Otherwise, we edit the original affinity for restoration later. - original_physical_ideal_core_id = core_id; + original_physical_ideal_core_id = cpu_core_id; original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); } } @@ -804,8 +851,8 @@ void KThread::RemoveWaiterImpl(KThread* thread) { thread->SetLockOwner(nullptr); } -void KThread::RestorePriority(KernelCore& kernel, KThread* thread) { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); +void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) { + ASSERT(kernel_ctx.GlobalSchedulerContext().IsLocked()); while (true) { // We want to inherit priority where possible. @@ -821,7 +868,7 @@ void KThread::RestorePriority(KernelCore& kernel, KThread* thread) { // Ensure we don't violate condition variable red black tree invariants. if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { - BeforeUpdatePriority(kernel, cv_tree, thread); + BeforeUpdatePriority(kernel_ctx, cv_tree, thread); } // Change the priority. @@ -830,11 +877,11 @@ void KThread::RestorePriority(KernelCore& kernel, KThread* thread) { // Restore the condition variable, if relevant. if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { - AfterUpdatePriority(kernel, cv_tree, thread); + AfterUpdatePriority(kernel_ctx, cv_tree, thread); } // Update the scheduler. - KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); + KScheduler::OnThreadPriorityChanged(kernel_ctx, thread, old_priority); // Keep the lock owner up to date. KThread* lock_owner = thread->GetLockOwner(); @@ -932,7 +979,7 @@ void KThread::Exit() { // Release the thread resource hint from parent. if (parent != nullptr) { - // TODO(bunnei): Hint that the resource is about to be released. + parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1); resource_limit_release_hint = true; } @@ -995,56 +1042,6 @@ std::shared_ptr<Common::Fiber>& KThread::GetHostContext() { return host_context; } -ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(Core::System& system, - ThreadType type_flags, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process* owner_process) { - auto& kernel = system.Kernel(); - - std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel); - - if (const auto result = - thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority, - processor_id, owner_process, type_flags); - result.IsError()) { - return result; - } - - thread->name = name; - - auto& scheduler = kernel.GlobalSchedulerContext(); - scheduler.AddThread(thread); - - return MakeResult<std::shared_ptr<KThread>>(std::move(thread)); -} - -ResultVal<std::shared_ptr<KThread>> KThread::CreateThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, - u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, - std::function<void(void*)>&& thread_start_func, void* thread_start_parameter) { - auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg, - processor_id, stack_top, owner_process); - - if (thread_result.Succeeded()) { - (*thread_result)->host_context = - std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter); - } - - return thread_result; -} - -ResultVal<std::shared_ptr<KThread>> KThread::CreateUserThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, - u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) { - std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); - - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - - return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id, - stack_top, owner_process, std::move(init_func), init_func_parameter); -} - KThread* GetCurrentThreadPointer(KernelCore& kernel) { return kernel.GetCurrentEmuThread(); } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index b442dfe57..4abfc2b49 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -19,7 +19,7 @@ #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_types.h" #include "core/hle/result.h" @@ -37,7 +37,7 @@ namespace Kernel { class GlobalSchedulerContext; class KernelCore; -class Process; +class KProcess; class KScheduler; class KThreadQueue; @@ -99,15 +99,19 @@ enum class ThreadWaitReasonForDebugging : u32 { [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); -class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { +class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>, + public boost::intrusive::list_base_hook<> { + KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); + +private: friend class KScheduler; - friend class Process; + friend class KProcess; public: static constexpr s32 DefaultThreadPriority = 44; static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; - explicit KThread(KernelCore& kernel); + explicit KThread(KernelCore& kernel_); ~KThread() override; public: @@ -115,74 +119,10 @@ public: using ThreadContext64 = Core::ARM_Interface::ThreadContext64; using WaiterList = boost::intrusive::list<KThread>; - /** - * Creates and returns a new thread. - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @return A shared pointer to the newly created thread - */ - [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); - - /** - * Creates and returns a new thread, with a specified entry point. - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @param thread_start_func The function where the host context will start. - * @param thread_start_parameter The parameter which will passed to host context on init - * @return A shared pointer to the newly created thread - */ - [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, - std::function<void(void*)>&& thread_start_func, void* thread_start_parameter); - - /** - * Creates and returns a new thread for the emulated "user" process. - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @return A shared pointer to the newly created thread - */ - [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateUserThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); - - [[nodiscard]] std::string GetName() const override { - return name; - } - void SetName(std::string new_name) { name = std::move(new_name); } - [[nodiscard]] std::string GetTypeName() const override { - return "Thread"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Thread; - [[nodiscard]] HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - /** * Gets the thread's current priority * @return The current thread's priority @@ -257,10 +197,6 @@ public: void Suspend(); - void Finalize() override; - - bool IsSignaled() const override; - void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { synced_object = obj; wait_result = wait_res; @@ -354,11 +290,11 @@ public: current_core_id = core; } - [[nodiscard]] Process* GetOwnerProcess() { + [[nodiscard]] KProcess* GetOwnerProcess() { return parent; } - [[nodiscard]] const Process* GetOwnerProcess() const { + [[nodiscard]] const KProcess* GetOwnerProcess() const { return parent; } @@ -382,7 +318,7 @@ public: [[nodiscard]] ResultCode GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask); - [[nodiscard]] ResultCode SetCoreMask(s32 core_id, u64 v_affinity_mask); + [[nodiscard]] ResultCode SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask); [[nodiscard]] ResultCode SetActivity(Svc::ThreadActivity activity); @@ -422,6 +358,40 @@ public: return termination_requested || GetRawState() == ThreadState::Terminated; } + [[nodiscard]] virtual u64 GetId() const override final { + return this->GetThreadID(); + } + + [[nodiscard]] virtual bool IsInitialized() const override { + return initialized; + } + + [[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0); + } + + virtual void Finalize() override; + + [[nodiscard]] virtual bool IsSignaled() const override; + + static void PostDestroy(uintptr_t arg); + + [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); + + [[nodiscard]] static ResultCode InitializeIdleThread(Core::System& system, KThread* thread, + s32 virt_core); + + [[nodiscard]] static ResultCode InitializeHighPriorityThread(Core::System& system, + KThread* thread, + KThreadFunction func, + uintptr_t arg, s32 virt_core); + + [[nodiscard]] static ResultCode InitializeUserThread(Core::System& system, KThread* thread, + KThreadFunction func, uintptr_t arg, + VAddr user_stack_top, s32 prio, + s32 virt_core, KProcess* owner); + +public: struct StackParameters { u8 svc_permission[0x10]; std::atomic<u8> dpc_flags; @@ -671,13 +641,15 @@ private: void StartTermination(); [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, - s32 prio, s32 virt_core, Process* owner, ThreadType type); + s32 prio, s32 virt_core, KProcess* owner, ThreadType type); [[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, - s32 core, Process* owner, ThreadType type); + s32 core, KProcess* owner, ThreadType type, + std::function<void(void*)>&& init_func, + void* init_func_parameter); - static void RestorePriority(KernelCore& kernel, KThread* thread); + static void RestorePriority(KernelCore& kernel_ctx, KThread* thread); // For core KThread implementation ThreadContext32 thread_context_32{}; @@ -697,7 +669,7 @@ private: std::atomic<s64> cpu_time{}; KSynchronizationObject* synced_object{}; VAddr address_key{}; - Process* parent{}; + KProcess* parent{}; VAddr kernel_stack_top{}; u32* light_ipc_data{}; VAddr tls_address{}; @@ -742,7 +714,6 @@ private: VAddr mutex_wait_address_for_debugging{}; ThreadWaitReasonForDebugging wait_reason_for_debugging{}; ThreadType thread_type_for_debugging{}; - std::string name; public: using ConditionVariableThreadTreeType = ConditionVariableThreadTree; diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp new file mode 100644 index 000000000..5bc33706d --- /dev/null +++ b/src/core/hle/kernel/k_transfer_memory.cpp @@ -0,0 +1,45 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +KTransferMemory::KTransferMemory(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_} {} + +KTransferMemory::~KTransferMemory() = default; + +ResultCode KTransferMemory::Initialize(VAddr address_, std::size_t size_, + Svc::MemoryPermission owner_perm_) { + // Set members. + owner = kernel.CurrentProcess(); + + // TODO(bunnei): Lock for transfer memory + + // Set remaining tracking members. + owner->Open(); + owner_perm = owner_perm_; + address = address_; + size = size_; + is_initialized = true; + + return RESULT_SUCCESS; +} + +void KTransferMemory::Finalize() { + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList>::Finalize(); +} + +void KTransferMemory::PostDestroy(uintptr_t arg) { + KProcess* owner = reinterpret_cast<KProcess*>(arg); + owner->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1); + owner->Close(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h new file mode 100644 index 000000000..838fd2b18 --- /dev/null +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -0,0 +1,66 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> + +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/kernel/svc_types.h" +#include "core/hle/result.h" + +union ResultCode; + +namespace Core::Memory { +class Memory; +} + +namespace Kernel { + +class KernelCore; +class KProcess; + +class KTransferMemory final + : public KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject); + +public: + explicit KTransferMemory(KernelCore& kernel_); + virtual ~KTransferMemory() override; + + ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_); + + virtual void Finalize() override; + + virtual bool IsInitialized() const override { + return is_initialized; + } + + virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast<uintptr_t>(owner); + } + + static void PostDestroy(uintptr_t arg); + + KProcess* GetOwner() const { + return owner; + } + + VAddr GetSourceAddress() const { + return address; + } + + size_t GetSize() const { + return is_initialized ? size * PageSize : 0; + } + +private: + KProcess* owner{}; + VAddr address{}; + Svc::MemoryPermission owner_perm{}; + size_t size{}; + bool is_initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_writable_event.cpp b/src/core/hle/kernel/k_writable_event.cpp index 25c52edb2..b7b83c151 100644 --- a/src/core/hle/kernel/k_writable_event.cpp +++ b/src/core/hle/kernel/k_writable_event.cpp @@ -8,20 +8,29 @@ namespace Kernel { -KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name) - : Object{kernel, std::move(name)} {} +KWritableEvent::KWritableEvent(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer{kernel_} {} + KWritableEvent::~KWritableEvent() = default; -void KWritableEvent::Initialize(KEvent* parent_) { +void KWritableEvent::Initialize(KEvent* parent_, std::string&& name_) { parent = parent_; + name = std::move(name_); + parent->GetReadableEvent().Open(); } ResultCode KWritableEvent::Signal() { - return parent->GetReadableEvent()->Signal(); + return parent->GetReadableEvent().Signal(); } ResultCode KWritableEvent::Clear() { - return parent->GetReadableEvent()->Clear(); + return parent->GetReadableEvent().Clear(); +} + +void KWritableEvent::Destroy() { + // Close our references. + parent->GetReadableEvent().Close(); + parent->Close(); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h index 518f5448d..607b0eadb 100644 --- a/src/core/hle/kernel/k_writable_event.h +++ b/src/core/hle/kernel/k_writable_event.h @@ -4,7 +4,8 @@ #pragma once -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Kernel { @@ -12,24 +13,19 @@ namespace Kernel { class KernelCore; class KEvent; -class KWritableEvent final : public Object { +class KWritableEvent final + : public KAutoObjectWithSlabHeapAndContainer<KWritableEvent, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KWritableEvent, KAutoObject); + public: - explicit KWritableEvent(KernelCore& kernel, std::string&& name); + explicit KWritableEvent(KernelCore& kernel_); ~KWritableEvent() override; - std::string GetTypeName() const override { - return "KWritableEvent"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - void Initialize(KEvent* parent_); + virtual void Destroy() override; - void Finalize() override {} + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + void Initialize(KEvent* parent_, std::string&& name_); ResultCode Signal(); ResultCode Clear(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5c4f45ab4..bd4e4d350 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -26,10 +26,12 @@ #include "core/cpu_manager.h" #include "core/device_memory.h" #include "core/hardware_properties.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/init/init_slab_setup.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_shared_memory.h" @@ -37,7 +39,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" @@ -50,17 +51,16 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { struct KernelCore::Impl { - explicit Impl(Core::System& system, KernelCore& kernel) - : time_manager{system}, global_handle_table{kernel}, system{system} {} + explicit Impl(Core::System& system_, KernelCore& kernel_) + : time_manager{system_}, object_list_container{kernel_}, system{system_} {} - void SetMulticore(bool is_multicore) { - this->is_multicore = is_multicore; + void SetMulticore(bool is_multi) { + is_multicore = is_multi; } void Initialize(KernelCore& kernel) { global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); - - RegisterHostThread(); + global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); service_thread_manager = std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager"); @@ -69,14 +69,20 @@ struct KernelCore::Impl { InitializePhysicalCores(); // Derive the initial memory layout from the emulated board + Init::InitializeSlabResourceCounts(kernel); KMemoryLayout memory_layout; DeriveInitialMemoryLayout(memory_layout); - InitializeMemoryLayout(memory_layout); + Init::InitializeSlabHeaps(system, memory_layout); + + // Initialize kernel memory and resources. InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout); - InitializeSlabHeaps(); + InitializeMemoryLayout(memory_layout); + InitializePageSlab(); InitializeSchedulers(); InitializeSuspendThreads(); InitializePreemption(kernel); + + RegisterHostThread(); } void InitializeCores() { @@ -93,34 +99,49 @@ struct KernelCore::Impl { service_threads.clear(); next_object_id = 0; - next_kernel_process_id = Process::InitialKIPIDMin; - next_user_process_id = Process::ProcessIDMin; + next_kernel_process_id = KProcess::InitialKIPIDMin; + next_user_process_id = KProcess::ProcessIDMin; next_thread_id = 1; - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - if (suspend_threads[i]) { - suspend_threads[i].reset(); + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + if (suspend_threads[core_id]) { + suspend_threads[core_id]->Close(); + suspend_threads[core_id] = nullptr; } + + schedulers[core_id].reset(); } cores.clear(); - current_process = nullptr; + if (current_process) { + current_process->Close(); + current_process = nullptr; + } - global_handle_table.Clear(); + global_handle_table.reset(); preemption_event = nullptr; + for (auto& iter : named_ports) { + iter.second->Close(); + } named_ports.clear(); exclusive_monitor.reset(); - hid_shared_mem = nullptr; - font_shared_mem = nullptr; - irs_shared_mem = nullptr; - time_shared_mem = nullptr; - - system_resource_limit = nullptr; + // Cleanup persistent kernel objects + auto CleanupObject = [](KAutoObject* obj) { + if (obj) { + obj->Close(); + obj = nullptr; + } + }; + CleanupObject(hid_shared_mem); + CleanupObject(font_shared_mem); + CleanupObject(irs_shared_mem); + CleanupObject(time_shared_mem); + CleanupObject(system_resource_limit); // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others next_host_thread_id = Core::Hardware::NUM_CPU_CORES; @@ -145,7 +166,9 @@ struct KernelCore::Impl { void InitializeSystemResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing, const KMemoryLayout& memory_layout) { - system_resource_limit = std::make_shared<KResourceLimit>(kernel, core_timing); + system_resource_limit = KResourceLimit::Create(system.Kernel()); + system_resource_limit->Initialize(&core_timing); + const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes(); // If setting the default system values fails, then something seriously wrong has occurred. @@ -189,19 +212,16 @@ struct KernelCore::Impl { } void InitializeSuspendThreads() { - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - std::string name = "Suspend Thread Id:" + std::to_string(i); - std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::CreateThread( - system, ThreadType::HighPriority, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, - nullptr, std::move(init_func), init_func_parameter); - - suspend_threads[i] = std::move(thread_res).Unwrap(); + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + suspend_threads[core_id] = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {}, + core_id) + .IsSuccess()); + suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); } } - void MakeCurrentProcess(Process* process) { + void MakeCurrentProcess(KProcess* process) { current_process = process; if (process == nullptr) { return; @@ -232,11 +252,15 @@ struct KernelCore::Impl { // Gets the dummy KThread for the caller, allocating a new one if this is the first time KThread* GetHostDummyThread() { - const thread_local auto thread = - KThread::CreateThread( - system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, - KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr) - .Unwrap(); + auto make_thread = [this]() { + std::unique_ptr<KThread> thread = std::make_unique<KThread>(system.Kernel()); + KAutoObject::Create(thread.get()); + ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); + thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); + return std::move(thread); + }; + + thread_local auto thread = make_thread(); return thread.get(); } @@ -371,7 +395,8 @@ struct KernelCore::Impl { const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit(); // Determine the size of the slab region. - const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize); + const size_t slab_region_size = + Common::AlignUp(Init::CalculateTotalSlabHeapSize(system.Kernel()), PageSize); ASSERT(slab_region_size <= resource_region_size); // Setup the slab region. @@ -569,25 +594,30 @@ struct KernelCore::Impl { const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size}; const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size}; - hid_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size, - "HID:SharedMemory"); - font_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size, - "Font:SharedMemory"); - irs_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size, - "IRS:SharedMemory"); - time_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size, - "Time:SharedMemory"); + hid_shared_mem = KSharedMemory::Create(system.Kernel()); + font_shared_mem = KSharedMemory::Create(system.Kernel()); + irs_shared_mem = KSharedMemory::Create(system.Kernel()); + time_shared_mem = KSharedMemory::Create(system.Kernel()); + + hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, + {hid_phys_addr, hid_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + hid_phys_addr, hid_size, "HID:SharedMemory"); + font_shared_mem->Initialize(system.DeviceMemory(), nullptr, + {font_phys_addr, font_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + font_phys_addr, font_size, "Font:SharedMemory"); + irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, + {irs_phys_addr, irs_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + irs_phys_addr, irs_size, "IRS:SharedMemory"); + time_shared_mem->Initialize(system.DeviceMemory(), nullptr, + {time_phys_addr, time_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + time_phys_addr, time_size, "Time:SharedMemory"); } - void InitializeSlabHeaps() { + void InitializePageSlab() { // Allocate slab heaps user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>(); @@ -596,30 +626,33 @@ struct KernelCore::Impl { // Reserve slab heaps ASSERT( system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); - // Initialize slab heaps + // Initialize slab heap user_slab_heap_pages->Initialize( system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase), user_slab_heap_size); } std::atomic<u32> next_object_id{0}; - std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; - std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; + std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; + std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin}; std::atomic<u64> next_thread_id{1}; // Lists all processes that exist in the current session. - std::vector<std::shared_ptr<Process>> process_list; - Process* current_process = nullptr; + std::vector<KProcess*> process_list; + KProcess* current_process{}; std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; Kernel::TimeManager time_manager; - std::shared_ptr<KResourceLimit> system_resource_limit; + Init::KSlabResourceCounts slab_resource_counts{}; + KResourceLimit* system_resource_limit{}; std::shared_ptr<Core::Timing::EventType> preemption_event; // This is the kernel's handle table or supervisor handle table which // stores all the objects in place. - HandleTable global_handle_table; + std::unique_ptr<KHandleTable> global_handle_table; + + KAutoObjectWithListContainer object_list_container; /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. @@ -636,10 +669,10 @@ struct KernelCore::Impl { std::unique_ptr<KSlabHeap<Page>> user_slab_heap_pages; // Shared memory for services - std::shared_ptr<Kernel::KSharedMemory> hid_shared_mem; - std::shared_ptr<Kernel::KSharedMemory> font_shared_mem; - std::shared_ptr<Kernel::KSharedMemory> irs_shared_mem; - std::shared_ptr<Kernel::KSharedMemory> time_shared_mem; + Kernel::KSharedMemory* hid_shared_mem{}; + Kernel::KSharedMemory* font_shared_mem{}; + Kernel::KSharedMemory* irs_shared_mem{}; + Kernel::KSharedMemory* time_shared_mem{}; // Threads used for services std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; @@ -648,7 +681,7 @@ struct KernelCore::Impl { // the release of itself std::unique_ptr<Common::ThreadWorker> service_thread_manager; - std::array<std::shared_ptr<KThread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; @@ -663,15 +696,14 @@ struct KernelCore::Impl { }; KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {} -KernelCore::~KernelCore() { - Shutdown(); -} +KernelCore::~KernelCore() = default; void KernelCore::SetMulticore(bool is_multicore) { impl->SetMulticore(is_multicore); } void KernelCore::Initialize() { + slab_heap_container = std::make_unique<SlabHeapContainer>(); impl->Initialize(*this); } @@ -683,31 +715,35 @@ void KernelCore::Shutdown() { impl->Shutdown(); } -std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const { +const KResourceLimit* KernelCore::GetSystemResourceLimit() const { return impl->system_resource_limit; } -std::shared_ptr<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { - return impl->global_handle_table.Get<KThread>(handle); +KResourceLimit* KernelCore::GetSystemResourceLimit() { + return impl->system_resource_limit; +} + +KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { + return impl->global_handle_table->GetObject<KThread>(handle); } -void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { - impl->process_list.push_back(std::move(process)); +void KernelCore::AppendNewProcess(KProcess* process) { + impl->process_list.push_back(process); } -void KernelCore::MakeCurrentProcess(Process* process) { +void KernelCore::MakeCurrentProcess(KProcess* process) { impl->MakeCurrentProcess(process); } -Process* KernelCore::CurrentProcess() { +KProcess* KernelCore::CurrentProcess() { return impl->current_process; } -const Process* KernelCore::CurrentProcess() const { +const KProcess* KernelCore::CurrentProcess() const { return impl->current_process; } -const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const { +const std::vector<KProcess*>& KernelCore::GetProcessList() const { return impl->process_list; } @@ -781,6 +817,14 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { return *impl->exclusive_monitor; } +KAutoObjectWithListContainer& KernelCore::ObjectListContainer() { + return impl->object_list_container; +} + +const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const { + return impl->object_list_container; +} + void KernelCore::InvalidateAllInstructionCaches() { for (auto& physical_core : impl->cores) { physical_core.ArmInterface().ClearInstructionCache(); @@ -800,8 +844,9 @@ void KernelCore::PrepareReschedule(std::size_t id) { // TODO: Reimplement, this } -void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { - impl->named_ports.emplace(std::move(name), std::move(port)); +void KernelCore::AddNamedPort(std::string name, KClientPort* port) { + port->Open(); + impl->named_ports.emplace(std::move(name), port); } KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { @@ -833,12 +878,12 @@ u64 KernelCore::CreateNewUserProcessID() { return impl->next_user_process_id++; } -Kernel::HandleTable& KernelCore::GlobalHandleTable() { - return impl->global_handle_table; +KHandleTable& KernelCore::GlobalHandleTable() { + return *impl->global_handle_table; } -const Kernel::HandleTable& KernelCore::GlobalHandleTable() const { - return impl->global_handle_table; +const KHandleTable& KernelCore::GlobalHandleTable() const { + return *impl->global_handle_table; } void KernelCore::RegisterCoreThread(std::size_t core_id) { @@ -910,9 +955,9 @@ void KernelCore::Suspend(bool in_suspention) { { KScopedSchedulerLock lock(*this); const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - impl->suspend_threads[i]->SetState(state); - impl->suspend_threads[i]->SetWaitReasonForDebugging( + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + impl->suspend_threads[core_id]->SetState(state); + impl->suspend_threads[core_id]->SetWaitReasonForDebugging( ThreadWaitReasonForDebugging::Suspended); } } @@ -952,6 +997,14 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi }); } +Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { + return impl->slab_resource_counts; +} + +const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const { + return impl->slab_resource_counts; +} + bool KernelCore::IsPhantomModeForSingleCore() const { return impl->IsPhantomModeForSingleCore(); } @@ -960,4 +1013,12 @@ void KernelCore::SetIsPhantomModeForSingleCore(bool value) { impl->SetIsPhantomModeForSingleCore(value); } +Core::System& KernelCore::System() { + return impl->system; +} + +const Core::System& KernelCore::System() const { + return impl->system; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a500e63bc..51aaccbc7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,8 +11,10 @@ #include <vector> #include "core/arm/cpu_interrupt_handler.h" #include "core/hardware_properties.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/memory_types.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/svc_common.h" namespace Core { class CPUInterruptHandler; @@ -27,20 +29,32 @@ struct EventType; namespace Kernel { -class ClientPort; +class KClientPort; class GlobalSchedulerContext; -class HandleTable; +class KAutoObjectWithListContainer; +class KClientSession; +class KEvent; +class KHandleTable; +class KLinkedListNode; class KMemoryManager; +class KPort; +class KProcess; class KResourceLimit; class KScheduler; +class KSession; class KSharedMemory; class KThread; +class KTransferMemory; +class KWritableEvent; class PhysicalCore; -class Process; class ServiceThread; class Synchronization; class TimeManager; +namespace Init { +struct KSlabResourceCounts; +} + template <typename T> class KSlabHeap; @@ -51,7 +65,7 @@ constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63}; /// Represents a single instance of the kernel. class KernelCore { private: - using NamedPortTable = std::unordered_map<std::string, std::shared_ptr<ClientPort>>; + using NamedPortTable = std::unordered_map<std::string, KClientPort*>; public: /// Constructs an instance of the kernel using the given System @@ -83,25 +97,28 @@ public: void Shutdown(); /// Retrieves a shared pointer to the system resource limit instance. - std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const; + const KResourceLimit* GetSystemResourceLimit() const; + + /// Retrieves a shared pointer to the system resource limit instance. + KResourceLimit* GetSystemResourceLimit(); /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. - std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; + KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. - void AppendNewProcess(std::shared_ptr<Process> process); + void AppendNewProcess(KProcess* process); /// Makes the given process the new current process. - void MakeCurrentProcess(Process* process); + void MakeCurrentProcess(KProcess* process); /// Retrieves a pointer to the current process. - Process* CurrentProcess(); + KProcess* CurrentProcess(); /// Retrieves a const pointer to the current process. - const Process* CurrentProcess() const; + const KProcess* CurrentProcess() const; /// Retrieves the list of processes. - const std::vector<std::shared_ptr<Process>>& GetProcessList() const; + const std::vector<KProcess*>& GetProcessList() const; /// Gets the sole instance of the global scheduler Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); @@ -143,6 +160,10 @@ public: const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + KAutoObjectWithListContainer& ObjectListContainer(); + + const KAutoObjectWithListContainer& ObjectListContainer() const; + std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts(); const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const; @@ -152,7 +173,7 @@ public: void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); /// Adds a port to the named port table - void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); + void AddNamedPort(std::string name, KClientPort* port); /// Finds a port within the named port table with the given name. NamedPortTable::iterator FindNamedPort(const std::string& name); @@ -225,9 +246,10 @@ public: /** * Creates an HLE service thread, which are used to execute service routines asynchronously. - * While these are allocated per ServerSession, these need to be owned and managed outside of - * ServerSession to avoid a circular dependency. - * @param name String name for the ServerSession creating this thread, used for debug purposes. + * While these are allocated per ServerSession, these need to be owned and managed outside + * of ServerSession to avoid a circular dependency. + * @param name String name for the ServerSession creating this thread, used for debug + * purposes. * @returns The a weak pointer newly created service thread. */ std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); @@ -243,9 +265,45 @@ public: bool IsPhantomModeForSingleCore() const; void SetIsPhantomModeForSingleCore(bool value); + Core::System& System(); + const Core::System& System() const; + + /// Gets the slab heap for the specified kernel object type. + template <typename T> + KSlabHeap<T>& SlabHeap() { + if constexpr (std::is_same_v<T, KClientSession>) { + return slab_heap_container->client_session; + } else if constexpr (std::is_same_v<T, KEvent>) { + return slab_heap_container->event; + } else if constexpr (std::is_same_v<T, KLinkedListNode>) { + return slab_heap_container->linked_list_node; + } else if constexpr (std::is_same_v<T, KPort>) { + return slab_heap_container->port; + } else if constexpr (std::is_same_v<T, KProcess>) { + return slab_heap_container->process; + } else if constexpr (std::is_same_v<T, KResourceLimit>) { + return slab_heap_container->resource_limit; + } else if constexpr (std::is_same_v<T, KSession>) { + return slab_heap_container->session; + } else if constexpr (std::is_same_v<T, KSharedMemory>) { + return slab_heap_container->shared_memory; + } else if constexpr (std::is_same_v<T, KThread>) { + return slab_heap_container->thread; + } else if constexpr (std::is_same_v<T, KTransferMemory>) { + return slab_heap_container->transfer_memory; + } else if constexpr (std::is_same_v<T, KWritableEvent>) { + return slab_heap_container->writeable_event; + } + } + + /// Gets the current slab resource counts. + Init::KSlabResourceCounts& SlabResourceCounts(); + + /// Gets the current slab resource counts. + const Init::KSlabResourceCounts& SlabResourceCounts() const; + private: - friend class Object; - friend class Process; + friend class KProcess; friend class KThread; /// Creates a new object ID, incrementing the internal object ID counter. @@ -261,14 +319,33 @@ private: u64 CreateNewThreadID(); /// Provides a reference to the global handle table. - Kernel::HandleTable& GlobalHandleTable(); + KHandleTable& GlobalHandleTable(); /// Provides a const reference to the global handle table. - const Kernel::HandleTable& GlobalHandleTable() const; + const KHandleTable& GlobalHandleTable() const; struct Impl; std::unique_ptr<Impl> impl; + bool exception_exited{}; + +private: + /// Helper to encapsulate all slab heaps in a single heap allocated container + struct SlabHeapContainer { + KSlabHeap<KClientSession> client_session; + KSlabHeap<KEvent> event; + KSlabHeap<KLinkedListNode> linked_list_node; + KSlabHeap<KPort> port; + KSlabHeap<KProcess> process; + KSlabHeap<KResourceLimit> resource_limit; + KSlabHeap<KSession> session; + KSlabHeap<KSharedMemory> shared_memory; + KSlabHeap<KThread> thread; + KSlabHeap<KTransferMemory> transfer_memory; + KSlabHeap<KWritableEvent> writeable_event; + }; + + std::unique_ptr<SlabHeapContainer> slab_heap_container; }; } // namespace Kernel diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp deleted file mode 100644 index d7f40c403..000000000 --- a/src/core/hle/kernel/object.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" - -namespace Kernel { - -Object::Object(KernelCore& kernel_) - : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {} -Object::Object(KernelCore& kernel_, std::string&& name_) - : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {} -Object::~Object() = default; - -bool Object::IsWaitable() const { - switch (GetHandleType()) { - case HandleType::ReadableEvent: - case HandleType::Thread: - case HandleType::Process: - case HandleType::ServerPort: - case HandleType::ServerSession: - return true; - - case HandleType::Unknown: - case HandleType::Event: - case HandleType::WritableEvent: - case HandleType::SharedMemory: - case HandleType::TransferMemory: - case HandleType::ResourceLimit: - case HandleType::ClientPort: - case HandleType::ClientSession: - case HandleType::Session: - return false; - } - - UNREACHABLE(); - return false; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h deleted file mode 100644 index 501e58b33..000000000 --- a/src/core/hle/kernel/object.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <atomic> -#include <memory> -#include <string> - -#include "common/common_types.h" - -namespace Kernel { - -class KernelCore; - -using Handle = u32; - -enum class HandleType : u32 { - Unknown, - Event, - WritableEvent, - ReadableEvent, - SharedMemory, - TransferMemory, - Thread, - Process, - ResourceLimit, - ClientPort, - ServerPort, - ClientSession, - ServerSession, - Session, -}; - -class Object : NonCopyable, public std::enable_shared_from_this<Object> { -public: - explicit Object(KernelCore& kernel_); - explicit Object(KernelCore& kernel_, std::string&& name_); - virtual ~Object(); - - /// Returns a unique identifier for the object. For debugging purposes only. - u32 GetObjectId() const { - return object_id.load(std::memory_order_relaxed); - } - - virtual std::string GetTypeName() const { - return "[BAD KERNEL OBJECT TYPE]"; - } - virtual std::string GetName() const { - return name; - } - virtual HandleType GetHandleType() const = 0; - - void Close() { - // TODO(bunnei): This is a placeholder to decrement the reference count, which we will use - // when we implement KAutoObject instead of using shared_ptr. - } - - /** - * Check if a thread can wait on the object - * @return True if a thread can wait on the object, otherwise false - */ - bool IsWaitable() const; - - virtual void Finalize() = 0; - -protected: - /// The kernel instance this object was created under. - KernelCore& kernel; - -private: - std::atomic<u32> object_id{0}; - std::string name; -}; - -template <typename T> -std::shared_ptr<T> SharedFrom(T* raw) { - if (raw == nullptr) - return nullptr; - return std::static_pointer_cast<T>(raw->shared_from_this()); -} - -/** - * Attempts to downcast the given Object pointer to a pointer to T. - * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T. - */ -template <typename T> -inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) { - if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { - return std::static_pointer_cast<T>(object); - } - return nullptr; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 1006ee50c..fcb8b1ea5 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -6,7 +6,7 @@ #include "common/bit_util.h" #include "common/logging/log.h" -#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/svc_results.h" @@ -99,7 +99,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() { interrupt_capabilities.set(); // Allow using the maximum possible amount of handles - handle_table_size = static_cast<s32>(HandleTable::MAX_COUNT); + handle_table_size = static_cast<s32>(KHandleTable::MaxTableSize); // Allow all debugging capabilities. is_debuggable = true; @@ -159,7 +159,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s const auto type = GetCapabilityType(flag); if (type == CapabilityType::Unset) { - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } // Bail early on ignorable entries, as one would expect, @@ -202,7 +202,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s } LOG_ERROR(Kernel, "Invalid capability type! type={}", type); - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } void ProcessCapabilities::Clear() { @@ -225,7 +225,7 @@ ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) { if (priority_mask != 0 || core_mask != 0) { LOG_ERROR(Kernel, "Core or priority mask are not zero! priority_mask={}, core_mask={}", priority_mask, core_mask); - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } const u32 core_num_min = (flags >> 16) & 0xFF; @@ -329,7 +329,7 @@ ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) { const u32 reserved = flags >> 17; if (reserved != 0) { LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); - return ResultReservedValue; + return ResultReservedUsed; } program_type = static_cast<ProgramType>((flags >> 14) & 0b111); @@ -349,7 +349,7 @@ ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) { LOG_ERROR(Kernel, "Kernel version is non zero or flags are too small! major_version={}, flags={}", major_version, flags); - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } kernel_version = flags; @@ -360,7 +360,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) { const u32 reserved = flags >> 26; if (reserved != 0) { LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); - return ResultReservedValue; + return ResultReservedUsed; } handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF); @@ -371,7 +371,7 @@ ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) { const u32 reserved = flags >> 19; if (reserved != 0) { LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); - return ResultReservedValue; + return ResultReservedUsed; } is_debuggable = (flags & 0x20000) != 0; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp deleted file mode 100644 index 5d17346ad..000000000 --- a/src/core/hle/kernel/server_port.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <tuple> -#include "common/assert.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel { - -ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} -ServerPort::~ServerPort() = default; - -ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { - if (pending_sessions.empty()) { - return ResultNotFound; - } - - auto session = std::move(pending_sessions.back()); - pending_sessions.pop_back(); - return MakeResult(std::move(session)); -} - -void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) { - pending_sessions.push_back(std::move(pending_session)); - if (pending_sessions.size() == 1) { - NotifyAvailable(); - } -} - -bool ServerPort::IsSignaled() const { - return !pending_sessions.empty(); -} - -ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, - std::string name) { - std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel); - std::shared_ptr<ClientPort> client_port = std::make_shared<ClientPort>(kernel); - - server_port->name = name + "_Server"; - client_port->name = name + "_Client"; - client_port->server_port = server_port; - client_port->max_sessions = max_sessions; - client_port->active_sessions = 0; - - return std::make_pair(std::move(server_port), std::move(client_port)); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h deleted file mode 100644 index 29b4f2509..000000000 --- a/src/core/hle/kernel/server_port.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> -#include <utility> -#include <vector> -#include "common/common_types.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class ClientPort; -class KernelCore; -class ServerSession; -class SessionRequestHandler; - -class ServerPort final : public KSynchronizationObject { -public: - explicit ServerPort(KernelCore& kernel); - ~ServerPort() override; - - using HLEHandler = std::shared_ptr<SessionRequestHandler>; - using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>; - - /** - * Creates a pair of ServerPort and an associated ClientPort. - * - * @param kernel The kernel instance to create the port pair under. - * @param max_sessions Maximum number of sessions to the port - * @param name Optional name of the ports - * @return The created port tuple - */ - static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions, - std::string name = "UnknownPort"); - - std::string GetTypeName() const override { - return "ServerPort"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - /** - * Accepts a pending incoming connection on this port. If there are no pending sessions, will - * return ERR_NO_PENDING_SESSIONS. - */ - ResultVal<std::shared_ptr<ServerSession>> Accept(); - - /// Whether or not this server port has an HLE handler available. - bool HasHLEHandler() const { - return hle_handler != nullptr; - } - - /// Gets the HLE handler for this port. - HLEHandler GetHLEHandler() const { - return hle_handler; - } - - /** - * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port - * will inherit a reference to this handler. - */ - void SetHleHandler(HLEHandler hle_handler_) { - hle_handler = std::move(hle_handler_); - } - - /// Appends a ServerSession to the collection of ServerSessions - /// waiting to be accepted by this port. - void AppendPendingSession(std::shared_ptr<ServerSession> pending_session); - - bool IsSignaled() const override; - - void Finalize() override {} - -private: - /// ServerSessions waiting to be accepted by the port - std::vector<std::shared_ptr<ServerSession>> pending_sessions; - - /// This session's HLE request handler template (optional) - /// ServerSessions created from this port inherit a reference to this handler. - HLEHandler hle_handler; - - /// Name of the port (optional) - std::string name; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index ee46f3e21..04be8a502 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -13,8 +13,8 @@ #include "common/scope_exit.h" #include "common/thread.h" #include "core/core.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/lock.h" #include "video_core/renderer_base.h" @@ -26,7 +26,7 @@ public: explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); ~Impl(); - void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); + void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); private: std::vector<std::thread> threads; @@ -69,18 +69,27 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std }); } -void ServiceThread::Impl::QueueSyncRequest(ServerSession& session, +void ServiceThread::Impl::QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context) { { std::unique_lock lock{queue_mutex}; - // ServerSession owns the service thread, so we cannot caption a strong pointer here in the - // event that the ServerSession is terminated. - std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)}; - requests.emplace([weak_ptr, context{std::move(context)}]() { - if (auto strong_ptr = weak_ptr.lock()) { - strong_ptr->CompleteSyncRequest(*context); + // Open a reference to the session to ensure it is not closes while the service request + // completes asynchronously. + session.Open(); + + requests.emplace([session_ptr{&session}, context{std::move(context)}]() { + // Close the reference. + SCOPE_EXIT({ session_ptr->Close(); }); + + // If the session has been closed, we are done. + if (session_ptr->IsServerClosed()) { + return; } + + // Complete the service request. + KScopedAutoObject server_session{&session_ptr->GetServerSession()}; + server_session->CompleteSyncRequest(*context); }); } condition.notify_one(); @@ -102,7 +111,7 @@ ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const ServiceThread::~ServiceThread() = default; -void ServiceThread::QueueSyncRequest(ServerSession& session, +void ServiceThread::QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context) { impl->QueueSyncRequest(session, std::move(context)); } diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h index 025ab8fb5..6a7fd7c56 100644 --- a/src/core/hle/kernel/service_thread.h +++ b/src/core/hle/kernel/service_thread.h @@ -11,14 +11,14 @@ namespace Kernel { class HLERequestContext; class KernelCore; -class ServerSession; +class KSession; class ServiceThread final { public: explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); ~ServiceThread(); - void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); + void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); private: class Impl; diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp deleted file mode 100644 index 8830d4e91..000000000 --- a/src/core/hle/kernel/session.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" - -namespace Kernel { - -Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {} -Session::~Session() { - // Release reserved resource when the Session pair was created. - kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1); -} - -Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { - // Reserve a new session from the resource limit. - KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(), - LimitableResource::Sessions); - ASSERT(session_reservation.Succeeded()); - auto session{std::make_shared<Session>(kernel)}; - auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; - auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; - - session->name = std::move(name); - session->client = client_session; - session->server = server_session; - - session_reservation.Commit(); - return std::make_pair(std::move(client_session), std::move(server_session)); -} - -bool Session::IsSignaled() const { - UNIMPLEMENTED(); - return true; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h deleted file mode 100644 index fa3c5651a..000000000 --- a/src/core/hle/kernel/session.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> -#include <utility> - -#include "core/hle/kernel/k_synchronization_object.h" - -namespace Kernel { - -class ClientSession; -class ServerSession; - -/** - * Parent structure to link the client and server endpoints of a session with their associated - * client port. - */ -class Session final : public KSynchronizationObject { -public: - explicit Session(KernelCore& kernel); - ~Session() override; - - using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>; - - static SessionPair Create(KernelCore& kernel, std::string name = "Unknown"); - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Session; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - bool IsSignaled() const override; - - void Finalize() override {} - - std::shared_ptr<ClientSession> Client() { - if (auto result{client.lock()}) { - return result; - } - return {}; - } - - std::shared_ptr<ServerSession> Server() { - if (auto result{server.lock()}) { - return result; - } - return {}; - } - -private: - std::string name; - std::weak_ptr<ClientSession> client; - std::weak_ptr<ServerSession> server; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h new file mode 100644 index 000000000..0c5995db0 --- /dev/null +++ b/src/core/hle/kernel/slab_helpers.h @@ -0,0 +1,148 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/intrusive_red_black_tree.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_auto_object_container.h" +#include "core/hle/kernel/k_light_lock.h" +#include "core/hle/kernel/k_slab_heap.h" +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +template <class Derived> +class KSlabAllocated { +public: + constexpr KSlabAllocated() = default; + + size_t GetSlabIndex(KernelCore& kernel) const { + return kernel.SlabHeap<Derived>().GetIndex(static_cast<const Derived*>(this)); + } + +public: + static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) { + kernel.SlabHeap<Derived>().Initialize(memory, memory_size); + } + + static Derived* Allocate(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().Allocate(); + } + + static void Free(KernelCore& kernel, Derived* obj) { + kernel.SlabHeap<Derived>().Free(obj); + } + + static size_t GetObjectSize(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetObjectSize(); + } + + static size_t GetSlabHeapSize(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetSlabHeapSize(); + } + + static size_t GetPeakIndex(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetPeakIndex(); + } + + static uintptr_t GetSlabHeapAddress(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetSlabHeapAddress(); + } + + static size_t GetNumRemaining(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetNumRemaining(); + } +}; + +template <typename Derived, typename Base> +class KAutoObjectWithSlabHeapAndContainer : public Base { + static_assert(std::is_base_of<KAutoObjectWithList, Base>::value); + +private: + static Derived* Allocate(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().AllocateWithKernel(kernel); + } + + static void Free(KernelCore& kernel, Derived* obj) { + kernel.SlabHeap<Derived>().Free(obj); + } + +public: + KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {} + virtual ~KAutoObjectWithSlabHeapAndContainer() {} + + virtual void Destroy() override { + const bool is_initialized = this->IsInitialized(); + uintptr_t arg = 0; + if (is_initialized) { + kernel.ObjectListContainer().Unregister(this); + arg = this->GetPostDestroyArgument(); + this->Finalize(); + } + Free(kernel, static_cast<Derived*>(this)); + if (is_initialized) { + Derived::PostDestroy(arg); + } + } + + virtual bool IsInitialized() const { + return true; + } + virtual uintptr_t GetPostDestroyArgument() const { + return 0; + } + + size_t GetSlabIndex() const { + return SlabHeap<Derived>(kernel).GetObjectIndex(static_cast<const Derived*>(this)); + } + +public: + static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) { + kernel.SlabHeap<Derived>().Initialize(memory, memory_size); + kernel.ObjectListContainer().Initialize(); + } + + static Derived* Create(KernelCore& kernel) { + Derived* obj = Allocate(kernel); + if (obj != nullptr) { + KAutoObject::Create(obj); + } + return obj; + } + + static void Register(KernelCore& kernel, Derived* obj) { + return kernel.ObjectListContainer().Register(obj); + } + + static size_t GetObjectSize(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetObjectSize(); + } + + static size_t GetSlabHeapSize(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetSlabHeapSize(); + } + + static size_t GetPeakIndex(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetPeakIndex(); + } + + static uintptr_t GetSlabHeapAddress(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetSlabHeapAddress(); + } + + static size_t GetNumRemaining(KernelCore& kernel) { + return kernel.SlabHeap<Derived>().GetNumRemaining(); + } + +protected: + KernelCore& kernel; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index bebb86154..52011be9c 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -21,15 +21,16 @@ #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/cpu_manager.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" @@ -38,16 +39,15 @@ #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_types.h" #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/time_manager.h" -#include "core/hle/kernel/transfer_memory.h" #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -113,7 +113,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, LOG_ERROR(Kernel_SVC, "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", dst_addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (manager.IsInsideHeapRegion(dst_addr, size)) { @@ -121,7 +121,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, "Destination does not fit within the heap region, addr=0x{:016X}, " "size=0x{:016X}", dst_addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (manager.IsInsideAliasRegion(dst_addr, size)) { @@ -129,7 +129,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, "Destination does not fit within the map region, addr=0x{:016X}, " "size=0x{:016X}", dst_addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return RESULT_SUCCESS; @@ -141,38 +141,6 @@ enum class ResourceLimitValueType { PeakValue, }; -ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, - u32 resource_type, ResourceLimitValueType value_type) { - std::lock_guard lock{HLE::g_hle_lock}; - const auto type = static_cast<LimitableResource>(resource_type); - if (!IsValidResourceType(type)) { - LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); - return ResultInvalidEnumValue; - } - - const auto* const current_process = system.Kernel().CurrentProcess(); - ASSERT(current_process != nullptr); - - const auto resource_limit_object = - current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); - if (!resource_limit_object) { - LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", - resource_limit); - return ResultInvalidHandle; - } - - switch (value_type) { - case ResourceLimitValueType::CurrentValue: - return MakeResult(resource_limit_object->GetCurrentValue(type)); - case ResourceLimitValueType::LimitValue: - return MakeResult(resource_limit_object->GetLimitValue(type)); - case ResourceLimitValueType::PeakValue: - return MakeResult(resource_limit_object->GetPeakValue(type)); - default: - LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type); - return ResultInvalidEnumValue; - } -} } // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. @@ -291,11 +259,8 @@ static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr } /// Connect to an OS service given the port name, returns the handle to the port to out -static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, - VAddr port_name_address) { - std::lock_guard lock{HLE::g_hle_lock}; +static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { auto& memory = system.Memory(); - if (!memory.IsValidVirtualAddress(port_name_address)) { LOG_ERROR(Kernel_SVC, "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", @@ -314,21 +279,33 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); + // Get the current handle table. auto& kernel = system.Kernel(); + auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + + // Find the client port. const auto it = kernel.FindNamedPort(port_name); if (!kernel.IsValidNamedPort(it)) { LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); return ResultNotFound; } + auto port = it->second; - auto client_port = it->second; + // Reserve a handle for the port. + // NOTE: Nintendo really does write directly to the output handle here. + R_TRY(handle_table.Reserve(out)); + auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); }); - std::shared_ptr<ClientSession> client_session; - CASCADE_RESULT(client_session, client_port->Connect()); + // Create a session. + KClientSession* session{}; + R_TRY(port->CreateSession(std::addressof(session))); - // Return the client session - auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); + // Register the session in the table, close the extra reference. + handle_table.Register(*out, session); + session->Close(); + + // We succeeded. + handle_guard.Cancel(); return RESULT_SUCCESS; } @@ -340,14 +317,12 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { + auto& kernel = system.Kernel(); - const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle); - if (!session) { - LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); - return ResultInvalidHandle; - } + KScopedAutoObject session = + kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); auto thread = kernel.CurrentScheduler()->GetCurrentThread(); @@ -355,7 +330,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { KScopedSchedulerLock lock(kernel); thread->SetState(ThreadState::Waiting); thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); - session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); + session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); } KSynchronizationObject* dummy{}; @@ -368,18 +343,13 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { /// Get the ID for the specified thread. static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); - // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Get the thread's id. - *out_thread_id = thread->GetThreadID(); + *out_thread_id = thread->GetId(); return RESULT_SUCCESS; } @@ -395,110 +365,101 @@ static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, } /// Gets the ID of the specified process or a specified thread's owning process. -static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { +static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<Process> process = handle_table.Get<Process>(handle); - if (process) { - *process_id = process->GetProcessID(); - return RESULT_SUCCESS; + // Get the object from the handle table. + KScopedAutoObject obj = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>( + static_cast<Handle>(handle)); + R_UNLESS(obj.IsNotNull(), ResultInvalidHandle); + + // Get the process from the object. + KProcess* process = nullptr; + if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) { + // The object is a process, so we can use it directly. + process = p; + } else if (KThread* t = obj->DynamicCast<KThread*>(); t != nullptr) { + // The object is a thread, so we want to use its parent. + process = reinterpret_cast<KThread*>(obj.GetPointerUnsafe())->GetOwnerProcess(); + } else { + // TODO(bunnei): This should also handle debug objects before returning. + UNIMPLEMENTED_MSG("Debug objects not implemented"); } - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); - if (thread) { - const Process* const owner_process = thread->GetOwnerProcess(); - if (!owner_process) { - LOG_ERROR(Kernel_SVC, "Non-existent owning process encountered."); - return ResultInvalidHandle; - } - - *process_id = owner_process->GetProcessID(); - return RESULT_SUCCESS; - } + // Make sure the target process exists. + R_UNLESS(process != nullptr, ResultInvalidHandle); - // NOTE: This should also handle debug objects before returning. + // Get the process id. + *out_process_id = process->GetId(); - LOG_ERROR(Kernel_SVC, "Handle does not exist, handle=0x{:08X}", handle); return ResultInvalidHandle; } -static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, - Handle handle) { - u64 process_id{}; - const auto result = GetProcessId(system, &process_id, handle); - *process_id_low = static_cast<u32>(process_id); - *process_id_high = static_cast<u32>(process_id >> 32); +static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low, + u32* out_process_id_high, Handle handle) { + u64 out_process_id{}; + const auto result = GetProcessId(system, &out_process_id, handle); + *out_process_id_low = static_cast<u32>(out_process_id); + *out_process_id_high = static_cast<u32>(out_process_id >> 32); return result; } /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, - u64 handle_count, s64 nano_seconds) { - LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", - handles_address, handle_count, nano_seconds); + u64 num_handles, s64 nano_seconds) { + LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}", + handles_address, num_handles, nano_seconds); - auto& memory = system.Memory(); - if (!memory.IsValidVirtualAddress(handles_address)) { - LOG_ERROR(Kernel_SVC, - "Handle address is not a valid virtual address, handle_address=0x{:016X}", - handles_address); - return ResultInvalidPointer; - } - - static constexpr u64 MaxHandles = 0x40; - - if (handle_count > MaxHandles) { - LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}", - MaxHandles, handle_count); - return ResultOutOfRange; - } + // Ensure number of handles is valid. + R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); auto& kernel = system.Kernel(); - std::vector<KSynchronizationObject*> objects(handle_count); + std::vector<KSynchronizationObject*> objs(num_handles); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + Handle* handles = system.Memory().GetPointer<Handle>(handles_address); - for (u64 i = 0; i < handle_count; ++i) { - const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); - const auto object = handle_table.Get<KSynchronizationObject>(handle); + // Copy user handles. + if (num_handles > 0) { + // Convert the handles to objects. + R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, + num_handles), + ResultInvalidHandle); + } - if (object == nullptr) { - LOG_ERROR(Kernel_SVC, "Object is a nullptr"); - return ResultInvalidHandle; + // Ensure handles are closed when we're done. + SCOPE_EXIT({ + for (u64 i = 0; i < num_handles; ++i) { + objs[i]->Close(); } + }); - objects[i] = object.get(); - } - return KSynchronizationObject::Wait(kernel, index, objects.data(), - static_cast<s32>(objects.size()), nano_seconds); + return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()), + nano_seconds); } static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, - s32 handle_count, u32 timeout_high, s32* index) { + s32 num_handles, u32 timeout_high, s32* index) { const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; - return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); + return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds); } /// Resumes a thread waiting on WaitSynchronization -static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); +static ResultCode CancelSynchronization(Core::System& system, Handle handle) { + LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>( + static_cast<Handle>(handle)); // Cancel the thread's wait. thread->WaitCancel(); return RESULT_SUCCESS; } -static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { - return CancelSynchronization(system, thread_handle); +static ResultCode CancelSynchronization32(Core::System& system, Handle handle) { + return CancelSynchronization(system, handle); } /// Attempts to locks a mutex @@ -678,7 +639,7 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) { } /// Gets system/memory information for the current process -static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, +static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle, u64 info_sub_id) { std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, @@ -744,10 +705,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return ResultInvalidEnumValue; } - const auto& current_process_handle_table = - system.Kernel().CurrentProcess()->GetHandleTable(); - const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle)); - if (!process) { + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", info_id, info_sub_id, handle); return ResultInvalidHandle; @@ -851,21 +811,19 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return ResultInvalidCombination; } - Process* const current_process = system.Kernel().CurrentProcess(); - HandleTable& handle_table = current_process->GetHandleTable(); + KProcess* const current_process = system.Kernel().CurrentProcess(); + KHandleTable& handle_table = current_process->GetHandleTable(); const auto resource_limit = current_process->GetResourceLimit(); if (!resource_limit) { - *result = KernelHandle::InvalidHandle; + *result = Svc::InvalidHandle; // Yes, the kernel considers this a successful operation. return RESULT_SUCCESS; } - const auto table_result = handle_table.Create(resource_limit); - if (table_result.Failed()) { - return table_result.Code(); - } + Handle handle{}; + R_TRY(handle_table.Add(&handle, resource_limit)); - *result = *table_result; + *result = handle; return RESULT_SUCCESS; } @@ -876,9 +834,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return ResultInvalidHandle; } - if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { + if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) { LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", - Process::RANDOM_ENTROPY_SIZE, info_sub_id); + KProcess::RANDOM_ENTROPY_SIZE, info_sub_id); return ResultInvalidCombination; } @@ -899,9 +857,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return ResultInvalidCombination; } - const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>( - static_cast<Handle>(handle)); - if (!thread) { + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>( + static_cast<Handle>(handle)); + if (thread.IsNull()) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", static_cast<Handle>(handle)); return ResultInvalidHandle; @@ -910,7 +869,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha const auto& core_timing = system.CoreTiming(); const auto& scheduler = *system.Kernel().CurrentScheduler(); const auto* const current_thread = scheduler.GetCurrentThread(); - const bool same_thread = current_thread == thread.get(); + const bool same_thread = current_thread == thread.GetPointerUnsafe(); const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); u64 out_ticks = 0; @@ -966,10 +925,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) if (!(addr < addr + size)) { LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } - Process* const current_process{system.Kernel().CurrentProcess()}; + KProcess* const current_process{system.Kernel().CurrentProcess()}; auto& page_table{current_process->PageTable()}; if (current_process->GetSystemResourceSize() == 0) { @@ -981,14 +940,14 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) LOG_ERROR(Kernel_SVC, "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (page_table.IsOutsideAliasRegion(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.MapPhysicalMemory(addr, size); @@ -1020,10 +979,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size if (!(addr < addr + size)) { LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } - Process* const current_process{system.Kernel().CurrentProcess()}; + KProcess* const current_process{system.Kernel().CurrentProcess()}; auto& page_table{current_process->PageTable()}; if (current_process->GetSystemResourceSize() == 0) { @@ -1035,14 +994,14 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size LOG_ERROR(Kernel_SVC, "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (page_table.IsOutsideAliasRegion(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.UnmapPhysicalMemory(addr, size); @@ -1062,37 +1021,19 @@ static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; }; - if (!IsValidThreadActivity(thread_activity)) { - LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})", - thread_activity); - return ResultInvalidEnumValue; - } + R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue); // Get the thread from its handle. - auto& kernel = system.Kernel(); - const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Check that the activity is being set on a non-current thread for the current process. - if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { - LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); - return ResultInvalidHandle; - } - if (thread.get() == GetCurrentThreadPointer(kernel)) { - LOG_ERROR(Kernel_SVC, "Thread is busy"); - return ResultBusy; - } + R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle); + R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy); // Set the activity. - const auto set_result = thread->SetActivity(thread_activity); - if (set_result.IsError()) { - LOG_ERROR(Kernel_SVC, "Failed to set thread activity."); - return set_result; - } + R_TRY(thread->SetActivity(thread_activity)); return RESULT_SUCCESS; } @@ -1107,36 +1048,55 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, thread_handle); + auto& kernel = system.Kernel(); + // Get the thread from its handle. - const auto* current_process = system.Kernel().CurrentProcess(); - const std::shared_ptr<KThread> thread = - current_process->GetHandleTable().Get<KThread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Require the handle be to a non-current thread in the current process. - if (thread->GetOwnerProcess() != current_process) { - LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); - return ResultInvalidHandle; - } - if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { - LOG_ERROR(Kernel_SVC, "Current thread is busy."); - return ResultBusy; - } + const auto* current_process = kernel.CurrentProcess(); + R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId); - // Get the thread context. - std::vector<u8> context; - const auto context_result = thread->GetThreadContext3(context); - if (context_result.IsError()) { - LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", - context_result.raw); - return context_result; - } + // Verify that the thread isn't terminated. + R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested); + + /// Check that the thread is not the current one. + /// NOTE: Nintendo does not check this, and thus the following loop will deadlock. + R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId); + + // Try to get the thread context until the thread isn't current on any core. + while (true) { + KScopedSchedulerLock sl{kernel}; - // Copy the thread context to user space. - system.Memory().WriteBlock(out_context, context.data(), context.size()); + // TODO(bunnei): Enforce that thread is suspended for debug here. + + // If the thread's raw state isn't runnable, check if it's current on some core. + if (thread->GetRawState() != ThreadState::Runnable) { + bool current = false; + for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { + if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) { + current = true; + } + break; + } + + // If the thread is current, retry until it isn't. + if (current) { + continue; + } + } + + // Get the thread context. + std::vector<u8> context; + R_TRY(thread->GetThreadContext3(context)); + + // Copy the thread context to user space. + system.Memory().WriteBlock(out_context, context.data(), context.size()); + + return RESULT_SUCCESS; + } return RESULT_SUCCESS; } @@ -1150,12 +1110,9 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han LOG_TRACE(Kernel_SVC, "called"); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Get the thread's priority. *out_priority = thread->GetPriority(); @@ -1167,30 +1124,26 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, H } /// Sets the priority for the specified thread -static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { - LOG_TRACE(Kernel_SVC, "called"); +static ResultCode SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) { + // Get the current process. + KProcess& process = *system.Kernel().CurrentProcess(); // Validate the priority. - if (HighestThreadPriority > priority || priority > LowestThreadPriority) { - LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); - return ResultInvalidPriority; - } + R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority, + ResultInvalidPriority); + R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Set the thread priority. thread->SetBasePriority(priority); return RESULT_SUCCESS; } -static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { - return SetThreadPriority(system, handle, priority); +static ResultCode SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) { + return SetThreadPriority(system, thread_handle, priority); } /// Get which CPU core is executing the current thread @@ -1203,82 +1156,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) { return GetCurrentProcessorNumber(system); } -static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, - u64 size, u32 permissions) { - std::lock_guard lock{HLE::g_hle_lock}; +constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { + switch (perm) { + case Svc::MemoryPermission::Read: + case Svc::MemoryPermission::ReadWrite: + return true; + default: + return false; + } +} + +constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { + return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; +} + +static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, + u64 size, Svc::MemoryPermission map_perm) { LOG_TRACE(Kernel_SVC, "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", - shared_memory_handle, addr, size, permissions); + shmem_handle, address, size, map_perm); - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); - return ResultInvalidAddress; - } + // Validate the address/size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is 0"); - return ResultInvalidSize; - } + // Validate the permission. + R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); - return ResultInvalidSize; - } + // Get the current process. + auto& process = *system.Kernel().CurrentProcess(); + auto& page_table = process.PageTable(); - if (!IsValidAddressRange(addr, size)) { - LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", - addr, size); - return ResultInvalidCurrentMemory; - } + // Get the shared memory. + KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); + R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); - const auto permission_type = static_cast<MemoryPermission>(permissions); - if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { - LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", - permissions); - return ResultInvalidMemoryPermissions; - } + // Verify that the mapping is in range. + R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); - auto* const current_process{system.Kernel().CurrentProcess()}; - auto& page_table{current_process->PageTable()}; + // Add the shared memory to the process. + R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size)); - if (page_table.IsInvalidRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Addr does not fit within the valid region, addr=0x{:016X}, " - "size=0x{:016X}", - addr, size); - return ResultInvalidMemoryRange; - } + // Ensure that we clean up the shared memory if we fail to map it. + auto guard = + SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); }); - if (page_table.IsInsideHeapRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Addr does not fit within the heap region, addr=0x{:016X}, " - "size=0x{:016X}", - addr, size); - return ResultInvalidMemoryRange; - } + // Map the shared memory. + R_TRY(shmem->Map(process, address, size, map_perm)); - if (page_table.IsInsideAliasRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Address does not fit within the map region, addr=0x{:016X}, " - "size=0x{:016X}", - addr, size); - return ResultInvalidMemoryRange; - } + // We succeeded. + guard.Cancel(); + return RESULT_SUCCESS; +} - auto shared_memory{current_process->GetHandleTable().Get<KSharedMemory>(shared_memory_handle)}; - if (!shared_memory) { - LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", - shared_memory_handle); - return ResultInvalidHandle; - } +static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, + u32 size, Svc::MemoryPermission map_perm) { + return MapSharedMemory(system, shmem_handle, address, size, map_perm); +} + +static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, + u64 size) { + // Validate the address/size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + + // Get the current process. + auto& process = *system.Kernel().CurrentProcess(); + auto& page_table = process.PageTable(); + + // Get the shared memory. + KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); + R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); - return shared_memory->Map(*current_process, addr, size, - static_cast<KMemoryPermission>(permission_type)); + // Verify that the mapping is in range. + R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); + + // Unmap the shared memory. + R_TRY(shmem->Unmap(process, address, size)); + + // Remove the shared memory from the process. + process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); + + return RESULT_SUCCESS; } -static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, - u32 size, u32 permissions) { - return MapSharedMemory(system, shared_memory_handle, addr, size, permissions); +static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, + u32 size) { + return UnmapSharedMemory(system, shmem_handle, address, size); } static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, @@ -1287,8 +1255,8 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); return ResultInvalidHandle; @@ -1369,8 +1337,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto process = handle_table.Get<Process>(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", process_handle); return ResultInvalidHandle; @@ -1390,7 +1358,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " "size=0x{:016X}).", dst_address, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.MapProcessCodeMemory(dst_address, src_address, size); @@ -1437,8 +1405,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto process = handle_table.Get<Process>(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", process_handle); return ResultInvalidHandle; @@ -1458,7 +1426,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " "size=0x{:016X}).", dst_address, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); @@ -1483,7 +1451,7 @@ static void ExitProcess32(Core::System& system) { ExitProcess(system); } -static constexpr bool IsValidCoreId(int32_t core_id) { +static constexpr bool IsValidVirtualCoreId(int32_t core_id) { return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); } @@ -1503,7 +1471,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e } // Validate arguments. - if (!IsValidCoreId(core_id)) { + if (!IsValidVirtualCoreId(core_id)) { LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); return ResultInvalidCoreId; } @@ -1521,35 +1489,42 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e return ResultInvalidPriority; } + // Reserve a new thread from the process resource limit (waiting up to 100ms). KScopedResourceReservation thread_reservation( kernel.CurrentProcess(), LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000); if (!thread_reservation.Succeeded()) { LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } - std::shared_ptr<KThread> thread; - { - KScopedLightLock lk{process.GetStateLock()}; - CASCADE_RESULT(thread, - KThread::CreateUserThread(system, ThreadType::User, "", entry_point, - priority, arg, core_id, stack_bottom, &process)); + // Create the thread. + KThread* thread = KThread::Create(kernel); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached."); + return ResultOutOfResource; } + SCOPE_EXIT({ thread->Close(); }); - const auto new_thread_handle = process.GetHandleTable().Create(thread); - if (new_thread_handle.Failed()) { - LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", - new_thread_handle.Code().raw); - return new_thread_handle.Code(); + // Initialize the thread. + { + KScopedLightLock lk{process.GetStateLock()}; + R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom, + priority, core_id, &process)); } - *out_handle = *new_thread_handle; // Set the thread name for debugging purposes. - thread->SetName( - fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); + thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle)); + + // Commit the thread reservation. thread_reservation.Commit(); + // Register the new thread. + KThread::Register(kernel, thread); + + // Add the thread to the handle table. + R_TRY(process.GetHandleTable().Add(out_handle, thread)); + return RESULT_SUCCESS; } @@ -1563,21 +1538,15 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Try to start the thread. - const auto run_result = thread->Run(); - if (run_result.IsError()) { - LOG_ERROR(Kernel_SVC, - "Unable to successfuly start thread (thread handle={:08X}, result={})", - thread_handle, run_result.raw); - return run_result; - } + R_TRY(thread->Run()); + + // If we succeeded, persist a reference to the thread. + thread->Open(); return RESULT_SUCCESS; } @@ -1591,7 +1560,7 @@ static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); - system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); + system.GlobalSchedulerContext().RemoveThread(current_thread); current_thread->Exit(); } @@ -1824,8 +1793,11 @@ static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) static ResultCode CloseHandle(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); - auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - return handle_table.Close(handle); + // Remove the handle. + R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle), + ResultInvalidHandle); + + return RESULT_SUCCESS; } static ResultCode CloseHandle32(Core::System& system, Handle handle) { @@ -1841,16 +1813,16 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { // Try to reset as readable event. { - auto readable_event = handle_table.Get<KReadableEvent>(handle); - if (readable_event) { + KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle); + if (readable_event.IsNotNull()) { return readable_event->Reset(); } } // Try to reset as process. { - auto process = handle_table.Get<Process>(handle); - if (process) { + KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); + if (process.IsNotNull()) { return process->Reset(); } } @@ -1864,65 +1836,68 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) { return ResetSignal(system, handle); } -/// Creates a TransferMemory object -static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, - u32 permissions) { - std::lock_guard lock{HLE::g_hle_lock}; - LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, - permissions); - - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr); - return ResultInvalidAddress; +static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { + switch (perm) { + case MemoryPermission::None: + case MemoryPermission::Read: + case MemoryPermission::ReadWrite: + return true; + default: + return false; } +} - if (!Common::Is4KBAligned(size) || size == 0) { - LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size); - return ResultInvalidAddress; - } +/// Creates a TransferMemory object +static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, + MemoryPermission map_perm) { + auto& kernel = system.Kernel(); - if (!IsValidAddressRange(addr, size)) { - LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", - addr, size); - return ResultInvalidCurrentMemory; - } + // Validate the size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); - const auto perms{static_cast<MemoryPermission>(permissions)}; - if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) { - LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", - permissions); - return ResultInvalidMemoryPermissions; - } + // Validate the permissions. + R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); + + // Get the current process and handle table. + auto& process = *kernel.CurrentProcess(); + auto& handle_table = process.GetHandleTable(); - auto& kernel = system.Kernel(); // Reserve a new transfer memory from the process resource limit. KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), LimitableResource::TransferMemory); - if (!trmem_reservation.Succeeded()) { - LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); - return ResultResourceLimitedExceeded; - } - auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, - static_cast<KMemoryPermission>(perms)); + R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached); - if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { - return reserve_result; - } + // Create the transfer memory. + KTransferMemory* trmem = KTransferMemory::Create(kernel); + R_UNLESS(trmem != nullptr, ResultOutOfResource); - auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const auto result{handle_table.Create(std::move(transfer_mem_handle))}; - if (result.Failed()) { - return result.Code(); - } + // Ensure the only reference is in the handle table when we're done. + SCOPE_EXIT({ trmem->Close(); }); + + // Ensure that the region is in range. + R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory); + + // Initialize the transfer memory. + R_TRY(trmem->Initialize(address, size, map_perm)); + + // Commit the reservation. trmem_reservation.Commit(); - *handle = *result; + // Register the transfer memory. + KTransferMemory::Register(kernel, trmem); + + // Add the transfer memory to the handle table. + R_TRY(handle_table.Add(out, trmem)); + return RESULT_SUCCESS; } -static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, - u32 permissions) { - return CreateTransferMemory(system, handle, addr, size, permissions); +static ResultCode CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size, + MemoryPermission map_perm) { + return CreateTransferMemory(system, out, address, size, map_perm); } static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, @@ -1930,19 +1905,12 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Get the core mask. - const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); - if (result.IsError()) { - LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw); - return result; - } + R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); return RESULT_SUCCESS; } @@ -1958,58 +1926,33 @@ static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, u64 affinity_mask) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", - thread_handle, core_id, affinity_mask); - - const auto& current_process = *system.Kernel().CurrentProcess(); - // Determine the core id/affinity mask. - if (core_id == Svc::IdealCoreUseProcessValue) { - core_id = current_process.GetIdealCoreId(); + if (core_id == IdealCoreUseProcessValue) { + core_id = system.Kernel().CurrentProcess()->GetIdealCoreId(); affinity_mask = (1ULL << core_id); } else { // Validate the affinity mask. - const u64 process_core_mask = current_process.GetCoreMask(); - if ((affinity_mask | process_core_mask) != process_core_mask) { - LOG_ERROR(Kernel_SVC, - "Affinity mask does match the process core mask (affinity mask={:016X}, core " - "mask={:016X})", - affinity_mask, process_core_mask); - return ResultInvalidCoreId; - } - if (affinity_mask == 0) { - LOG_ERROR(Kernel_SVC, "Affinity mask is zero."); - return ResultInvalidCombination; - } + const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask(); + R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId); + R_UNLESS(affinity_mask != 0, ResultInvalidCombination); // Validate the core id. - if (IsValidCoreId(core_id)) { - if (((1ULL << core_id) & affinity_mask) == 0) { - LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); - return ResultInvalidCombination; - } + if (IsValidVirtualCoreId(core_id)) { + R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination); } else { - if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { - LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); - return ResultInvalidCoreId; - } + R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare, + ResultInvalidCoreId); } } // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Set the core mask. - const auto set_result = thread->SetCoreMask(core_id, affinity_mask); - if (set_result.IsError()) { - LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw); - return set_result; - } + R_TRY(thread->SetCoreMask(core_id, affinity_mask)); + return RESULT_SUCCESS; } @@ -2022,27 +1965,12 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle static ResultCode SignalEvent(Core::System& system, Handle event_handle) { LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); - auto& kernel = system.Kernel(); // Get the current handle table. - const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); - - // Reserve a new event from the process resource limit. - KScopedResourceReservation event_reservation(kernel.CurrentProcess(), - LimitableResource::Events); - if (!event_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve a new event"); - return ResultResourceLimitedExceeded; - } + const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); // Get the writable event. - auto writable_event = handle_table.Get<KWritableEvent>(event_handle); - if (!writable_event) { - LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle); - return ResultInvalidHandle; - } - - // Commit the successfuly reservation. - event_reservation.Commit(); + KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle); + R_UNLESS(writable_event.IsNotNull(), ResultInvalidHandle); return writable_event->Signal(); } @@ -2059,16 +1987,16 @@ static ResultCode ClearEvent(Core::System& system, Handle event_handle) { // Try to clear the writable event. { - auto writable_event = handle_table.Get<KWritableEvent>(event_handle); - if (writable_event) { + KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle); + if (writable_event.IsNotNull()) { return writable_event->Clear(); } } // Try to clear the readable event. { - auto readable_event = handle_table.Get<KReadableEvent>(event_handle); - if (readable_event) { + KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle); + if (readable_event.IsNotNull()) { return readable_event->Clear(); } } @@ -2087,34 +2015,40 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o // Get the kernel reference and handle table. auto& kernel = system.Kernel(); - HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); + auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + + // Reserve a new event from the process resource limit + KScopedResourceReservation event_reservation(kernel.CurrentProcess(), + LimitableResource::Events); + R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); // Create a new event. - const auto event = KEvent::Create(kernel, "CreateEvent"); - if (!event) { - LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached."); - return ResultOutOfResource; - } + KEvent* event = KEvent::Create(kernel); + R_UNLESS(event != nullptr, ResultOutOfResource); // Initialize the event. - event->Initialize(); + event->Initialize("CreateEvent"); + + // Commit the thread reservation. + event_reservation.Commit(); + + // Ensure that we clean up the event (and its only references are handle table) on function end. + SCOPE_EXIT({ + event->GetWritableEvent().Close(); + event->GetReadableEvent().Close(); + }); + + // Register the event. + KEvent::Register(kernel, event); // Add the writable event to the handle table. - const auto write_create_result = handle_table.Create(event->GetWritableEvent()); - if (write_create_result.Failed()) { - return write_create_result.Code(); - } - *out_write = *write_create_result; + R_TRY(handle_table.Add(out_write, std::addressof(event->GetWritableEvent()))); // Add the writable event to the handle table. - auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); }); + auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); }); // Add the readable event to the handle table. - const auto read_create_result = handle_table.Create(event->GetReadableEvent()); - if (read_create_result.Failed()) { - return read_create_result.Code(); - } - *out_read = *read_create_result; + R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); // We succeeded. handle_guard.Cancel(); @@ -2134,8 +2068,8 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ }; const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const auto process = handle_table.Get<Process>(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); return ResultInvalidHandle; @@ -2152,83 +2086,86 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ } static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { - std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called"); + // Create a new resource limit. auto& kernel = system.Kernel(); - auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming()); + KResourceLimit* resource_limit = KResourceLimit::Create(kernel); + R_UNLESS(resource_limit != nullptr, ResultOutOfResource); - auto* const current_process = kernel.CurrentProcess(); - ASSERT(current_process != nullptr); + // Ensure we don't leak a reference to the limit. + SCOPE_EXIT({ resource_limit->Close(); }); - const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); - if (handle.Failed()) { - return handle.Code(); - } + // Initialize the resource limit. + resource_limit->Initialize(&system.CoreTiming()); + + // Register the limit. + KResourceLimit::Register(kernel, resource_limit); + + // Add the limit to the handle table. + R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit)); - *out_handle = *handle; return RESULT_SUCCESS; } -static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value, - Handle resource_limit, u32 resource_type) { - LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); +static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value, + Handle resource_limit_handle, + LimitableResource which) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, + which); - const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, - ResourceLimitValueType::LimitValue); - if (limit_value.Failed()) { - return limit_value.Code(); - } + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + + // Get the resource limit. + auto& kernel = system.Kernel(); + KScopedAutoObject resource_limit = + kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + + // Get the limit value. + *out_limit_value = resource_limit->GetLimitValue(which); - *out_value = static_cast<u64>(*limit_value); return RESULT_SUCCESS; } -static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value, - Handle resource_limit, u32 resource_type) { - LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); +static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value, + Handle resource_limit_handle, + LimitableResource which) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, + which); - const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, - ResourceLimitValueType::CurrentValue); - if (current_value.Failed()) { - return current_value.Code(); - } + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + + // Get the resource limit. + auto& kernel = system.Kernel(); + KScopedAutoObject resource_limit = + kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + + // Get the current value. + *out_current_value = resource_limit->GetCurrentValue(which); - *out_value = static_cast<u64>(*current_value); return RESULT_SUCCESS; } -static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit, - u32 resource_type, u64 value) { - LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, - resource_type, value); +static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, + LimitableResource which, u64 limit_value) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}", + resource_limit_handle, which, limit_value); - const auto type = static_cast<LimitableResource>(resource_type); - if (!IsValidResourceType(type)) { - LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); - return ResultInvalidEnumValue; - } - - auto* const current_process = system.Kernel().CurrentProcess(); - ASSERT(current_process != nullptr); + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); - auto resource_limit_object = - current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); - if (!resource_limit_object) { - LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", - resource_limit); - return ResultInvalidHandle; - } + // Get the resource limit. + auto& kernel = system.Kernel(); + KScopedAutoObject resource_limit = + kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); - const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value)); - if (set_result.IsError()) { - LOG_ERROR(Kernel_SVC, - "Attempted to lower resource limit ({}) for category '{}' below its current " - "value ({})", - resource_limit_object->GetLimitValue(type), resource_type, - resource_limit_object->GetCurrentValue(type)); - return set_result; - } + // Set the limit value. + R_TRY(resource_limit->SetLimitValue(which, limit_value)); return RESULT_SUCCESS; } @@ -2351,7 +2288,7 @@ static const FunctionDef SVC_Table_32[] = { {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, - {0x14, nullptr, "UnmapSharedMemory32"}, + {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"}, {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, @@ -2546,7 +2483,7 @@ static const FunctionDef SVC_Table_64[] = { {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, - {0x14, nullptr, "UnmapSharedMemory"}, + {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"}, {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, diff --git a/src/core/hle/kernel/svc_common.h b/src/core/hle/kernel/svc_common.h index 4af049551..60ea2c405 100644 --- a/src/core/hle/kernel/svc_common.h +++ b/src/core/hle/kernel/svc_common.h @@ -6,9 +6,24 @@ #include "common/common_types.h" +namespace Kernel { +using Handle = u32; +} + namespace Kernel::Svc { constexpr s32 ArgumentHandleCountMax = 0x40; constexpr u32 HandleWaitMask{1u << 30}; +constexpr inline Handle InvalidHandle = Handle(0); + +enum PseudoHandle : Handle { + CurrentThread = 0xFFFF8000, + CurrentProcess = 0xFFFF8001, +}; + +constexpr bool IsPseudoHandle(Handle handle) { + return handle == PseudoHandle::CurrentProcess || handle == PseudoHandle::CurrentThread; +} + } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index a26d9f2c9..53a940723 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h @@ -10,18 +10,18 @@ namespace Kernel { // Confirmed Switch kernel error codes -constexpr ResultCode ResultMaxConnectionsReached{ErrorModule::Kernel, 7}; -constexpr ResultCode ResultInvalidCapabilityDescriptor{ErrorModule::Kernel, 14}; +constexpr ResultCode ResultOutOfSessions{ErrorModule::Kernel, 7}; +constexpr ResultCode ResultInvalidArgument{ErrorModule::Kernel, 14}; constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57}; constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; constexpr ResultCode ResultInvalidSize{ErrorModule::Kernel, 101}; constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103}; constexpr ResultCode ResultOutOfMemory{ErrorModule::Kernel, 104}; -constexpr ResultCode ResultHandleTableFull{ErrorModule::Kernel, 105}; +constexpr ResultCode ResultOutOfHandles{ErrorModule::Kernel, 105}; constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106}; -constexpr ResultCode ResultInvalidMemoryPermissions{ErrorModule::Kernel, 108}; -constexpr ResultCode ResultInvalidMemoryRange{ErrorModule::Kernel, 110}; +constexpr ResultCode ResultInvalidNewMemoryPermission{ErrorModule::Kernel, 108}; +constexpr ResultCode ResultInvalidMemoryRegion{ErrorModule::Kernel, 110}; constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112}; constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113}; constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114}; @@ -33,9 +33,11 @@ constexpr ResultCode ResultOutOfRange{ErrorModule::Kernel, 119}; constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120}; constexpr ResultCode ResultNotFound{ErrorModule::Kernel, 121}; constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122}; -constexpr ResultCode ResultSessionClosedByRemote{ErrorModule::Kernel, 123}; +constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123}; constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; -constexpr ResultCode ResultReservedValue{ErrorModule::Kernel, 126}; -constexpr ResultCode ResultResourceLimitedExceeded{ErrorModule::Kernel, 132}; +constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126}; +constexpr ResultCode ResultPortClosed{ErrorModule::Kernel, 131}; +constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132}; +constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519}; } // namespace Kernel diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 96afd544b..913b16494 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -154,15 +154,28 @@ void SvcWrap64(Core::System& system) { FuncReturn(system, retval); } +// Used by GetResourceLimitLimitValue. +template <ResultCode func(Core::System&, u64*, Handle, LimitableResource)> +void SvcWrap64(Core::System& system) { + u64 param_1 = 0; + const u32 retval = func(system, ¶m_1, static_cast<Handle>(Param(system, 1)), + static_cast<LimitableResource>(Param(system, 2))) + .raw; + + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); +} + template <ResultCode func(Core::System&, u32, u64)> void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw); } -template <ResultCode func(Core::System&, u32, u32, u64)> +// Used by SetResourceLimitLimitValue +template <ResultCode func(Core::System&, Handle, LimitableResource, u64)> void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), - static_cast<u32>(Param(system, 1)), Param(system, 2)) + FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), + static_cast<LimitableResource>(Param(system, 1)), Param(system, 2)) .raw); } @@ -219,10 +232,11 @@ void SvcWrap64(Core::System& system) { func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); } -template <ResultCode func(Core::System&, u32, u64, u64, u32)> +// Used by MapSharedMemory +template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)> void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), - Param(system, 2), static_cast<u32>(Param(system, 3))) + FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), Param(system, 1), + Param(system, 2), static_cast<Svc::MemoryPermission>(Param(system, 3))) .raw); } @@ -252,11 +266,13 @@ void SvcWrap64(Core::System& system) { .raw); } -template <ResultCode func(Core::System&, u64*, u64, u64, u64)> +// Used by GetInfo +template <ResultCode func(Core::System&, u64*, u64, Handle, u64)> void SvcWrap64(Core::System& system) { u64 param_1 = 0; - const u32 retval = - func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw; + const u32 retval = func(system, ¶m_1, Param(system, 1), + static_cast<Handle>(Param(system, 2)), Param(system, 3)) + .raw; system.CurrentArmInterface().SetReg(1, param_1); FuncReturn(system, retval); @@ -273,11 +289,12 @@ void SvcWrap64(Core::System& system) { FuncReturn(system, retval); } -template <ResultCode func(Core::System&, u32*, u64, u64, u32)> +// Used by CreateTransferMemory +template <ResultCode func(Core::System&, Handle*, u64, u64, Svc::MemoryPermission)> void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), - static_cast<u32>(Param(system, 3))) + static_cast<Svc::MemoryPermission>(Param(system, 3))) .raw; system.CurrentArmInterface().SetReg(1, param_1); @@ -537,6 +554,16 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by MapSharedMemory32 +template <ResultCode func(Core::System&, Handle, u32, u32, Svc::MemoryPermission)> +void SvcWrap32(Core::System& system) { + const u32 retval = func(system, static_cast<Handle>(Param(system, 0)), + static_cast<u32>(Param(system, 1)), static_cast<u32>(Param(system, 2)), + static_cast<Svc::MemoryPermission>(Param(system, 3))) + .raw; + FuncReturn(system, retval); +} + // Used by SetThreadCoreMask32 template <ResultCode func(Core::System&, Handle, s32, u32, u32)> void SvcWrap32(Core::System& system) { @@ -586,11 +613,12 @@ void SvcWrap32(Core::System& system) { } // Used by CreateTransferMemory32 -template <ResultCode func(Core::System&, Handle*, u32, u32, u32)> +template <ResultCode func(Core::System&, Handle*, u32, u32, Svc::MemoryPermission)> void SvcWrap32(Core::System& system) { Handle handle = 0; - const u32 retval = - func(system, &handle, Param32(system, 1), Param32(system, 2), Param32(system, 3)).raw; + const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2), + static_cast<Svc::MemoryPermission>(Param32(system, 3))) + .raw; system.CurrentArmInterface().SetReg(1, handle); FuncReturn(system, retval); } diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index fd0630019..ae9b4be2f 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -6,7 +6,6 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" @@ -15,16 +14,12 @@ namespace Kernel { TimeManager::TimeManager(Core::System& system_) : system{system_} { - time_manager_event_type = Core::Timing::CreateEvent( - "Kernel::TimeManagerCallback", - [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { - std::shared_ptr<KThread> thread; - { - std::lock_guard lock{mutex}; - thread = SharedFrom<KThread>(reinterpret_cast<KThread*>(thread_handle)); - } - thread->Wakeup(); - }); + time_manager_event_type = + Core::Timing::CreateEvent("Kernel::TimeManagerCallback", + [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { + KThread* thread = reinterpret_cast<KThread*>(thread_handle); + thread->Wakeup(); + }); } void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index 0d7f05f30..2d175a9c4 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -8,8 +8,6 @@ #include <mutex> #include <unordered_map> -#include "core/hle/kernel/object.h" - namespace Core { class System; } // namespace Core diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp deleted file mode 100644 index 1dd65468d..000000000 --- a/src/core/hle/kernel/transfer_memory.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/transfer_memory.h" -#include "core/hle/result.h" -#include "core/memory.h" - -namespace Kernel { - -TransferMemory::TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory) - : Object{kernel}, memory{memory} {} - -TransferMemory::~TransferMemory() { - // Release memory region when transfer memory is destroyed - Reset(); - owner_process->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1); -} - -std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, - Core::Memory::Memory& memory, - VAddr base_address, std::size_t size, - KMemoryPermission permissions) { - std::shared_ptr<TransferMemory> transfer_memory{ - std::make_shared<TransferMemory>(kernel, memory)}; - - transfer_memory->base_address = base_address; - transfer_memory->size = size; - transfer_memory->owner_permissions = permissions; - transfer_memory->owner_process = kernel.CurrentProcess(); - - return transfer_memory; -} - -u8* TransferMemory::GetPointer() { - return memory.GetPointer(base_address); -} - -const u8* TransferMemory::GetPointer() const { - return memory.GetPointer(base_address); -} - -ResultCode TransferMemory::Reserve() { - return owner_process->PageTable().ReserveTransferMemory(base_address, size, owner_permissions); -} - -ResultCode TransferMemory::Reset() { - return owner_process->PageTable().ResetTransferMemory(base_address, size); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h deleted file mode 100644 index 59328c0fe..000000000 --- a/src/core/hle/kernel/transfer_memory.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> - -#include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/physical_memory.h" - -union ResultCode; - -namespace Core::Memory { -class Memory; -} - -namespace Kernel { - -class KernelCore; -class Process; - -/// Defines the interface for transfer memory objects. -/// -/// Transfer memory is typically used for the purpose of -/// transferring memory between separate process instances, -/// thus the name. -/// -class TransferMemory final : public Object { -public: - explicit TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory); - ~TransferMemory() override; - - static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; - - static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Core::Memory::Memory& memory, - VAddr base_address, std::size_t size, - KMemoryPermission permissions); - - TransferMemory(const TransferMemory&) = delete; - TransferMemory& operator=(const TransferMemory&) = delete; - - TransferMemory(TransferMemory&&) = delete; - TransferMemory& operator=(TransferMemory&&) = delete; - - std::string GetTypeName() const override { - return "TransferMemory"; - } - - std::string GetName() const override { - return GetTypeName(); - } - - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - /// Gets a pointer to the backing block of this instance. - u8* GetPointer(); - - /// Gets a pointer to the backing block of this instance. - const u8* GetPointer() const; - - /// Gets the size of the memory backing this instance in bytes. - constexpr std::size_t GetSize() const { - return size; - } - - /// Reserves the region to be used for the transfer memory, called after the transfer memory is - /// created. - ResultCode Reserve(); - - /// Resets the region previously used for the transfer memory, called after the transfer memory - /// is closed. - ResultCode Reset(); - - void Finalize() override {} - -private: - /// The base address for the memory managed by this instance. - VAddr base_address{}; - - /// Size of the memory, in bytes, that this instance manages. - std::size_t size{}; - - /// The memory permissions that are applied to this instance. - KMemoryPermission owner_permissions{}; - - /// The process that this transfer memory instance was created under. - Process* owner_process{}; - - Core::Memory::Memory& memory; -}; - -} // namespace Kernel diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 5450dcf0f..49c09a570 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -16,8 +16,8 @@ #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/acc/acc.h" #include "core/hle/service/acc/acc_aa.h" #include "core/hle/service/acc/acc_su.h" diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 58c7f2930..408e441dc 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -15,11 +15,11 @@ #include "core/file_sys/savedata_factory.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/transfer_memory.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" @@ -42,6 +42,7 @@ #include "core/hle/service/set/set.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/vi/vi.h" +#include "core/memory.h" namespace Service::AM { @@ -253,7 +254,8 @@ IDebugFunctions::IDebugFunctions(Core::System& system_) IDebugFunctions::~IDebugFunctions() = default; ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_) - : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_} { + : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_}, + launchable_event{system.Kernel()}, accumulated_suspended_tick_changed_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, &ISelfController::Exit, "Exit"}, @@ -306,19 +308,20 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv RegisterHandlers(functions); - auto& kernel = system.Kernel(); - launchable_event = Kernel::KEvent::Create(kernel, "ISelfController:LaunchableEvent"); - launchable_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(launchable_event)); + + launchable_event.Initialize("ISelfController:LaunchableEvent"); // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not // suspended if the event has previously been created by a call to // GetAccumulatedSuspendedTickChangedEvent. - accumulated_suspended_tick_changed_event = - Kernel::KEvent::Create(kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent"); - accumulated_suspended_tick_changed_event->Initialize(); - accumulated_suspended_tick_changed_event->GetWritableEvent()->Signal(); + + Kernel::KAutoObject::Create(std::addressof(accumulated_suspended_tick_changed_event)); + accumulated_suspended_tick_changed_event.Initialize( + "ISelfController:AccumulatedSuspendedTickChangedEvent"); + accumulated_suspended_tick_changed_event.GetWritableEvent().Signal(); } ISelfController::~ISelfController() = default; @@ -377,11 +380,11 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) { void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - launchable_event->GetWritableEvent()->Signal(); + launchable_event.GetWritableEvent().Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(launchable_event->GetReadableEvent()); + rb.PushCopyObjects(launchable_event.GetReadableEvent()); } void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { @@ -560,7 +563,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); + rb.PushCopyObjects(accumulated_suspended_tick_changed_event.GetReadableEvent()); } void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) { @@ -578,39 +581,40 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo rb.Push(RESULT_SUCCESS); } -AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { - on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived"); - on_new_message->Initialize(); - on_operation_mode_changed = - Kernel::KEvent::Create(kernel, "AMMessageQueue:OperationModeChanged"); - on_operation_mode_changed->Initialize(); +AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) + : on_new_message{kernel}, on_operation_mode_changed{kernel} { + + Kernel::KAutoObject::Create(std::addressof(on_new_message)); + Kernel::KAutoObject::Create(std::addressof(on_operation_mode_changed)); + + on_new_message.Initialize("AMMessageQueue:OnMessageReceived"); + on_operation_mode_changed.Initialize("AMMessageQueue:OperationModeChanged"); } AppletMessageQueue::~AppletMessageQueue() = default; -const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const { - return on_new_message->GetReadableEvent(); +Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() { + return on_new_message.GetReadableEvent(); } -const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() - const { - return on_operation_mode_changed->GetReadableEvent(); +Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { + return on_operation_mode_changed.GetReadableEvent(); } void AppletMessageQueue::PushMessage(AppletMessage msg) { messages.push(msg); - on_new_message->GetWritableEvent()->Signal(); + on_new_message.GetWritableEvent().Signal(); } AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { if (messages.empty()) { - on_new_message->GetWritableEvent()->Clear(); + on_new_message.GetWritableEvent().Clear(); return AppletMessage::NoMessage; } auto msg = messages.front(); messages.pop(); if (messages.empty()) { - on_new_message->GetWritableEvent()->Clear(); + on_new_message.GetWritableEvent().Clear(); } return msg; } @@ -630,7 +634,7 @@ void AppletMessageQueue::FocusStateChanged() { void AppletMessageQueue::OperationModeChanged() { PushMessage(AppletMessage::OperationModeChanged); PushMessage(AppletMessage::PerformanceModeChanged); - on_operation_mode_changed->GetWritableEvent()->Signal(); + on_operation_mode_changed.GetWritableEvent().Signal(); } ICommonStateGetter::ICommonStateGetter(Core::System& system_, @@ -927,11 +931,9 @@ private: void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - const auto event = applet->GetBroker().GetStateChangedEvent(); - IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(event); + rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); } void IsCompleted(Kernel::HLERequestContext& ctx) { @@ -1213,16 +1215,16 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex } auto transfer_mem = - system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); + system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); - if (transfer_mem == nullptr) { + if (transfer_mem.IsNull()) { LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_UNKNOWN); return; } - const u8* const mem_begin = transfer_mem->GetPointer(); + const u8* const mem_begin = system.Memory().GetPointer(transfer_mem->GetSourceAddress()); const u8* const mem_end = mem_begin + transfer_mem->GetSize(); std::vector<u8> memory{mem_begin, mem_end}; @@ -1247,16 +1249,16 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) } auto transfer_mem = - system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); + system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); - if (transfer_mem == nullptr) { + if (transfer_mem.IsNull()) { LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_UNKNOWN); return; } - const u8* const mem_begin = transfer_mem->GetPointer(); + const u8* const mem_begin = system.Memory().GetPointer(transfer_mem->GetSourceAddress()); const u8* const mem_end = mem_begin + transfer_mem->GetSize(); std::vector<u8> memory{mem_begin, mem_end}; @@ -1266,7 +1268,9 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) } IApplicationFunctions::IApplicationFunctions(Core::System& system_) - : ServiceFramework{system_, "IApplicationFunctions"} { + : ServiceFramework{system_, "IApplicationFunctions"}, gpu_error_detected_event{system.Kernel()}, + friend_invitation_storage_channel_event{system.Kernel()}, + health_warning_disappeared_system_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, @@ -1334,16 +1338,15 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) RegisterHandlers(functions); - auto& kernel = system.Kernel(); - gpu_error_detected_event = - Kernel::KEvent::Create(kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); - gpu_error_detected_event->Initialize(); - friend_invitation_storage_channel_event = - Kernel::KEvent::Create(kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent"); - friend_invitation_storage_channel_event->Initialize(); - health_warning_disappeared_system_event = - Kernel::KEvent::Create(kernel, "IApplicationFunctions:HealthWarningDisappearedSystemEvent"); - health_warning_disappeared_system_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(gpu_error_detected_event)); + Kernel::KAutoObject::Create(std::addressof(friend_invitation_storage_channel_event)); + Kernel::KAutoObject::Create(std::addressof(health_warning_disappeared_system_event)); + + gpu_error_detected_event.Initialize("IApplicationFunctions:GpuErrorDetectedSystemEvent"); + friend_invitation_storage_channel_event.Initialize( + "IApplicationFunctions:FriendInvitationStorageChannelEvent"); + health_warning_disappeared_system_event.Initialize( + "IApplicationFunctions:HealthWarningDisappearedSystemEvent"); } IApplicationFunctions::~IApplicationFunctions() = default; @@ -1740,7 +1743,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); + rb.PushCopyObjects(gpu_error_detected_event.GetReadableEvent()); } void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) { @@ -1748,7 +1751,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); + rb.PushCopyObjects(friend_invitation_storage_channel_event.GetReadableEvent()); } void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel( @@ -1764,7 +1767,7 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); + rb.PushCopyObjects(health_warning_disappeared_system_event.GetReadableEvent()); } void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, @@ -1782,7 +1785,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger } IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) - : ServiceFramework{system_, "IHomeMenuFunctions"} { + : ServiceFramework{system_, "IHomeMenuFunctions"}, pop_from_general_channel_event{ + system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, @@ -1803,9 +1807,8 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) RegisterHandlers(functions); - pop_from_general_channel_event = - Kernel::KEvent::Create(system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent"); - pop_from_general_channel_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(pop_from_general_channel_event)); + pop_from_general_channel_event.Initialize("IHomeMenuFunctions:PopFromGeneralChannelEvent"); } IHomeMenuFunctions::~IHomeMenuFunctions() = default; @@ -1822,7 +1825,7 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); + rb.PushCopyObjects(pop_from_general_channel_event.GetReadableEvent()); } IGlobalStateController::IGlobalStateController(Core::System& system_) diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 5d302e155..184030a8e 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -8,12 +8,12 @@ #include <memory> #include <queue> +#include "core/hle/kernel/k_event.h" #include "core/hle/service/service.h" namespace Kernel { class KernelCore; -class KEvent; -class TransferMemory; +class KTransferMemory; } // namespace Kernel namespace Service::NVFlinger { @@ -56,8 +56,8 @@ public: explicit AppletMessageQueue(Kernel::KernelCore& kernel); ~AppletMessageQueue(); - const std::shared_ptr<Kernel::KReadableEvent>& GetMessageReceiveEvent() const; - const std::shared_ptr<Kernel::KReadableEvent>& GetOperationModeChangedEvent() const; + Kernel::KReadableEvent& GetMessageReceiveEvent(); + Kernel::KReadableEvent& GetOperationModeChangedEvent(); void PushMessage(AppletMessage msg); AppletMessage PopMessage(); std::size_t GetMessageCount() const; @@ -67,8 +67,8 @@ public: private: std::queue<AppletMessage> messages; - std::shared_ptr<Kernel::KEvent> on_new_message; - std::shared_ptr<Kernel::KEvent> on_operation_mode_changed; + Kernel::KEvent on_new_message; + Kernel::KEvent on_operation_mode_changed; }; class IWindowController final : public ServiceFramework<IWindowController> { @@ -156,8 +156,8 @@ private: }; NVFlinger::NVFlinger& nvflinger; - std::shared_ptr<Kernel::KEvent> launchable_event; - std::shared_ptr<Kernel::KEvent> accumulated_suspended_tick_changed_event; + Kernel::KEvent launchable_event; + Kernel::KEvent accumulated_suspended_tick_changed_event; u32 idle_time_detection_extension = 0; u64 num_fatal_sections_entered = 0; @@ -300,9 +300,9 @@ private: bool launch_popped_application_specific = false; bool launch_popped_account_preselect = false; s32 previous_program_index{-1}; - std::shared_ptr<Kernel::KEvent> gpu_error_detected_event; - std::shared_ptr<Kernel::KEvent> friend_invitation_storage_channel_event; - std::shared_ptr<Kernel::KEvent> health_warning_disappeared_system_event; + Kernel::KEvent gpu_error_detected_event; + Kernel::KEvent friend_invitation_storage_channel_event; + Kernel::KEvent health_warning_disappeared_system_event; }; class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { @@ -314,7 +314,7 @@ private: void RequestToGetForeground(Kernel::HLERequestContext& ctx); void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); - std::shared_ptr<Kernel::KEvent> pop_from_general_channel_event; + Kernel::KEvent pop_from_general_channel_event; }; class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index a56df6a7e..ae995df6b 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -12,10 +12,8 @@ #include "core/frontend/applets/profile_select.h" #include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/web_browser.h" -#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" @@ -31,16 +29,16 @@ namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) - : system{system_}, applet_mode{applet_mode_} { - state_changed_event = - Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:StateChangedEvent"); - state_changed_event->Initialize(); - pop_out_data_event = - Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:PopDataOutEvent"); - pop_out_data_event->Initialize(); - pop_interactive_out_data_event = Kernel::KEvent::Create( - system.Kernel(), "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); - pop_interactive_out_data_event->Initialize(); + : system{system_}, applet_mode{applet_mode_}, state_changed_event{system.Kernel()}, + pop_out_data_event{system.Kernel()}, pop_interactive_out_data_event{system.Kernel()} { + + Kernel::KAutoObject::Create(std::addressof(state_changed_event)); + Kernel::KAutoObject::Create(std::addressof(pop_out_data_event)); + Kernel::KAutoObject::Create(std::addressof(pop_interactive_out_data_event)); + + state_changed_event.Initialize("ILibraryAppletAccessor:StateChangedEvent"); + pop_out_data_event.Initialize("ILibraryAppletAccessor:PopDataOutEvent"); + pop_interactive_out_data_event.Initialize("ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } AppletDataBroker::~AppletDataBroker() = default; @@ -67,7 +65,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { auto out = std::move(out_channel.front()); out_channel.pop_front(); - pop_out_data_event->GetWritableEvent()->Clear(); + pop_out_data_event.GetWritableEvent().Clear(); return out; } @@ -86,7 +84,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { auto out = std::move(out_interactive_channel.front()); out_interactive_channel.pop_front(); - pop_interactive_out_data_event->GetWritableEvent()->Clear(); + pop_interactive_out_data_event.GetWritableEvent().Clear(); return out; } @@ -105,7 +103,7 @@ void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storag void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { out_channel.emplace_back(std::move(storage)); - pop_out_data_event->GetWritableEvent()->Signal(); + pop_out_data_event.GetWritableEvent().Signal(); } void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { @@ -114,11 +112,11 @@ void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& s void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { out_interactive_channel.emplace_back(std::move(storage)); - pop_interactive_out_data_event->GetWritableEvent()->Signal(); + pop_interactive_out_data_event.GetWritableEvent().Signal(); } -void AppletDataBroker::SignalStateChanged() const { - state_changed_event->GetWritableEvent()->Signal(); +void AppletDataBroker::SignalStateChanged() { + state_changed_event.GetWritableEvent().Signal(); switch (applet_mode) { case LibraryAppletMode::AllForeground: @@ -142,16 +140,16 @@ void AppletDataBroker::SignalStateChanged() const { } } -std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const { - return pop_out_data_event->GetReadableEvent(); +Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() { + return pop_out_data_event.GetReadableEvent(); } -std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { - return pop_interactive_out_data_event->GetReadableEvent(); +Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() { + return pop_interactive_out_data_event.GetReadableEvent(); } -std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetStateChangedEvent() const { - return state_changed_event->GetReadableEvent(); +Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() { + return state_changed_event.GetReadableEvent(); } Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_) diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 4215d2232..5c0b4b459 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -8,7 +8,7 @@ #include <queue> #include "common/swap.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_event.h" union ResultCode; @@ -95,11 +95,11 @@ public: void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage); void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage); - void SignalStateChanged() const; + void SignalStateChanged(); - std::shared_ptr<Kernel::KReadableEvent> GetNormalDataEvent() const; - std::shared_ptr<Kernel::KReadableEvent> GetInteractiveDataEvent() const; - std::shared_ptr<Kernel::KReadableEvent> GetStateChangedEvent() const; + Kernel::KReadableEvent& GetNormalDataEvent(); + Kernel::KReadableEvent& GetInteractiveDataEvent(); + Kernel::KReadableEvent& GetStateChangedEvent(); private: Core::System& system; @@ -119,13 +119,13 @@ private: // PopInteractiveDataToGame and PushInteractiveDataFromApplet std::deque<std::shared_ptr<IStorage>> out_interactive_channel; - std::shared_ptr<Kernel::KEvent> state_changed_event; + Kernel::KEvent state_changed_event; // Signaled on PushNormalDataFromApplet - std::shared_ptr<Kernel::KEvent> pop_out_data_event; + Kernel::KEvent pop_out_data_event; // Signaled on PushInteractiveDataFromApplet - std::shared_ptr<Kernel::KEvent> pop_interactive_out_data_event; + Kernel::KEvent pop_interactive_out_data_event; }; class Applet { diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index 0dd6ec68e..08348b180 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp @@ -9,7 +9,7 @@ #include "common/string_util.h" #include "core/core.h" #include "core/frontend/applets/error.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/error.h" #include "core/reporter.h" diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index b7483261e..e95499edd 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp @@ -9,7 +9,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/frontend/applets/general_frontend.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/general_backend.h" diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 2404921fd..e5f4a4485 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -17,7 +17,7 @@ #include "core/file_sys/system_archive/system_archive.h" #include "core/file_sys/vfs_vector.h" #include "core/frontend/applets/web_browser.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/web_browser.h" diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 75867e349..1863260f1 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -16,10 +16,9 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/aoc/aoc_u.h" #include "core/loader/loader.h" @@ -50,7 +49,7 @@ static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) { class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> { public: explicit IPurchaseEventManager(Core::System& system_) - : ServiceFramework{system_, "IPurchaseEventManager"} { + : ServiceFramework{system_, "IPurchaseEventManager"}, purchased_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"}, @@ -63,9 +62,8 @@ public: RegisterHandlers(functions); - purchased_event = - Kernel::KEvent::Create(system.Kernel(), "IPurchaseEventManager:PurchasedEvent"); - purchased_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(purchased_event)); + purchased_event.Initialize("IPurchaseEventManager:PurchasedEvent"); } private: @@ -98,14 +96,15 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(purchased_event->GetReadableEvent()); + rb.PushCopyObjects(purchased_event.GetReadableEvent()); } - std::shared_ptr<Kernel::KEvent> purchased_event; + Kernel::KEvent purchased_event; }; AOC_U::AOC_U(Core::System& system_) - : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)} { + : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)}, + aoc_change_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "CountAddOnContentByApplicationId"}, @@ -127,9 +126,8 @@ AOC_U::AOC_U(Core::System& system_) RegisterHandlers(functions); - auto& kernel = system.Kernel(); - aoc_change_event = Kernel::KEvent::Create(kernel, "GetAddOnContentListChanged:Event"); - aoc_change_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(aoc_change_event)); + aoc_change_event.Initialize("GetAddOnContentListChanged:Event"); } AOC_U::~AOC_U() = default; @@ -256,7 +254,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(aoc_change_event->GetReadableEvent()); + rb.PushCopyObjects(aoc_change_event.GetReadableEvent()); } void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 1aa23529e..65095baa2 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h @@ -4,6 +4,7 @@ #pragma once +#include "core/hle/kernel/k_event.h" #include "core/hle/service/service.h" namespace Core { @@ -31,7 +32,7 @@ private: void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx); std::vector<u64> add_on_content; - std::shared_ptr<Kernel::KEvent> aoc_change_event; + Kernel::KEvent aoc_change_event; }; /// Registers all AOC services with the specified service manager. diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 5f51fca9a..e1ae726f5 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -43,9 +43,9 @@ class IAudioOut final : public ServiceFramework<IAudioOut> { public: IAudioOut(Core::System& system_, AudoutParams audio_params_, AudioCore::AudioOut& audio_core_, std::string&& device_name_, std::string&& unique_name) - : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, - device_name{std::move(device_name_)}, audio_params{audio_params_}, main_memory{ - system.Memory()} { + : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, device_name{std::move( + device_name_)}, + audio_params{audio_params_}, buffer_event{system.Kernel()}, main_memory{system.Memory()} { // clang-format off static const FunctionInfo functions[] = { {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, @@ -67,13 +67,13 @@ public: RegisterHandlers(functions); // This is the event handle used to check if the audio buffer was released - buffer_event = Kernel::KEvent::Create(system.Kernel(), "IAudioOutBufferReleased"); - buffer_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(buffer_event)); + buffer_event.Initialize("IAudioOutBufferReleased"); stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, audio_params.channel_count, std::move(unique_name), [this] { const auto guard = LockService(); - buffer_event->GetWritableEvent()->Signal(); + buffer_event.GetWritableEvent().Signal(); }); } @@ -126,7 +126,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(buffer_event->GetReadableEvent()); + rb.PushCopyObjects(buffer_event.GetReadableEvent()); } void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { @@ -220,7 +220,7 @@ private: [[maybe_unused]] AudoutParams audio_params{}; /// This is the event handle used to check if the audio buffer was released - std::shared_ptr<Kernel::KEvent> buffer_event; + Kernel::KEvent buffer_event; Core::Memory::Memory& main_memory; }; diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 3a48342fd..513bd3730 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -30,7 +30,7 @@ public: explicit IAudioRenderer(Core::System& system_, const AudioCommon::AudioRendererParameter& audren_params, const std::size_t instance_number) - : ServiceFramework{system_, "IAudioRenderer"} { + : ServiceFramework{system_, "IAudioRenderer"}, system_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, @@ -49,13 +49,13 @@ public: // clang-format on RegisterHandlers(functions); - system_event = Kernel::KEvent::Create(system.Kernel(), "IAudioRenderer:SystemEvent"); - system_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(system_event)); + system_event.Initialize("IAudioRenderer:SystemEvent"); renderer = std::make_unique<AudioCore::AudioRenderer>( system.CoreTiming(), system.Memory(), audren_params, [this]() { const auto guard = LockService(); - system_event->GetWritableEvent()->Signal(); + system_event.GetWritableEvent().Signal(); }, instance_number); } @@ -128,7 +128,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(system_event->GetReadableEvent()); + rb.PushCopyObjects(system_event.GetReadableEvent()); } void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { @@ -162,7 +162,7 @@ private: rb.Push(ERR_NOT_SUPPORTED); } - std::shared_ptr<Kernel::KEvent> system_event; + Kernel::KEvent system_event; std::unique_ptr<AudioCore::AudioRenderer> renderer; u32 rendering_time_limit_percent = 100; }; @@ -170,7 +170,9 @@ private: class IAudioDevice final : public ServiceFramework<IAudioDevice> { public: explicit IAudioDevice(Core::System& system_, u32_le revision_num) - : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num} { + : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num}, + buffer_event{system.Kernel()}, audio_input_device_switch_event{system.Kernel()}, + audio_output_device_switch_event{system.Kernel()} { static const FunctionInfo functions[] = { {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, @@ -188,20 +190,17 @@ public: }; RegisterHandlers(functions); - auto& kernel = system.Kernel(); - buffer_event = Kernel::KEvent::Create(kernel, "IAudioOutBufferReleasedEvent"); - buffer_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(buffer_event)); + buffer_event.Initialize("IAudioOutBufferReleasedEvent"); // Should be similar to audio_output_device_switch_event - audio_input_device_switch_event = - Kernel::KEvent::Create(kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent"); - audio_input_device_switch_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(audio_input_device_switch_event)); + audio_input_device_switch_event.Initialize("IAudioDevice:AudioInputDeviceSwitchedEvent"); // Should only be signalled when an audio output device has been changed, example: speaker // to headset - audio_output_device_switch_event = - Kernel::KEvent::Create(kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent"); - audio_output_device_switch_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(audio_output_device_switch_event)); + audio_output_device_switch_event.Initialize("IAudioDevice:AudioOutputDeviceSwitchedEvent"); } private: @@ -290,11 +289,11 @@ private: void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_Audio, "(STUBBED) called"); - buffer_event->GetWritableEvent()->Signal(); + buffer_event.GetWritableEvent().Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(buffer_event->GetReadableEvent()); + rb.PushCopyObjects(buffer_event.GetReadableEvent()); } void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { @@ -311,7 +310,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(audio_input_device_switch_event->GetReadableEvent()); + rb.PushCopyObjects(audio_input_device_switch_event.GetReadableEvent()); } void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { @@ -319,13 +318,13 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(audio_output_device_switch_event->GetReadableEvent()); + rb.PushCopyObjects(audio_output_device_switch_event.GetReadableEvent()); } u32_le revision = 0; - std::shared_ptr<Kernel::KEvent> buffer_event; - std::shared_ptr<Kernel::KEvent> audio_input_device_switch_event; - std::shared_ptr<Kernel::KEvent> audio_output_device_switch_event; + Kernel::KEvent buffer_event; + Kernel::KEvent audio_input_device_switch_event; + Kernel::KEvent audio_output_device_switch_event; }; // namespace Audio diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp index 92d25dbe4..0e935bfa6 100644 --- a/src/core/hle/service/bcat/backend/backend.cpp +++ b/src/core/hle/service/bcat/backend/backend.cpp @@ -5,7 +5,6 @@ #include "common/hex_util.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/lock.h" @@ -14,14 +13,14 @@ namespace Service::BCAT { ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel, - std::string_view event_name) { - event = Kernel::KEvent::Create(kernel, - "ProgressServiceBackend:UpdateEvent:" + std::string(event_name)); - event->Initialize(); + std::string_view event_name) + : update_event{kernel} { + Kernel::KAutoObject::Create(std::addressof(update_event)); + update_event.Initialize("ProgressServiceBackend:UpdateEvent:" + std::string(event_name)); } -std::shared_ptr<Kernel::KReadableEvent> ProgressServiceBackend::GetEvent() const { - return event->GetReadableEvent(); +Kernel::KReadableEvent& ProgressServiceBackend::GetEvent() { + return update_event.GetReadableEvent(); } DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { @@ -86,12 +85,12 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) { SignalUpdate(); } -void ProgressServiceBackend::SignalUpdate() const { +void ProgressServiceBackend::SignalUpdate() { if (need_hle_lock) { std::lock_guard lock(HLE::g_hle_lock); - event->GetWritableEvent()->Signal(); + update_event.GetWritableEvent().Signal(); } else { - event->GetWritableEvent()->Signal(); + update_event.GetWritableEvent().Signal(); } } diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h index db585b069..f591a362a 100644 --- a/src/core/hle/service/bcat/backend/backend.h +++ b/src/core/hle/service/bcat/backend/backend.h @@ -11,6 +11,7 @@ #include "common/common_types.h" #include "core/file_sys/vfs_types.h" +#include "core/hle/kernel/k_event.h" #include "core/hle/result.h" namespace Core { @@ -98,13 +99,13 @@ public: private: explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name); - std::shared_ptr<Kernel::KReadableEvent> GetEvent() const; + Kernel::KReadableEvent& GetEvent(); DeliveryCacheProgressImpl& GetImpl(); - void SignalUpdate() const; + void SignalUpdate(); DeliveryCacheProgressImpl impl{}; - std::shared_ptr<Kernel::KEvent> event; + Kernel::KEvent update_event; bool need_hle_lock = false; }; diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 285085f2a..0206cbb6a 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -12,9 +12,9 @@ #include "core/core.h" #include "core/file_sys/vfs.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/bcat/backend/backend.h" #include "core/hle/service/bcat/bcat.h" #include "core/hle/service/bcat/module.h" @@ -88,11 +88,9 @@ struct DeliveryCacheDirectoryEntry { class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { public: - explicit IDeliveryCacheProgressService(Core::System& system_, - std::shared_ptr<Kernel::KReadableEvent> event_, + explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_, const DeliveryCacheProgressImpl& impl_) - : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)}, - impl{impl_} { + : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} { // clang-format off static const FunctionInfo functions[] = { {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, @@ -121,7 +119,7 @@ private: rb.Push(RESULT_SUCCESS); } - std::shared_ptr<Kernel::KReadableEvent> event; + Kernel::KReadableEvent& event; const DeliveryCacheProgressImpl& impl; }; diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index af3a5842d..fd97a822c 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -17,7 +17,8 @@ namespace Service::BtDrv { class Bt final : public ServiceFramework<Bt> { public: - explicit Bt(Core::System& system_) : ServiceFramework{system_, "bt"} { + explicit Bt(Core::System& system_) + : ServiceFramework{system_, "bt"}, register_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "LeClientReadCharacteristic"}, @@ -34,9 +35,8 @@ public: // clang-format on RegisterHandlers(functions); - auto& kernel = system.Kernel(); - register_event = Kernel::KEvent::Create(kernel, "BT:RegisterEvent"); - register_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(register_event)); + register_event.Initialize("BT:RegisterEvent"); } private: @@ -45,10 +45,10 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(register_event->GetReadableEvent()); + rb.PushCopyObjects(register_event.GetReadableEvent()); } - std::shared_ptr<Kernel::KEvent> register_event; + Kernel::KEvent register_event; }; class BtDrv final : public ServiceFramework<BtDrv> { diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index d1ebc2388..3b5ef69e1 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -18,7 +18,10 @@ namespace Service::BTM { class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { public: - explicit IBtmUserCore(Core::System& system_) : ServiceFramework{system_, "IBtmUserCore"} { + explicit IBtmUserCore(Core::System& system_) + : ServiceFramework{system_, "IBtmUserCore"}, scan_event{system.Kernel()}, + connection_event{system.Kernel()}, service_discovery{system.Kernel()}, + config_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, @@ -57,15 +60,15 @@ public: // clang-format on RegisterHandlers(functions); - auto& kernel = system.Kernel(); - scan_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ScanEvent"); - scan_event->Initialize(); - connection_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConnectionEvent"); - connection_event->Initialize(); - service_discovery = Kernel::KEvent::Create(kernel, "IBtmUserCore:Discovery"); - service_discovery->Initialize(); - config_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConfigEvent"); - config_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(scan_event)); + Kernel::KAutoObject::Create(std::addressof(connection_event)); + Kernel::KAutoObject::Create(std::addressof(service_discovery)); + Kernel::KAutoObject::Create(std::addressof(config_event)); + + scan_event.Initialize("IBtmUserCore:ScanEvent"); + connection_event.Initialize("IBtmUserCore:ConnectionEvent"); + service_discovery.Initialize("IBtmUserCore:Discovery"); + config_event.Initialize("IBtmUserCore:ConfigEvent"); } private: @@ -74,7 +77,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(scan_event->GetReadableEvent()); + rb.PushCopyObjects(scan_event.GetReadableEvent()); } void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) { @@ -82,7 +85,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(connection_event->GetReadableEvent()); + rb.PushCopyObjects(connection_event.GetReadableEvent()); } void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) { @@ -90,7 +93,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(service_discovery->GetReadableEvent()); + rb.PushCopyObjects(service_discovery.GetReadableEvent()); } void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) { @@ -98,13 +101,13 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(config_event->GetReadableEvent()); + rb.PushCopyObjects(config_event.GetReadableEvent()); } - std::shared_ptr<Kernel::KEvent> scan_event; - std::shared_ptr<Kernel::KEvent> connection_event; - std::shared_ptr<Kernel::KEvent> service_discovery; - std::shared_ptr<Kernel::KEvent> config_event; + Kernel::KEvent scan_event; + Kernel::KEvent connection_event; + Kernel::KEvent service_discovery; + Kernel::KEvent config_event; }; class BTM_USR final : public ServiceFramework<BTM_USR> { diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 13147472e..432abde76 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -12,7 +12,7 @@ #include "common/swap.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/fatal/fatal.h" #include "core/hle/service/fatal/fatal_p.h" #include "core/hle/service/fatal/fatal_u.h" diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 67b2b3102..67baaee9b 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -21,7 +21,7 @@ #include "core/file_sys/sdmc_factory.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_offset.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_ldr.h" #include "core/hle/service/filesystem/fsp_pr.h" diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 7dc487e48..92ea27074 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -25,7 +25,7 @@ #include "core/file_sys/system_archive/system_archive.h" #include "core/file_sys/vfs.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" #include "core/reporter.h" diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index a35979053..91c202952 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -185,7 +185,8 @@ private: class INotificationService final : public ServiceFramework<INotificationService> { public: explicit INotificationService(Common::UUID uuid_, Core::System& system_) - : ServiceFramework{system_, "INotificationService"}, uuid{uuid_} { + : ServiceFramework{system_, "INotificationService"}, uuid{uuid_}, notification_event{ + system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, &INotificationService::GetEvent, "GetEvent"}, @@ -196,9 +197,8 @@ public: RegisterHandlers(functions); - notification_event = - Kernel::KEvent::Create(system.Kernel(), "INotificationService:NotifyEvent"); - notification_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(notification_event)); + notification_event.Initialize("INotificationService:NotifyEvent"); } private: @@ -207,7 +207,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(notification_event->GetReadableEvent()); + rb.PushCopyObjects(notification_event.GetReadableEvent()); } void Clear(Kernel::HLERequestContext& ctx) { @@ -273,7 +273,7 @@ private: }; Common::UUID uuid{Common::INVALID_UUID}; - std::shared_ptr<Kernel::KEvent> notification_event; + Kernel::KEvent notification_event; std::queue<SizedNotificationInfo> notifications; States states{}; }; diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index 7b1c6677c..6ad62ee5a 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp @@ -9,8 +9,8 @@ #include "core/file_sys/control_metadata.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/glue/arp.h" #include "core/hle/service/glue/errors.h" #include "core/hle/service/glue/manager.h" diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index bb77d8959..9e5df3bb7 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -1,10 +1,9 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <cstring> -#include "common/common_types.h" #include "common/logging/log.h" +#include "common/math_util.h" #include "common/settings.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" @@ -12,10 +11,19 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; -constexpr f32 angle_threshold = 0.08f; -constexpr f32 pinch_threshold = 100.0f; -Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase{system_} {} +// HW is around 700, value is set to 400 to make it easier to trigger with mouse +constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s +constexpr f32 angle_threshold = 0.015f; // Threshold in radians +constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels +constexpr f32 press_delay = 0.5f; // Time in seconds +constexpr f32 double_tap_delay = 0.35f; // Time in seconds + +constexpr f32 Square(s32 num) { + return static_cast<f32>(num * num); +} + +Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {} Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { @@ -24,6 +32,8 @@ void Controller_Gesture::OnInit() { keyboard_finger_id[id] = MAX_POINTS; udp_finger_id[id] = MAX_POINTS; } + shared_memory.header.entry_count = 0; + force_update = true; } void Controller_Gesture::OnRelease() {} @@ -38,17 +48,23 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u shared_memory.header.last_entry_index = 0; return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + ReadTouchInput(); - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + GestureProperties gesture = GetGestureProperties(); + f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / + (1000 * 1000 * 1000); - // TODO(german77): Implement all gesture types + // Only update if necesary + if (!ShouldUpdateGesture(gesture, time_difference)) { + return; + } + last_update_timestamp = shared_memory.header.timestamp; + UpdateGestureSharedMemory(data, size, gesture, time_difference); +} + +void Controller_Gesture::ReadTouchInput() { const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); for (std::size_t id = 0; id < mouse_status.size(); ++id) { @@ -63,50 +79,71 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); } } +} - TouchType type = TouchType::Idle; - Attribute attributes{}; - GestureProperties gesture = GetGestureProperties(); - if (last_gesture.active_points != gesture.active_points) { - ++last_gesture.detection_count; +bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, + f32 time_difference) { + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + if (force_update) { + force_update = false; + return true; } - if (gesture.active_points > 0) { - if (last_gesture.active_points == 0) { - attributes.is_new_touch.Assign(true); - last_gesture.average_distance = gesture.average_distance; - last_gesture.angle = gesture.angle; - } - type = TouchType::Touch; - if (gesture.mid_point.x != last_entry.x || gesture.mid_point.y != last_entry.y) { - type = TouchType::Pan; - } - if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { - type = TouchType::Pinch; - } - if (std::abs(gesture.angle - last_gesture.angle) > angle_threshold) { - type = TouchType::Rotate; + // Update if coordinates change + for (size_t id = 0; id < MAX_POINTS; id++) { + if (gesture.points[id].x != last_gesture.points[id].x || + gesture.points[id].y != last_gesture.points[id].y) { + return true; } + } + + // Update on press and hold event after 0.5 seconds + if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && + time_difference > press_delay) { + return enable_press_and_tap; + } + + return false; +} + +void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, + GestureProperties& gesture, + f32 time_difference) { + TouchType type = TouchType::Idle; + Attribute attributes{}; + + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - cur_entry.delta_x = gesture.mid_point.x - last_entry.x; - cur_entry.delta_y = gesture.mid_point.y - last_entry.y; - // TODO: Find how velocities are calculated - cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f; - cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f; + if (shared_memory.header.entry_count < 16) { + shared_memory.header.entry_count++; + } - // Slowdown the rate of change for less flapping - last_gesture.average_distance = - (last_gesture.average_distance * 0.9f) + (gesture.average_distance * 0.1f); - last_gesture.angle = (last_gesture.angle * 0.9f) + (gesture.angle * 0.1f); + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + // Reset values to default + cur_entry.delta_x = 0; + cur_entry.delta_y = 0; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + cur_entry.direction = Direction::None; + cur_entry.rotation_angle = 0; + cur_entry.scale = 0; + + if (gesture.active_points > 0) { + if (last_gesture.active_points == 0) { + NewGesture(gesture, type, attributes); + } else { + UpdateExistingGesture(gesture, type, time_difference); + } } else { - cur_entry.delta_x = 0; - cur_entry.delta_y = 0; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; + EndGesture(gesture, last_gesture, type, attributes, time_difference); } - last_gesture.active_points = gesture.active_points; - cur_entry.detection_count = last_gesture.detection_count; + + // Apply attributes + cur_entry.detection_count = gesture.detection_count; cur_entry.type = type; cur_entry.attributes = attributes; cur_entry.x = gesture.mid_point.x; @@ -116,12 +153,190 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u cur_entry.points[id].x = gesture.points[id].x; cur_entry.points[id].y = gesture.points[id].y; } - cur_entry.rotation_angle = 0; - cur_entry.scale = 0; + last_gesture = gesture; std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } +void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, + Attribute& attributes) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + gesture.detection_count++; + type = TouchType::Touch; + + // New touch after cancel is not considered new + if (last_entry.type != TouchType::Cancel) { + attributes.is_new_touch.Assign(1); + enable_press_and_tap = true; + } +} + +void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, + f32 time_difference) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + + // Promote to pan type if touch moved + for (size_t id = 0; id < MAX_POINTS; id++) { + if (gesture.points[id].x != last_gesture.points[id].x || + gesture.points[id].y != last_gesture.points[id].y) { + type = TouchType::Pan; + break; + } + } + + // Number of fingers changed cancel the last event and clear data + if (gesture.active_points != last_gesture.active_points) { + type = TouchType::Cancel; + enable_press_and_tap = false; + gesture.active_points = 0; + gesture.mid_point = {}; + for (size_t id = 0; id < MAX_POINTS; id++) { + gesture.points[id].x = 0; + gesture.points[id].y = 0; + } + return; + } + + // Calculate extra parameters of panning + if (type == TouchType::Pan) { + UpdatePanEvent(gesture, last_gesture, type, time_difference); + return; + } + + // Promote to press type + if (last_entry.type == TouchType::Touch) { + type = TouchType::Press; + } +} + +void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, Attribute& attributes, f32 time_difference) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + if (last_gesture.active_points != 0) { + switch (last_entry.type) { + case TouchType::Touch: + if (enable_press_and_tap) { + SetTapEvent(gesture, last_gesture, type, attributes); + return; + } + type = TouchType::Cancel; + force_update = true; + break; + case TouchType::Press: + case TouchType::Tap: + case TouchType::Swipe: + case TouchType::Pinch: + case TouchType::Rotate: + type = TouchType::Complete; + force_update = true; + break; + case TouchType::Pan: + EndPanEvent(gesture, last_gesture, type, time_difference); + break; + default: + break; + } + return; + } + if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { + gesture.detection_count++; + } +} + +void Controller_Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, Attribute& attributes) { + type = TouchType::Tap; + gesture = last_gesture; + force_update = true; + f32 tap_time_difference = + static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); + last_tap_timestamp = last_update_timestamp; + if (tap_time_difference < double_tap_delay) { + attributes.is_double_tap.Assign(1); + } +} + +void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + cur_entry.delta_x = gesture.mid_point.x - last_entry.x; + cur_entry.delta_y = gesture.mid_point.y - last_entry.y; + + cur_entry.vel_x = static_cast<f32>(cur_entry.delta_x) / time_difference; + cur_entry.vel_y = static_cast<f32>(cur_entry.delta_y) / time_difference; + last_pan_time_difference = time_difference; + + // Promote to pinch type + if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { + type = TouchType::Pinch; + cur_entry.scale = gesture.average_distance / last_gesture.average_distance; + } + + const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) / + (1 + (gesture.angle * last_gesture.angle))); + // Promote to rotate type + if (std::abs(angle_between_two_lines) > angle_threshold) { + type = TouchType::Rotate; + cur_entry.scale = 0; + cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + } +} + +void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + cur_entry.vel_x = + static_cast<f32>(last_entry.delta_x) / (last_pan_time_difference + time_difference); + cur_entry.vel_y = + static_cast<f32>(last_entry.delta_y) / (last_pan_time_difference + time_difference); + const f32 curr_vel = + std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); + + // Set swipe event with parameters + if (curr_vel > swipe_threshold) { + SetSwipeEvent(gesture, last_gesture, type); + return; + } + + // End panning without swipe + type = TouchType::Complete; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + force_update = true; +} + +void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + type = TouchType::Swipe; + gesture = last_gesture; + force_update = true; + cur_entry.delta_x = last_entry.delta_x; + cur_entry.delta_y = last_entry.delta_y; + if (std::abs(cur_entry.delta_x) > std::abs(cur_entry.delta_y)) { + if (cur_entry.delta_x > 0) { + cur_entry.direction = Direction::Right; + return; + } + cur_entry.direction = Direction::Left; + return; + } + if (cur_entry.delta_y > 0) { + cur_entry.direction = Direction::Down; + return; + } + cur_entry.direction = Direction::Up; +} + void Controller_Gesture::OnLoadInputDevices() { touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); @@ -183,23 +398,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() for (size_t id = 0; id < gesture.active_points; ++id) { gesture.points[id].x = - static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width); + static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width); gesture.points[id].y = - static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height); - gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points); - gesture.mid_point.y += static_cast<int>(gesture.points[id].y / gesture.active_points); + static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height); + + // Hack: There is no touch in docked but games still allow it + if (Settings::values.use_docked_mode.GetValue()) { + gesture.points[id].x = + static_cast<s32>(active_fingers[id].x * Layout::ScreenDocked::Width); + gesture.points[id].y = + static_cast<s32>(active_fingers[id].y * Layout::ScreenDocked::Height); + } + + gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); + gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); } for (size_t id = 0; id < gesture.active_points; ++id) { - const double distance = - std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) + - std::pow(static_cast<float>(gesture.mid_point.y - gesture.points[id].y), 2); - gesture.average_distance += - static_cast<float>(distance) / static_cast<float>(gesture.active_points); + const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + + Square(gesture.mid_point.y - gesture.points[id].y)); + gesture.average_distance += distance / static_cast<f32>(gesture.active_points); } - gesture.angle = std::atan2(static_cast<float>(gesture.mid_point.y - gesture.points[0].y), - static_cast<float>(gesture.mid_point.x - gesture.points[0].x)); + gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), + static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); + + gesture.detection_count = last_gesture.detection_count; + return gesture; } diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7c357b977..18110a6ad 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -1,4 +1,4 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -7,7 +7,6 @@ #include <array> #include "common/bit_field.h" #include "common/common_types.h" -#include "common/swap.h" #include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" @@ -35,10 +34,10 @@ private: enum class TouchType : u32 { Idle, // Nothing touching the screen - Complete, // Unknown. End of touch? - Cancel, // Never triggered - Touch, // Pressing without movement - Press, // Never triggered + Complete, // Set at the end of a touch event + Cancel, // Set when the number of fingers change + Touch, // A finger just touched the screen + Press, // Set if last type is touch and the finger hasn't moved Tap, // Fast press then release Pan, // All points moving together across the screen Swipe, // Fast press movement and release of a single point @@ -58,8 +57,8 @@ private: union { u32_le raw{}; - BitField<0, 1, u32> is_new_touch; - BitField<1, 1, u32> is_double_tap; + BitField<4, 1, u32> is_new_touch; + BitField<8, 1, u32> is_double_tap; }; }; static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); @@ -73,10 +72,9 @@ private: struct GestureState { s64_le sampling_number; s64_le sampling_number2; - s64_le detection_count; TouchType type; - Direction dir; + Direction direction; s32_le x; s32_le y; s32_le delta_x; @@ -84,8 +82,8 @@ private: f32 vel_x; f32 vel_y; Attribute attributes; - u32 scale; - u32 rotation_angle; + f32 scale; + f32 rotation_angle; s32_le point_count; std::array<Points, 4> points; }; @@ -109,10 +107,46 @@ private: Points mid_point{}; s64_le detection_count{}; u64_le delta_time{}; - float average_distance{}; - float angle{}; + f32 average_distance{}; + f32 angle{}; }; + // Reads input from all available input engines + void ReadTouchInput(); + + // Returns true if gesture state needs to be updated + bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); + + // Updates the shared memory to the next state + void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, + f32 time_difference); + + // Initializes new gesture + void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); + + // Updates existing gesture state + void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); + + // Terminates exiting gesture + void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + Attribute& attributes, f32 time_difference); + + // Set current event to a tap event + void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + Attribute& attributes); + + // Calculates and set the extra parameters related to a pan event + void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference); + + // Terminates the pan event + void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + f32 time_difference); + + // Set current event to a swipe event + void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type); + // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned std::optional<size_t> GetUnusedFingerID() const; @@ -134,6 +168,11 @@ private: std::array<size_t, MAX_FINGERS> keyboard_finger_id; std::array<size_t, MAX_FINGERS> udp_finger_id; std::array<Finger, MAX_POINTS> fingers; - GestureProperties last_gesture; + GestureProperties last_gesture{}; + s64_le last_update_timestamp{}; + s64_le last_tap_timestamp{}; + f32 last_pan_time_difference{}; + bool force_update{false}; + bool enable_press_and_tap{false}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index d4678ef49..7acad3798 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -159,7 +159,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { const auto controller_type = connected_controllers[controller_idx].type; auto& controller = shared_memory_entries[controller_idx]; if (controller_type == NPadControllerType::None) { - styleset_changed_events[controller_idx]->GetWritableEvent()->Signal(); + styleset_changed_events[controller_idx]->GetWritableEvent().Signal(); return; } controller.style_set.raw = 0; // Zero out @@ -253,9 +253,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { void Controller_NPad::OnInit() { auto& kernel = system.Kernel(); for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { - styleset_changed_events[i] = - Kernel::KEvent::Create(kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); - styleset_changed_events[i]->Initialize(); + styleset_changed_events[i] = Kernel::KEvent::Create(kernel); + styleset_changed_events[i]->Initialize(fmt::format("npad:NpadStyleSetChanged_{}", i)); } if (!IsControllerActivated()) { @@ -341,6 +340,11 @@ void Controller_NPad::OnRelease() { VibrateControllerAtIndex(npad_idx, device_idx, {}); } } + + for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { + styleset_changed_events[i]->Close(); + styleset_changed_events[i] = nullptr; + } } void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { @@ -955,14 +959,12 @@ bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_dev return vibration_devices_mounted[npad_index][device_index]; } -std::shared_ptr<Kernel::KReadableEvent> Controller_NPad::GetStyleSetChangedEvent( - u32 npad_id) const { - const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; - return styleset_event->GetReadableEvent(); +Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) { + return styleset_changed_events[NPadIdToIndex(npad_id)]->GetReadableEvent(); } void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { - styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent()->Signal(); + styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal(); } void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index ea484d4bf..c050c9a44 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -11,7 +11,6 @@ #include "common/quaternion.h" #include "common/settings.h" #include "core/frontend/input.h" -#include "core/hle/kernel/object.h" #include "core/hle/service/hid/controllers/controller_base.h" namespace Kernel { @@ -199,7 +198,7 @@ public: bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; - std::shared_ptr<Kernel::KReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; + Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id); void SignalStyleSetChangedEvent(u32 npad_id) const; // Adds a new controller at an index. @@ -573,8 +572,9 @@ private: NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; // Each controller should have their own styleset changed event - std::array<std::shared_ptr<Kernel::KEvent>, 10> styleset_changed_events; - std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints; + std::array<Kernel::KEvent*, 10> styleset_changed_events{}; + std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> + last_vibration_timepoints{}; std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; bool permit_vibration_session_enabled{false}; std::array<std::array<bool, 2>, 10> vibration_devices_mounted{}; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 9c4bf6d16..49c17fd14 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -13,18 +13,18 @@ #include "core/frontend/input.h" #include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/transfer_memory.h" #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/irs.h" #include "core/hle/service/hid/xcd.h" #include "core/hle/service/service.h" +#include "core/memory.h" #include "core/hle/service/hid/controllers/console_sixaxis.h" #include "core/hle/service/hid/controllers/controller_base.h" @@ -53,9 +53,6 @@ IAppletResource::IAppletResource(Core::System& system_) }; RegisterHandlers(functions); - auto& kernel = system.Kernel(); - shared_mem = SharedFrom(&kernel.GetHidSharedMem()); - MakeController<Controller_DebugPad>(HidController::DebugPad); MakeController<Controller_Touchscreen>(HidController::Touchscreen); MakeController<Controller_Mouse>(HidController::Mouse); @@ -118,7 +115,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(shared_mem); + rb.PushCopyObjects(&system.Kernel().GetHidSharedMem()); } void IAppletResource::UpdateControllers(std::uintptr_t user_data, @@ -130,7 +127,8 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, if (should_reload) { controller->OnLoadInputDevices(); } - controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); + controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), + SHARED_MEMORY_SIZE); } // If ns_late is higher than the update rate ignore the delay @@ -145,7 +143,7 @@ void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose auto& core_timing = system.CoreTiming(); controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate( - core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); + core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); // If ns_late is higher than the update rate ignore the delay if (ns_late > motion_update_ns) { @@ -1496,20 +1494,20 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); - auto t_mem_1 = - system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_1_handle); + auto t_mem_1 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + t_mem_1_handle); - if (t_mem_1 == nullptr) { + if (t_mem_1.IsNull()) { LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_UNKNOWN); return; } - auto t_mem_2 = - system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_2_handle); + auto t_mem_2 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + t_mem_2_handle); - if (t_mem_2 == nullptr) { + if (t_mem_2.IsNull()) { LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_UNKNOWN); @@ -1524,7 +1522,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { .ActivateController(); applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor) - .SetTransferMemoryPointer(t_mem_1->GetPointer()); + .SetTransferMemoryPointer(system.Memory().GetPointer(t_mem_1->GetSourceAddress())); LOG_WARNING(Service_HID, "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, " diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index c2bdd39a3..aa3307955 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -13,10 +13,6 @@ namespace Core::Timing { struct EventType; } -namespace Kernel { -class KSharedMemory; -} - namespace Service::SM { class ServiceManager; } @@ -69,8 +65,6 @@ private: void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); - std::shared_ptr<Kernel::KSharedMemory> shared_mem; - std::shared_ptr<Core::Timing::EventType> pad_update_event; std::shared_ptr<Core::Timing::EventType> motion_update_event; diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 2dfa936fb..3c6085990 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -37,10 +37,6 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { // clang-format on RegisterHandlers(functions); - - auto& kernel = system.Kernel(); - - shared_mem = SharedFrom(&kernel.GetIrsSharedMem()); } void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { @@ -62,7 +58,7 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(shared_mem); + rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem()); } void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index b0c8c7168..9bc6462b0 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -4,17 +4,12 @@ #pragma once -#include "core/hle/kernel/object.h" #include "core/hle/service/service.h" namespace Core { class System; } -namespace Kernel { -class KSharedMemory; -} - namespace Service::HID { class IRS final : public ServiceFramework<IRS> { @@ -42,7 +37,6 @@ private: void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); - std::shared_ptr<Kernel::KSharedMemory> shared_mem; const u32 device_handle{0xABCD}; }; diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index c8bc60ad1..c3948eb8e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -12,8 +12,8 @@ #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_system_control.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/service/ldr/ldr.h" #include "core/hle/service/service.h" @@ -321,7 +321,7 @@ public: return addr; } - ResultVal<VAddr> MapProcessCodeMemory(Kernel::Process* process, VAddr baseAddress, + ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr baseAddress, u64 size) const { for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { auto& page_table{process->PageTable()}; @@ -342,7 +342,7 @@ public: return ERROR_INSUFFICIENT_ADDRESS_SPACE; } - ResultVal<VAddr> MapNro(Kernel::Process* process, VAddr nro_addr, std::size_t nro_size, + ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) const { for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { auto& page_table{process->PageTable()}; @@ -378,7 +378,7 @@ public: return ERROR_INSUFFICIENT_ADDRESS_SPACE; } - ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, + ResultCode LoadNro(Kernel::KProcess* process, const NROHeader& nro_header, VAddr nro_addr, VAddr start) const { const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset}; const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset}; @@ -387,11 +387,9 @@ public: const VAddr bss_end_addr{ Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)}; - auto CopyCode{[&](VAddr src_addr, VAddr dst_addr, u64 size) { - std::vector<u8> source_data(size); - system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); - system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size()); - }}; + const auto CopyCode = [this, process](VAddr src_addr, VAddr dst_addr, u64 size) { + system.Memory().CopyBlock(*process, dst_addr, src_addr, size); + }; CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start, nro_header.segment_headers[TEXT_INDEX].memory_size); CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start, diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index b0cb07d24..c8519e2db 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp @@ -4,7 +4,6 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/service/mm/mm_u.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 2d1d4d67f..d25b20ab5 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -8,7 +8,6 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" @@ -24,10 +23,9 @@ constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, const char* name) - : ServiceFramework{system_, name}, module{std::move(module_)} { - auto& kernel = system.Kernel(); - nfc_tag_load = Kernel::KEvent::Create(kernel, "IUser:NFCTagDetected"); - nfc_tag_load->Initialize(); + : ServiceFramework{system_, name}, nfc_tag_load{system.Kernel()}, module{std::move(module_)} { + Kernel::KAutoObject::Create(std::addressof(nfc_tag_load)); + nfc_tag_load.Initialize("IUser:NFCTagDetected"); } Module::Interface::~Interface() = default; @@ -35,7 +33,8 @@ Module::Interface::~Interface() = default; class IUser final : public ServiceFramework<IUser> { public: explicit IUser(Module::Interface& nfp_interface_, Core::System& system_) - : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_} { + : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_}, + deactivate_event{system.Kernel()}, availability_change_event{system.Kernel()} { static const FunctionInfo functions[] = { {0, &IUser::Initialize, "Initialize"}, {1, &IUser::Finalize, "Finalize"}, @@ -65,11 +64,11 @@ public: }; RegisterHandlers(functions); - auto& kernel = system.Kernel(); - deactivate_event = Kernel::KEvent::Create(kernel, "IUser:DeactivateEvent"); - deactivate_event->Initialize(); - availability_change_event = Kernel::KEvent::Create(kernel, "IUser:AvailabilityChangeEvent"); - availability_change_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(deactivate_event)); + Kernel::KAutoObject::Create(std::addressof(availability_change_event)); + + deactivate_event.Initialize("IUser:DeactivateEvent"); + availability_change_event.Initialize("IUser:AvailabilityChangeEvent"); } private: @@ -167,7 +166,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(deactivate_event->GetReadableEvent()); + rb.PushCopyObjects(deactivate_event.GetReadableEvent()); } void StopDetection(Kernel::HLERequestContext& ctx) { @@ -176,7 +175,7 @@ private: switch (device_state) { case DeviceState::TagFound: case DeviceState::TagNearby: - deactivate_event->GetWritableEvent()->Signal(); + deactivate_event.GetWritableEvent().Signal(); device_state = DeviceState::Initialized; break; case DeviceState::SearchingForTag: @@ -265,7 +264,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(availability_change_event->GetReadableEvent()); + rb.PushCopyObjects(availability_change_event.GetReadableEvent()); } void GetRegisterInfo(Kernel::HLERequestContext& ctx) { @@ -319,9 +318,9 @@ private: const u32 npad_id{0}; // Player 1 controller State state{State::NonInitialized}; DeviceState device_state{DeviceState::Initialized}; - std::shared_ptr<Kernel::KEvent> deactivate_event; - std::shared_ptr<Kernel::KEvent> availability_change_event; - const Module::Interface& nfp_interface; + Module::Interface& nfp_interface; + Kernel::KEvent deactivate_event; + Kernel::KEvent availability_change_event; }; void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { @@ -339,12 +338,12 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { } std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); - nfc_tag_load->GetWritableEvent()->Signal(); + nfc_tag_load.GetWritableEvent().Signal(); return true; } -const std::shared_ptr<Kernel::KReadableEvent>& Module::Interface::GetNFCEvent() const { - return nfc_tag_load->GetReadableEvent(); +Kernel::KReadableEvent& Module::Interface::GetNFCEvent() { + return nfc_tag_load.GetReadableEvent(); } const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index c46551760..5e4e49bc6 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -7,6 +7,7 @@ #include <array> #include <vector> +#include "core/hle/kernel/k_event.h" #include "core/hle/service/service.h" namespace Kernel { @@ -38,11 +39,11 @@ public: void CreateUserInterface(Kernel::HLERequestContext& ctx); bool LoadAmiibo(const std::vector<u8>& buffer); - const std::shared_ptr<Kernel::KReadableEvent>& GetNFCEvent() const; + Kernel::KReadableEvent& GetNFCEvent(); const AmiiboFile& GetAmiiboBuffer() const; private: - std::shared_ptr<Kernel::KEvent> nfc_tag_load; + Kernel::KEvent nfc_tag_load; AmiiboFile amiibo{}; protected: diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 9f110df8e..94ef3983a 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -127,7 +127,8 @@ public: class IRequest final : public ServiceFramework<IRequest> { public: - explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} { + explicit IRequest(Core::System& system_) + : ServiceFramework{system_, "IRequest"}, event1{system.Kernel()}, event2{system.Kernel()} { static const FunctionInfo functions[] = { {0, &IRequest::GetRequestState, "GetRequestState"}, {1, &IRequest::GetResult, "GetResult"}, @@ -157,12 +158,11 @@ public: }; RegisterHandlers(functions); - auto& kernel = system.Kernel(); + Kernel::KAutoObject::Create(std::addressof(event1)); + Kernel::KAutoObject::Create(std::addressof(event2)); - event1 = Kernel::KEvent::Create(kernel, "IRequest:Event1"); - event1->Initialize(); - event2 = Kernel::KEvent::Create(kernel, "IRequest:Event2"); - event2->Initialize(); + event1.Initialize("IRequest:Event1"); + event2.Initialize("IRequest:Event2"); } private: @@ -198,7 +198,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 2}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent()); + rb.PushCopyObjects(event1.GetReadableEvent(), event2.GetReadableEvent()); } void Cancel(Kernel::HLERequestContext& ctx) { @@ -229,7 +229,7 @@ private: rb.Push<u32>(0); } - std::shared_ptr<Kernel::KEvent> event1, event2; + Kernel::KEvent event1, event2; }; class INetworkProfile final : public ServiceFramework<INetworkProfile> { diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index fee360ab9..420a5a075 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -300,7 +300,8 @@ class IEnsureNetworkClockAvailabilityService final : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { public: explicit IEnsureNetworkClockAvailabilityService(Core::System& system_) - : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"} { + : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"}, + finished_event{system.Kernel()} { static const FunctionInfo functions[] = { {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent, @@ -312,19 +313,17 @@ public: }; RegisterHandlers(functions); - auto& kernel = system.Kernel(); - finished_event = - Kernel::KEvent::Create(kernel, "IEnsureNetworkClockAvailabilityService:FinishEvent"); - finished_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(finished_event)); + finished_event.Initialize("IEnsureNetworkClockAvailabilityService:FinishEvent"); } private: - std::shared_ptr<Kernel::KEvent> finished_event; + Kernel::KEvent finished_event; void StartTask(Kernel::HLERequestContext& ctx) { // No need to connect to the internet, just finish the task straight away. LOG_DEBUG(Service_NIM, "called"); - finished_event->GetWritableEvent()->Signal(); + finished_event.GetWritableEvent().Signal(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -334,7 +333,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(finished_event->GetReadableEvent()); + rb.PushCopyObjects(finished_event.GetReadableEvent()); } void GetResult(Kernel::HLERequestContext& ctx) { @@ -346,7 +345,7 @@ private: void Cancel(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NIM, "called"); - finished_event->GetWritableEvent()->Clear(); + finished_event.GetWritableEvent().Clear(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index da139fdc4..e14acce58 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -130,9 +130,6 @@ struct PL_U::Impl { } } - /// Handle to shared memory region designated for a shared font - std::shared_ptr<Kernel::KSharedMemory> shared_font_mem; - /// Backing memory for the shared font data std::shared_ptr<Kernel::PhysicalMemory> shared_font; @@ -260,14 +257,13 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { // Create shared font memory object auto& kernel = system.Kernel(); - impl->shared_font_mem = SharedFrom(&kernel.GetFontSharedMem()); - std::memcpy(impl->shared_font_mem->GetPointer(), impl->shared_font->data(), + std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(), impl->shared_font->size()); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(impl->shared_font_mem); + rb.PushCopyObjects(&kernel.GetFontSharedMem()); } void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 6f4007294..775e76330 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -102,20 +102,20 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector return NvResult::Success; } - auto event = events_interface.events[event_id]; + auto& event = events_interface.events[event_id]; auto& gpu = system.GPU(); // This is mostly to take into account unimplemented features. As synced // gpu is always synced. if (!gpu.IsAsync()) { - event.event->GetWritableEvent()->Signal(); + event.event->GetWritableEvent().Signal(); return NvResult::Success; } auto lock = gpu.LockSync(); const u32 current_syncpoint_value = event.fence.value; const s32 diff = current_syncpoint_value - params.threshold; if (diff >= 0) { - event.event->GetWritableEvent()->Signal(); + event.event->GetWritableEvent().Signal(); params.value = current_syncpoint_value; std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; @@ -142,7 +142,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; } params.value |= event_id; - event.event->GetWritableEvent()->Clear(); + event.event->GetWritableEvent().Clear(); gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Timeout; diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index eff9c3cc9..dc9b9341f 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -187,8 +187,8 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { if (event_id < MaxNvEvents) { IPC::ResponseBuilder rb{ctx, 3, 1}; rb.Push(RESULT_SUCCESS); - auto event = nvdrv->GetEvent(event_id); - event->Clear(); + auto& event = nvdrv->GetEvent(event_id); + event.Clear(); rb.PushCopyObjects(event); rb.PushEnum(NvResult::Success); } else { diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index ede77858a..74796dce1 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -42,9 +42,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { auto& kernel = system.Kernel(); for (u32 i = 0; i < MaxNvEvents; i++) { - std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); - events_interface.events[i] = {Kernel::KEvent::Create(kernel, std::move(event_label))}; - events_interface.events[i].event->Initialize(); + events_interface.events[i].event = Kernel::KEvent::Create(kernel); + events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i)); events_interface.status[i] = EventState::Free; events_interface.registered[i] = false; } @@ -64,7 +63,12 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { std::make_shared<Devices::nvhost_vic>(system, nvmap_dev, syncpoint_manager); } -Module::~Module() = default; +Module::~Module() { + for (u32 i = 0; i < MaxNvEvents; i++) { + events_interface.events[i].event->Close(); + events_interface.events[i].event = nullptr; + } +} NvResult Module::VerifyFD(DeviceFD fd) const { if (fd < 0) { @@ -172,16 +176,16 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { if (events_interface.assigned_syncpt[i] == syncpoint_id && events_interface.assigned_value[i] == value) { events_interface.LiberateEvent(i); - events_interface.events[i].event->GetWritableEvent()->Signal(); + events_interface.events[i].event->GetWritableEvent().Signal(); } } } -std::shared_ptr<Kernel::KReadableEvent> Module::GetEvent(const u32 event_id) const { +Kernel::KReadableEvent& Module::GetEvent(const u32 event_id) { return events_interface.events[event_id].event->GetReadableEvent(); } -std::shared_ptr<Kernel::KWritableEvent> Module::GetEventWriteable(const u32 event_id) const { +Kernel::KWritableEvent& Module::GetEventWriteable(const u32 event_id) { return events_interface.events[event_id].event->GetWritableEvent(); } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 53719aadd..a43ceb7ae 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -35,7 +35,7 @@ class nvdevice; /// Represents an Nvidia event struct NvEvent { - std::shared_ptr<Kernel::KEvent> event; + Kernel::KEvent* event{}; Fence fence{}; }; @@ -136,9 +136,9 @@ public: void SignalSyncpt(const u32 syncpoint_id, const u32 value); - std::shared_ptr<Kernel::KReadableEvent> GetEvent(u32 event_id) const; + Kernel::KReadableEvent& GetEvent(u32 event_id); - std::shared_ptr<Kernel::KWritableEvent> GetEventWriteable(u32 event_id) const; + Kernel::KWritableEvent& GetEventWriteable(u32 event_id); private: /// Manages syncpoints on the host diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 7842a82ed..0b6e7430b 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -7,7 +7,6 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/nvflinger/buffer_queue.h" @@ -15,9 +14,9 @@ namespace Service::NVFlinger { BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) - : id(id), layer_id(layer_id) { - buffer_wait_event = Kernel::KEvent::Create(kernel, "BufferQueue:WaitEvent"); - buffer_wait_event->Initialize(); + : id(id), layer_id(layer_id), buffer_wait_event{kernel} { + Kernel::KAutoObject::Create(std::addressof(buffer_wait_event)); + buffer_wait_event.Initialize("BufferQueue:WaitEvent"); } BufferQueue::~BufferQueue() = default; @@ -42,7 +41,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) .multi_fence = {}, }; - buffer_wait_event->GetWritableEvent()->Signal(); + buffer_wait_event.GetWritableEvent().Signal(); } std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, @@ -120,7 +119,7 @@ void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& mult } free_buffers_condition.notify_one(); - buffer_wait_event->GetWritableEvent()->Signal(); + buffer_wait_event.GetWritableEvent().Signal(); } std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { @@ -155,7 +154,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) { } free_buffers_condition.notify_one(); - buffer_wait_event->GetWritableEvent()->Signal(); + buffer_wait_event.GetWritableEvent().Signal(); } void BufferQueue::Connect() { @@ -170,7 +169,7 @@ void BufferQueue::Disconnect() { std::unique_lock lock{queue_sequence_mutex}; queue_sequence.clear(); } - buffer_wait_event->GetWritableEvent()->Signal(); + buffer_wait_event.GetWritableEvent().Signal(); is_connect = false; free_buffers_condition.notify_one(); } @@ -189,12 +188,12 @@ u32 BufferQueue::Query(QueryType type) { return 0; } -std::shared_ptr<Kernel::KWritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { - return buffer_wait_event->GetWritableEvent(); +Kernel::KWritableEvent& BufferQueue::GetWritableBufferWaitEvent() { + return buffer_wait_event.GetWritableEvent(); } -std::shared_ptr<Kernel::KReadableEvent> BufferQueue::GetBufferWaitEvent() const { - return buffer_wait_event->GetReadableEvent(); +Kernel::KReadableEvent& BufferQueue::GetBufferWaitEvent() { + return buffer_wait_event.GetReadableEvent(); } } // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 163fa4c54..4ec0b1506 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -13,7 +13,8 @@ #include "common/common_funcs.h" #include "common/math_util.h" #include "common/swap.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/nvdrv/nvdata.h" namespace Kernel { @@ -115,9 +116,9 @@ public: return is_connect; } - std::shared_ptr<Kernel::KWritableEvent> GetWritableBufferWaitEvent() const; + Kernel::KWritableEvent& GetWritableBufferWaitEvent(); - std::shared_ptr<Kernel::KReadableEvent> GetBufferWaitEvent() const; + Kernel::KReadableEvent& GetBufferWaitEvent(); private: BufferQueue(const BufferQueue&) = delete; @@ -129,7 +130,7 @@ private: std::list<u32> free_buffers; std::array<Buffer, buffer_slots> buffers; std::list<u32> queue_sequence; - std::shared_ptr<Kernel::KEvent> buffer_wait_event; + Kernel::KEvent buffer_wait_event; std::mutex free_buffers_mutex; std::condition_variable free_buffers_condition; diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index c43593e7f..7fb9133c7 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -165,7 +165,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co return layer->GetBufferQueue().GetId(); } -std::shared_ptr<Kernel::KReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { +Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) { const auto lock_guard = Lock(); auto* const display = FindDisplay(display_id); @@ -173,7 +173,7 @@ std::shared_ptr<Kernel::KReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id return nullptr; } - return display->GetVSyncEvent(); + return &display->GetVSyncEvent(); } BufferQueue* NVFlinger::FindBufferQueue(u32 id) { diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 6fe2c7f2a..b0febdaec 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -5,6 +5,7 @@ #pragma once #include <atomic> +#include <list> #include <memory> #include <mutex> #include <optional> @@ -14,7 +15,6 @@ #include <vector> #include "common/common_types.h" -#include "core/hle/kernel/object.h" namespace Common { class Event; @@ -72,7 +72,7 @@ public: /// Gets the vsync event for the specified display. /// /// If an invalid display ID is provided, then nullptr is returned. - [[nodiscard]] std::shared_ptr<Kernel::KReadableEvent> FindVsyncEvent(u64 display_id) const; + [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id); /// Obtains a buffer queue identified by the ID. [[nodiscard]] BufferQueue* FindBufferQueue(u32 id); @@ -106,7 +106,7 @@ private: std::shared_ptr<Nvidia::Module> nvdrv; - std::vector<VI::Display> displays; + std::list<VI::Display> displays; std::vector<std::unique_ptr<BufferQueue>> buffer_queues; /// Id to use for the next layer that is created, this counter is shared among all displays. diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index 9bebe6088..1c3d81143 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp @@ -7,7 +7,7 @@ #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/pctl/module.h" #include "core/hle/service/pctl/pctl.h" diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 68736c40c..f4715935d 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -4,8 +4,8 @@ #include "core/core.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/pm/pm.h" #include "core/hle/service/service.h" @@ -17,9 +17,9 @@ constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1}; constexpr u64 NO_PROCESS_FOUND_PID{0}; -std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList( - const std::vector<std::shared_ptr<Kernel::Process>>& process_list, - std::function<bool(const std::shared_ptr<Kernel::Process>&)> predicate) { +std::optional<Kernel::KProcess*> SearchProcessList( + const std::vector<Kernel::KProcess*>& process_list, + std::function<bool(Kernel::KProcess*)> predicate) { const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); if (iter == process_list.end()) { @@ -30,9 +30,9 @@ std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList( } void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx, - const std::vector<std::shared_ptr<Kernel::Process>>& process_list) { + const std::vector<Kernel::KProcess*>& process_list) { const auto process = SearchProcessList(process_list, [](const auto& process) { - return process->GetProcessID() == Kernel::Process::ProcessIDMin; + return process->GetProcessID() == Kernel::KProcess::ProcessIDMin; }); IPC::ResponseBuilder rb{ctx, 4}; @@ -125,8 +125,7 @@ private: class Info final : public ServiceFramework<Info> { public: - explicit Info(Core::System& system_, - const std::vector<std::shared_ptr<Kernel::Process>>& process_list_) + explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { static const FunctionInfo functions[] = { {0, &Info::GetTitleId, "GetTitleId"}, @@ -156,7 +155,7 @@ private: rb.Push((*process)->GetTitleID()); } - const std::vector<std::shared_ptr<Kernel::Process>>& process_list; + const std::vector<Kernel::KProcess*>& process_list; }; class Shell final : public ServiceFramework<Shell> { diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index d5b3b17a5..c914f8145 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -6,7 +6,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/prepo/prepo.h" #include "core/hle/service/service.h" @@ -60,7 +60,7 @@ private: const auto process_id = rp.PopRaw<u64>(); const auto data1 = ctx.ReadBuffer(0); - const auto data2 = [ctx] { + const auto data2 = [&ctx] { if (ctx.CanReadBuffer(1)) { return ctx.ReadBuffer(1); } @@ -87,7 +87,7 @@ private: const auto process_id = rp.PopRaw<u64>(); const auto data1 = ctx.ReadBuffer(0); - const auto data2 = [ctx] { + const auto data2 = [&ctx] { if (ctx.CanReadBuffer(1)) { return ctx.ReadBuffer(1); } @@ -139,7 +139,7 @@ private: const auto title_id = rp.PopRaw<u64>(); const auto data1 = ctx.ReadBuffer(0); - const auto data2 = [ctx] { + const auto data2 = [&ctx] { if (ctx.CanReadBuffer(1)) { return ctx.ReadBuffer(1); } @@ -163,7 +163,7 @@ private: const auto title_id = rp.PopRaw<u64>(); const auto data1 = ctx.ReadBuffer(0); - const auto data2 = [ctx] { + const auto data2 = [&ctx] { if (ctx.CanReadBuffer(1)) { return ctx.ReadBuffer(1); } diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp index 26ed52273..bb7af9217 100644 --- a/src/core/hle/service/ptm/psm.cpp +++ b/src/core/hle/service/ptm/psm.cpp @@ -19,7 +19,8 @@ namespace Service::PSM { class IPsmSession final : public ServiceFramework<IPsmSession> { public: - explicit IPsmSession(Core::System& system_) : ServiceFramework{system_, "IPsmSession"} { + explicit IPsmSession(Core::System& system_) + : ServiceFramework{system_, "IPsmSession"}, state_change_event{system.Kernel()} { // clang-format off static const FunctionInfo functions[] = { {0, &IPsmSession::BindStateChangeEvent, "BindStateChangeEvent"}, @@ -32,28 +33,27 @@ public: RegisterHandlers(functions); - state_change_event = - Kernel::KEvent::Create(system_.Kernel(), "IPsmSession::state_change_event"); - state_change_event->Initialize(); + Kernel::KAutoObject::Create(std::addressof(state_change_event)); + state_change_event.Initialize("IPsmSession::state_change_event"); } ~IPsmSession() override = default; void SignalChargerTypeChanged() { if (should_signal && should_signal_charger_type) { - state_change_event->GetWritableEvent()->Signal(); + state_change_event.GetWritableEvent().Signal(); } } void SignalPowerSupplyChanged() { if (should_signal && should_signal_power_supply) { - state_change_event->GetWritableEvent()->Signal(); + state_change_event.GetWritableEvent().Signal(); } } void SignalBatteryVoltageStateChanged() { if (should_signal && should_signal_battery_voltage) { - state_change_event->GetWritableEvent()->Signal(); + state_change_event.GetWritableEvent().Signal(); } } @@ -65,7 +65,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(state_change_event->GetReadableEvent()); + rb.PushCopyObjects(state_change_event.GetReadableEvent()); } void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) { @@ -114,7 +114,7 @@ private: bool should_signal_power_supply{}; bool should_signal_battery_voltage{}; bool should_signal{}; - std::shared_ptr<Kernel::KEvent> state_change_event; + Kernel::KEvent state_change_event; }; class PSM final : public ServiceFramework<PSM> { diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 41a502d8d..00e683c2f 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -11,11 +11,11 @@ #include "core/core.h" #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_port.h" #include "core/hle/service/acc/acc.h" #include "core/hle/service/am/am.h" #include "core/hle/service/aoc/aoc_u.h" @@ -116,10 +116,11 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { ASSERT(!port_installed); - auto [server_port, client_port] = - Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); - server_port->SetHleHandler(shared_from_this()); - kernel.AddNamedPort(service_name, std::move(client_port)); + auto* port = Kernel::KPort::Create(kernel); + port->Initialize(max_sessions, false, service_name); + port->GetServerPort().SetHleHandler(shared_from_this()); + kernel.AddNamedPort(service_name, &port->GetClientPort()); + port_installed = true; } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 916445517..884951428 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -11,7 +11,6 @@ #include "common/common_types.h" #include "common/spin_lock.h" #include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/object.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service @@ -21,11 +20,8 @@ class System; } namespace Kernel { -class ClientPort; -class ServerPort; -class ServerSession; class HLERequestContext; -} // namespace Kernel +} namespace Service { diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 5909fdd85..4f1ffe55f 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp @@ -7,7 +7,7 @@ #include "core/file_sys/errors.h" #include "core/file_sys/system_archive/system_version.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/set/set_sys.h" diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 916177efd..ee026e22f 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -5,16 +5,16 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/service/sm/controller.h" namespace Service::SM { void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); - LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); + LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); ctx.Session()->ConvertToDomain(); IPC::ResponseBuilder rb{ctx, 3}; @@ -30,7 +30,7 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(ctx.Session()->GetParent()->Client()); + rb.PushMoveObjects(ctx.Session()->GetParent()->GetClientSession()); } void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 94608d529..568effbc9 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -6,9 +6,12 @@ #include "common/assert.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/result.h" #include "core/hle/service/sm/controller.h" #include "core/hle/service/sm/sm.h" @@ -47,8 +50,8 @@ void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Cor self->controller_interface = std::make_unique<Controller>(system); } -ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name, - u32 max_sessions) { +ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, + u32 max_sessions) { CASCADE_CODE(ValidateServiceName(name)); @@ -57,11 +60,12 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(s return ERR_ALREADY_REGISTERED; } - auto [server_port, client_port] = - Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name); + auto* port = Kernel::KPort::Create(kernel); + port->Initialize(max_sessions, false, name); - registered_services.emplace(std::move(name), std::move(client_port)); - return MakeResult(std::move(server_port)); + registered_services.emplace(std::move(name), port); + + return MakeResult(&port->GetServerPort()); } ResultCode ServiceManager::UnregisterService(const std::string& name) { @@ -72,12 +76,14 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) { LOG_ERROR(Service_SM, "Server is not registered! service={}", name); return ERR_SERVICE_NOT_REGISTERED; } + + iter->second->Close(); + registered_services.erase(iter); return RESULT_SUCCESS; } -ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( - const std::string& name) { +ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) { CASCADE_CODE(ValidateServiceName(name)); auto it = registered_services.find(name); @@ -89,13 +95,6 @@ ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( return MakeResult(it->second); } -ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService( - const std::string& name) { - - CASCADE_RESULT(auto client_port, GetServicePort(name)); - return client_port->Connect(); -} - SM::~SM() = default; /** @@ -119,30 +118,32 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { std::string name(name_buf.begin(), end); - auto client_port = service_manager->GetServicePort(name); - if (client_port.Failed()) { + auto result = service_manager->GetServicePort(name); + if (result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(client_port.Code()); - LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); + rb.Push(result.Code()); + LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); if (name.length() == 0) return; // LibNX Fix UNIMPLEMENTED(); return; } - auto [client, server] = Kernel::Session::Create(kernel, name); + auto* port = result.Unwrap(); - const auto& server_port = client_port.Unwrap()->GetServerPort(); - if (server_port->GetHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(server); + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(&port->GetClientPort(), std::move(name)); + + if (port->GetServerPort().GetHLEHandler()) { + port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); } else { - server_port->AppendPendingSession(server); + port->EnqueueSession(&session->GetServerSession()); } - LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); + LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(std::move(client)); + rb.PushMoveObjects(session->GetClientSession()); } void SM::RegisterService(Kernel::HLERequestContext& ctx) { @@ -170,7 +171,9 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(handle.Code()); - rb.PushMoveObjects(std::move(handle).Unwrap()); + + auto server_port = handle.Unwrap(); + rb.PushMoveObjects(server_port); } void SM::UnregisterService(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 3f46ae44f..af5010c3b 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -10,9 +10,7 @@ #include <unordered_map> #include "common/concepts.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/k_port.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -21,10 +19,11 @@ class System; } namespace Kernel { -class ClientPort; -class ClientSession; +class KClientPort; +class KClientSession; class KernelCore; -class ServerPort; +class KPort; +class KServerPort; class SessionRequestHandler; } // namespace Kernel @@ -55,11 +54,9 @@ public: explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); - ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name, - u32 max_sessions); + ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions); ResultCode UnregisterService(const std::string& name); - ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); - ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); + ResultVal<Kernel::KPort*> GetServicePort(const std::string& name); template <Common::DerivedFrom<Kernel::SessionRequestHandler> T> std::shared_ptr<T> GetService(const std::string& service_name) const { @@ -68,11 +65,11 @@ public: LOG_DEBUG(Service, "Can't find service: {}", service_name); return nullptr; } - auto port = service->second->GetServerPort(); + auto* port = service->second; if (port == nullptr) { return nullptr; } - return std::static_pointer_cast<T>(port->GetHLEHandler()); + return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler()); } void InvokeControlRequest(Kernel::HLERequestContext& context); @@ -81,8 +78,8 @@ private: std::weak_ptr<SM> sm_interface; std::unique_ptr<Controller> controller_interface; - /// Map of registered services, retrieved using GetServicePort or ConnectToService. - std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services; + /// Map of registered services, retrieved using GetServicePort. + std::unordered_map<std::string, Kernel::KPort*> registered_services; /// Kernel context Kernel::KernelCore& kernel; diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index dc2baca4a..2c8899ae0 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -10,6 +10,11 @@ namespace Service::SSL { +enum class CertificateFormat : u32 { + Pem = 1, + Der = 2, +}; + class ISslConnection final : public ServiceFramework<ISslConnection> { public: explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { @@ -58,8 +63,8 @@ public: {1, nullptr, "GetOption"}, {2, &ISslContext::CreateConnection, "CreateConnection"}, {3, nullptr, "GetConnectionCount"}, - {4, nullptr, "ImportServerPki"}, - {5, nullptr, "ImportClientPki"}, + {4, &ISslContext::ImportServerPki, "ImportServerPki"}, + {5, &ISslContext::ImportClientPki, "ImportClientPki"}, {6, nullptr, "RemoveServerPki"}, {7, nullptr, "RemoveClientPki"}, {8, nullptr, "RegisterInternalPki"}, @@ -94,6 +99,39 @@ private: rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISslConnection>(system); } + + void ImportServerPki(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto certificate_format = rp.PopEnum<CertificateFormat>(); + const auto pkcs_12_certificates = ctx.ReadBuffer(0); + + constexpr u64 server_id = 0; + + LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(server_id); + } + + void ImportClientPki(Kernel::HLERequestContext& ctx) { + const auto pkcs_12_certificate = ctx.ReadBuffer(0); + const auto ascii_password = [&ctx] { + if (ctx.CanReadBuffer(1)) { + return ctx.ReadBuffer(1); + } + + return std::vector<u8>{}; + }(); + + constexpr u64 client_id = 0; + + LOG_WARNING(Service_SSL, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + rb.Push(client_id); + } }; class SSL final : public ServiceFramework<SSL> { diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp index 3172acc5a..7f47b12b8 100644 --- a/src/core/hle/service/time/standard_user_system_clock_core.cpp +++ b/src/core/hle/service/time/standard_user_system_clock_core.cpp @@ -4,7 +4,6 @@ #include "common/assert.h" #include "core/core.h" -#include "core/hle/kernel/k_event.h" #include "core/hle/service/time/standard_local_system_clock_core.h" #include "core/hle/service/time/standard_network_system_clock_core.h" #include "core/hle/service/time/standard_user_system_clock_core.h" @@ -17,10 +16,10 @@ StandardUserSystemClockCore::StandardUserSystemClockCore( : SystemClockCore(local_system_clock_core.GetSteadyClockCore()), local_system_clock_core{local_system_clock_core}, network_system_clock_core{network_system_clock_core}, auto_correction_enabled{}, - auto_correction_time{SteadyClockTimePoint::GetRandom()}, - auto_correction_event{Kernel::KEvent::Create( - system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} { - auto_correction_event->Initialize(); + auto_correction_time{SteadyClockTimePoint::GetRandom()}, auto_correction_event{ + system.Kernel()} { + Kernel::KAutoObject::Create(std::addressof(auto_correction_event)); + auto_correction_event.Initialize("StandardUserSystemClockCore:AutoCorrectionEvent"); } ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h index 5bc8bf5c2..1bff8a5af 100644 --- a/src/core/hle/service/time/standard_user_system_clock_core.h +++ b/src/core/hle/service/time/standard_user_system_clock_core.h @@ -4,6 +4,7 @@ #pragma once +#include "core/hle/kernel/k_event.h" #include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/system_clock_core.h" @@ -54,7 +55,7 @@ private: StandardNetworkSystemClockCore& network_system_clock_core; bool auto_correction_enabled{}; SteadyClockTimePoint auto_correction_time; - std::shared_ptr<Kernel::KEvent> auto_correction_event; + Kernel::KEvent auto_correction_event; }; } // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 32f372d71..e7991012b 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -8,8 +8,7 @@ #include "core/core_timing_util.h" #include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/time/interface.h" @@ -393,7 +392,7 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c LOG_DEBUG(Service_Time, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem())); + rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem()); } Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index 018ce94ed..eb57899f6 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -16,16 +16,11 @@ namespace Service::Time { static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000}; SharedMemory::SharedMemory(Core::System& system) : system(system) { - shared_memory_holder = SharedFrom(&system.Kernel().GetTimeSharedMem()); - std::memset(shared_memory_holder->GetPointer(), 0, SHARED_MEMORY_SIZE); + std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE); } SharedMemory::~SharedMemory() = default; -std::shared_ptr<Kernel::KSharedMemory> SharedMemory::GetSharedMemoryHolder() const { - return shared_memory_holder; -} - void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, Clock::TimeSpanType current_time_point) { const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( @@ -34,22 +29,22 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), clock_source_id}; shared_memory_format.standard_steady_clock_timepoint.StoreData( - shared_memory_holder->GetPointer(), context); + system.Kernel().GetTimeSharedMem().GetPointer(), context); } void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { shared_memory_format.standard_local_system_clock_context.StoreData( - shared_memory_holder->GetPointer(), context); + system.Kernel().GetTimeSharedMem().GetPointer(), context); } void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { shared_memory_format.standard_network_system_clock_context.StoreData( - shared_memory_holder->GetPointer(), context); + system.Kernel().GetTimeSharedMem().GetPointer(), context); } void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( - shared_memory_holder->GetPointer(), is_enabled); + system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled); } } // namespace Service::Time diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h index 3bc749114..1ad9a286d 100644 --- a/src/core/hle/service/time/time_sharedmemory.h +++ b/src/core/hle/service/time/time_sharedmemory.h @@ -17,9 +17,6 @@ public: explicit SharedMemory(Core::System& system); ~SharedMemory(); - // Return the shared memory handle - std::shared_ptr<Kernel::KSharedMemory> GetSharedMemoryHolder() const; - // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? template <typename T, std::size_t Offset> struct MemoryBarrier { @@ -63,7 +60,6 @@ public: void SetAutomaticCorrectionEnabled(bool is_enabled); private: - std::shared_ptr<Kernel::KSharedMemory> shared_memory_holder; Core::System& system; Format shared_memory_format{}; }; diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index ac9e87338..becbd36c1 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -17,10 +17,10 @@ namespace Service::VI { -Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} { - auto& kernel = system.Kernel(); - vsync_event = Kernel::KEvent::Create(kernel, fmt::format("Display VSync Event {}", id)); - vsync_event->Initialize(); +Display::Display(u64 id, std::string name, Core::System& system) + : id{id}, name{std::move(name)}, vsync_event{system.Kernel()} { + Kernel::KAutoObject::Create(std::addressof(vsync_event)); + vsync_event.Initialize(fmt::format("Display VSync Event {}", id)); } Display::~Display() = default; @@ -33,12 +33,12 @@ const Layer& Display::GetLayer(std::size_t index) const { return *layers.at(index); } -std::shared_ptr<Kernel::KReadableEvent> Display::GetVSyncEvent() const { - return vsync_event->GetReadableEvent(); +Kernel::KReadableEvent& Display::GetVSyncEvent() { + return vsync_event.GetReadableEvent(); } void Display::SignalVSyncEvent() { - vsync_event->GetWritableEvent()->Signal(); + vsync_event.GetWritableEvent().Signal(); } void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) { diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 8340059de..388ce6083 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "common/common_funcs.h" #include "common/common_types.h" namespace Kernel { @@ -24,6 +25,9 @@ class Layer; /// Represents a single display type class Display { + YUZU_NON_COPYABLE(Display); + YUZU_NON_MOVEABLE(Display); + public: /// Constructs a display with a given unique ID and name. /// @@ -33,12 +37,6 @@ public: Display(u64 id, std::string name, Core::System& system); ~Display(); - Display(const Display&) = delete; - Display& operator=(const Display&) = delete; - - Display(Display&&) = default; - Display& operator=(Display&&) = default; - /// Gets the unique ID assigned to this display. u64 GetID() const { return id; @@ -61,7 +59,7 @@ public: const Layer& GetLayer(std::size_t index) const; /// Gets the readable vsync event. - std::shared_ptr<Kernel::KReadableEvent> GetVSyncEvent() const; + Kernel::KReadableEvent& GetVSyncEvent(); /// Signals the internal vsync event. void SignalVSyncEvent(); @@ -102,7 +100,7 @@ private: std::string name; std::vector<std::shared_ptr<Layer>> layers; - std::shared_ptr<Kernel::KEvent> vsync_event; + Kernel::KEvent vsync_event; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 7ae07d072..32e47a43e 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -669,12 +669,10 @@ private: LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); - const auto& buffer_queue = *nv_flinger.FindBufferQueue(id); - // TODO(Subv): Find out what this actually is. IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent()); + rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent()); } NVFlinger::NVFlinger& nv_flinger; diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index fed47ecda..42f023258 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -13,8 +13,8 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/romfs_factory.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/nso.h" @@ -88,7 +88,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua } AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load( - Kernel::Process& process, Core::System& system) { + Kernel::KProcess& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 22a4ec5a6..a49a8b001 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -44,7 +44,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& out_dir) override; ResultStatus ReadIcon(std::vector<u8>& out_buffer) override; diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 627c18c7e..c062a4259 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -11,7 +11,7 @@ #include "common/logging/log.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/loader/elf.h" #include "core/memory.h" @@ -386,7 +386,7 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& elf_file) { return FileType::Error; } -AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process, +AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::KProcess& process, [[maybe_unused]] Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index 2b86c0b49..890299a20 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h @@ -32,7 +32,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; }; } // namespace Loader diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 9b447da2a..3ae9e6e0e 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -7,7 +7,7 @@ #include "core/file_sys/program_metadata.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/loader/kip.h" #include "core/memory.h" @@ -42,7 +42,7 @@ FileType AppLoader_KIP::GetFileType() const { : FileType::Error; } -AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process, +AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process, [[maybe_unused]] Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h index 2fe636f01..5f914b4a8 100644 --- a/src/core/loader/kip.h +++ b/src/core/loader/kip.h @@ -32,7 +32,7 @@ public: FileType GetFileType() const override; - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; private: std::unique_ptr<FileSys::KIP> kip; diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index e4f5fd40c..11b2d0837 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -11,7 +11,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/core.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/elf.h" #include "core/loader/kip.h" diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index bf6db1ab1..9eac11dec 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -25,7 +25,7 @@ class NACP; namespace Kernel { struct AddressMapping; -class Process; +class KProcess; } // namespace Kernel namespace Loader { @@ -165,7 +165,7 @@ public: * * @return The status result of the operation. */ - virtual LoadResult Load(Kernel::Process& process, Core::System& system) = 0; + virtual LoadResult Load(Kernel::KProcess& process, Core::System& system) = 0; /** * Get the code (typically .code section) of the application diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index f53c3a72c..aceb66414 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp @@ -6,7 +6,7 @@ #include "core/file_sys/content_archive.h" #include "core/file_sys/romfs.h" #include "core/file_sys/xts_archive.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/loader/nax.h" #include "core/loader/nca.h" @@ -41,7 +41,7 @@ FileType AppLoader_NAX::GetFileType() const { return IdentifyTypeImpl(*nax); } -AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process, Core::System& system) { +AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::KProcess& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index 68427c1cf..b3a50894f 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h @@ -37,7 +37,7 @@ public: FileType GetFileType() const override; - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 47e7a77a9..418cbf61b 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -9,7 +9,7 @@ #include "core/core.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/romfs_factory.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/nca.h" @@ -32,7 +32,7 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& nca_file) { return FileType::Error; } -AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::System& system) { +AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index c9792f390..f2ff080bb 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -39,7 +39,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 0597cfa60..ef54fa574 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -17,8 +17,8 @@ #include "core/file_sys/vfs_offset.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/nro.h" #include "core/loader/nso.h" @@ -130,7 +130,7 @@ static constexpr u32 PageAlignSize(u32 size) { return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); } -static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data) { +static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) { if (data.size() < sizeof(NroHeader)) { return {}; } @@ -199,11 +199,11 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data) { return true; } -bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& nro_file) { +bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) { return LoadNroImpl(process, nro_file.ReadAllBytes()); } -AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::System& system) { +AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 20bbaeb0e..fd453b402 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -19,7 +19,7 @@ class NACP; } namespace Kernel { -class Process; +class KProcess; } namespace Loader { @@ -43,7 +43,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadProgramId(u64& out_program_id) override; @@ -53,7 +53,7 @@ public: bool IsRomFSUpdatable() const override; private: - bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& nro_file); + bool LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file); std::vector<u8> icon_data; std::unique_ptr<FileSys::NACP> nacp; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index f671afe02..df59412cf 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -17,8 +17,8 @@ #include "core/file_sys/patch_manager.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/process.h" #include "core/loader/nso.h" #include "core/memory.h" @@ -71,7 +71,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) { return FileType::NSO; } -std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::System& system, +std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system, const FileSys::VfsFile& nso_file, VAddr load_base, bool should_pass_arguments, bool load_into_process, std::optional<FileSys::PatchManager> pm) { @@ -162,7 +162,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S return load_base + image_size; } -AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::System& system) { +AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 195149b55..f7b61bc2d 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -17,7 +17,7 @@ class System; } namespace Kernel { -class Process; +class KProcess; } namespace Loader { @@ -86,12 +86,12 @@ public: return IdentifyType(file); } - static std::optional<VAddr> LoadModule(Kernel::Process& process, Core::System& system, + static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system, const FileSys::VfsFile& nso_file, VAddr load_base, bool should_pass_arguments, bool load_into_process, std::optional<FileSys::PatchManager> pm = {}); - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadNSOModules(Modules& out_modules) override; diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index d7e590f1c..d815a7cd3 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -13,7 +13,7 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/submission_package.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/nca.h" @@ -79,7 +79,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) { return FileType::Error; } -AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process, Core::System& system) { +AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 1660f1b94..644c0ff58 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h @@ -45,7 +45,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 0125ddf33..635d6ae15 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -13,7 +13,7 @@ #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/file_sys/submission_package.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/nca.h" #include "core/loader/xci.h" @@ -56,7 +56,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& xci_file) { return FileType::Error; } -AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process, Core::System& system) { +AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::KProcess& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 7ea8179af..708155c30 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -45,7 +45,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process, Core::System& system) override; + LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b9dd3e275..b4c56e1c1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -17,8 +17,8 @@ #include "core/core.h" #include "core/device_memory.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/physical_memory.h" -#include "core/hle/kernel/process.h" #include "core/memory.h" #include "video_core/gpu.h" @@ -30,7 +30,7 @@ namespace Core::Memory { struct Memory::Impl { explicit Impl(Core::System& system_) : system{system_} {} - void SetCurrentPageTable(Kernel::Process& process, u32 core_id) { + void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { current_page_table = &process.PageTable().PageTableImpl(); const std::size_t address_space_width = process.PageTable().GetAddressSpaceWidth(); @@ -50,7 +50,7 @@ struct Memory::Impl { MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped); } - bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { + bool IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const { const auto& page_table = process.PageTable().PageTableImpl(); const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType(); return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory; @@ -82,6 +82,22 @@ struct Memory::Impl { return nullptr; } + u8* GetKernelBuffer(VAddr start_vaddr, size_t size) { + // TODO(bunnei): This is just a workaround until we have kernel memory layout mapped & + // managed. Until then, we use this to allocate and access kernel memory regions. + + auto search = kernel_memory_regions.find(start_vaddr); + if (search != kernel_memory_regions.end()) { + return search->second.get(); + } + + std::unique_ptr<u8[]> new_memory_region{new u8[size]}; + u8* raw_ptr = new_memory_region.get(); + kernel_memory_regions[start_vaddr] = std::move(new_memory_region); + + return raw_ptr; + } + u8 Read8(const VAddr addr) { return Read<u8>(addr); } @@ -178,7 +194,7 @@ struct Memory::Impl { return string; } - void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + void ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer, const std::size_t size) { const auto& page_table = process.PageTable().PageTableImpl(); @@ -223,7 +239,7 @@ struct Memory::Impl { } } - void ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + void ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer, const std::size_t size) { const auto& page_table = process.PageTable().PageTableImpl(); @@ -275,7 +291,7 @@ struct Memory::Impl { ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size); } - void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, + void WriteBlock(const Kernel::KProcess& process, const VAddr dest_addr, const void* src_buffer, const std::size_t size) { const auto& page_table = process.PageTable().PageTableImpl(); std::size_t remaining_size = size; @@ -318,7 +334,7 @@ struct Memory::Impl { } } - void WriteBlockUnsafe(const Kernel::Process& process, const VAddr dest_addr, + void WriteBlockUnsafe(const Kernel::KProcess& process, const VAddr dest_addr, const void* src_buffer, const std::size_t size) { const auto& page_table = process.PageTable().PageTableImpl(); std::size_t remaining_size = size; @@ -368,7 +384,7 @@ struct Memory::Impl { WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size); } - void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { + void ZeroBlock(const Kernel::KProcess& process, const VAddr dest_addr, const std::size_t size) { const auto& page_table = process.PageTable().PageTableImpl(); std::size_t remaining_size = size; std::size_t page_index = dest_addr >> PAGE_BITS; @@ -413,7 +429,7 @@ struct Memory::Impl { ZeroBlock(*system.CurrentProcess(), dest_addr, size); } - void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, + void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr, const std::size_t size) { const auto& page_table = process.PageTable().PageTableImpl(); std::size_t remaining_size = size; @@ -711,13 +727,21 @@ struct Memory::Impl { } Common::PageTable* current_page_table = nullptr; + std::unordered_map<VAddr, std::unique_ptr<u8[]>> kernel_memory_regions; Core::System& system; }; -Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {} +Memory::Memory(Core::System& system_) : system{system_} { + Reset(); +} + Memory::~Memory() = default; -void Memory::SetCurrentPageTable(Kernel::Process& process, u32 core_id) { +void Memory::Reset() { + impl = std::make_unique<Impl>(system); +} + +void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { impl->SetCurrentPageTable(process, core_id); } @@ -729,7 +753,7 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { impl->UnmapRegion(page_table, base, size); } -bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { +bool Memory::IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const { return impl->IsValidVirtualAddress(process, vaddr); } @@ -741,6 +765,10 @@ u8* Memory::GetPointer(VAddr vaddr) { return impl->GetPointer(vaddr); } +u8* Memory::GetKernelBuffer(VAddr start_vaddr, size_t size) { + return impl->GetKernelBuffer(start_vaddr, size); +} + const u8* Memory::GetPointer(VAddr vaddr) const { return impl->GetPointer(vaddr); } @@ -801,7 +829,7 @@ std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { return impl->ReadCString(vaddr, max_length); } -void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, +void Memory::ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer, const std::size_t size) { impl->ReadBlock(process, src_addr, dest_buffer, size); } @@ -810,7 +838,7 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_ impl->ReadBlock(src_addr, dest_buffer, size); } -void Memory::ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, +void Memory::ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer, const std::size_t size) { impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size); } @@ -819,7 +847,7 @@ void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std: impl->ReadBlockUnsafe(src_addr, dest_buffer, size); } -void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, +void Memory::WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer, std::size_t size) { impl->WriteBlock(process, dest_addr, src_buffer, size); } @@ -828,7 +856,7 @@ void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std impl->WriteBlock(dest_addr, src_buffer, size); } -void Memory::WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, +void Memory::WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer, std::size_t size) { impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size); } @@ -838,7 +866,7 @@ void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, impl->WriteBlockUnsafe(dest_addr, src_buffer, size); } -void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { +void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { impl->ZeroBlock(process, dest_addr, size); } @@ -846,7 +874,7 @@ void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) { impl->ZeroBlock(dest_addr, size); } -void Memory::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, +void Memory::CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr, const std::size_t size) { impl->CopyBlock(process, dest_addr, src_addr, size); } diff --git a/src/core/memory.h b/src/core/memory.h index 6d34fcfe2..345fd870d 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -19,7 +19,7 @@ class System; namespace Kernel { class PhysicalMemory; -class Process; +class KProcess; } // namespace Kernel namespace Core::Memory { @@ -59,11 +59,16 @@ public: Memory& operator=(Memory&&) = default; /** + * Resets the state of the Memory system. + */ + void Reset(); + + /** * Changes the currently active page table to that of the given process instance. * * @param process The process to use the page table of. */ - void SetCurrentPageTable(Kernel::Process& process, u32 core_id); + void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id); /** * Maps an allocated buffer onto a region of the emulated process address space. @@ -94,7 +99,7 @@ public: * * @returns True if the given virtual address is valid, false otherwise. */ - bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const; + bool IsValidVirtualAddress(const Kernel::KProcess& process, VAddr vaddr) const; /** * Checks whether or not the supplied address is a valid virtual @@ -116,6 +121,15 @@ public: */ u8* GetPointer(VAddr vaddr); + /** + * Gets a pointer to the start of a kernel heap allocated memory region. Will allocate one if it + * does not already exist. + * + * @param start_vaddr Start virtual address for the memory region. + * @param size Size of the memory region. + */ + u8* GetKernelBuffer(VAddr start_vaddr, size_t size); + template <typename T> T* GetPointer(VAddr vaddr) { return reinterpret_cast<T*>(GetPointer(vaddr)); @@ -319,7 +333,7 @@ public: * @post The range [dest_buffer, size) contains the read bytes from the * process' address space. */ - void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, + void ReadBlock(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer, std::size_t size); /** @@ -340,7 +354,7 @@ public: * @post The range [dest_buffer, size) contains the read bytes from the * process' address space. */ - void ReadBlockUnsafe(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, + void ReadBlockUnsafe(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer, std::size_t size); /** @@ -400,7 +414,7 @@ public: * and will mark that region as invalidated to caches that the active * graphics backend may be maintaining over the course of execution. */ - void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, + void WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer, std::size_t size); /** @@ -420,7 +434,7 @@ public: * will be ignored and an error will be logged. * */ - void WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, + void WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer, std::size_t size); /** @@ -472,7 +486,7 @@ public: * @post The range [dest_addr, size) within the process' address space is * filled with zeroes. */ - void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); + void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); /** * Fills the specified address range within the current process' address space with zeroes. @@ -497,7 +511,7 @@ public: * @post The range [dest_addr, size) within the process' address space contains the * same data within the range [src_addr, size). */ - void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, + void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr, std::size_t size); /** @@ -524,6 +538,8 @@ public: void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached); private: + Core::System& system; + struct Impl; std::unique_ptr<Impl> impl; }; diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 7643b7846..0f5ef7954 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -11,7 +11,7 @@ #include "core/core_timing_util.h" #include "core/hardware_properties.h" #include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 311d4dda8..896add892 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -19,7 +19,7 @@ #include "core/core.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/result.h" #include "core/memory.h" #include "core/reporter.h" diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 7c4e7dd3b..7399c3648 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -153,6 +153,11 @@ struct InputSubsystem::Impl { // TODO return the correct motion device return {}; } +#ifdef HAVE_SDL2 + if (params.Get("class", "") == "sdl") { + return sdl->GetMotionMappingForDevice(params); + } +#endif return {}; } diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h index 42bbf14d4..b5d41bba4 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h @@ -37,6 +37,9 @@ public: virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { return {}; } + virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) { + return {}; + } }; class NullState : public State { diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index f682a6db4..822d0b555 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -29,6 +29,7 @@ #endif #include "common/logging/log.h" +#include "common/math_util.h" #include "common/param_package.h" #include "common/settings_input.h" #include "common/threadsafe_queue.h" @@ -68,13 +69,57 @@ public: SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, SDL_GameController* game_controller) : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, - sdl_controller{game_controller, &SDL_GameControllerClose} {} + sdl_controller{game_controller, &SDL_GameControllerClose} { + EnableMotion(); + } + + void EnableMotion() { + if (sdl_controller) { + SDL_GameController* controller = sdl_controller.get(); + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); + has_accel = true; + } + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); + has_gyro = true; + } + } + } void SetButton(int button, bool value) { std::lock_guard lock{mutex}; state.buttons.insert_or_assign(button, value); } + void SetMotion(SDL_ControllerSensorEvent event) { + constexpr float gravity_constant = 9.80665f; + std::lock_guard lock{mutex}; + u64 time_difference = event.timestamp - last_motion_update; + last_motion_update = event.timestamp; + switch (event.sensor) { + case SDL_SENSOR_ACCEL: { + const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]}; + motion.SetAcceleration(acceleration / gravity_constant); + break; + } + case SDL_SENSOR_GYRO: { + const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]}; + motion.SetGyroscope(gyroscope / (Common::PI * 2)); + break; + } + } + + // Ignore duplicated timestamps + if (time_difference == 0) { + return; + } + + motion.SetGyroThreshold(0.0001f); + motion.UpdateRotation(time_difference * 1000); + motion.UpdateOrientation(time_difference * 1000); + } + bool GetButton(int button) const { std::lock_guard lock{mutex}; return state.buttons.at(button); @@ -121,6 +166,14 @@ public: return std::make_tuple(x, y); } + bool HasGyro() const { + return has_gyro; + } + + bool HasAccel() const { + return has_accel; + } + const MotionInput& GetMotion() const { return motion; } @@ -173,8 +226,11 @@ private: std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; mutable std::mutex mutex; - // Motion is initialized without PID values as motion input is not aviable for SDL2 - MotionInput motion{0.0f, 0.0f, 0.0f}; + // Motion is initialized with the PID values + MotionInput motion{0.3f, 0.005f, 0.0f}; + u64 last_motion_update{}; + bool has_gyro{false}; + bool has_accel{false}; }; std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { @@ -296,6 +352,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) { } break; } + case SDL_CONTROLLERSENSORUPDATE: { + if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { + joystick->SetMotion(event.csensor); + } + break; + } case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); @@ -449,6 +511,18 @@ private: std::shared_ptr<SDLJoystick> joystick; }; +class SDLMotion final : public Input::MotionDevice { +public: + explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {} + + Input::MotionStatus GetStatus() const override { + return joystick->GetMotion().GetMotion(); + } + +private: + std::shared_ptr<SDLJoystick> joystick; +}; + class SDLDirectionMotion final : public Input::MotionDevice { public: explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) @@ -658,6 +732,10 @@ public: auto joystick = state.GetSDLJoystickByGUID(guid, port); + if (params.Has("motion")) { + return std::make_unique<SDLMotion>(joystick); + } + if (params.Has("hat")) { const int hat = params.Get("hat", 0); const std::string direction_name = params.Get("direction", ""); @@ -717,6 +795,17 @@ SDLState::SDLState() { RegisterFactory<VibrationDevice>("sdl", vibration_factory); RegisterFactory<MotionDevice>("sdl", motion_factory); + // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + + // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a + // GameController and not a generic one + SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); + + // Turn off Pro controller home led + SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); + // If the frontend is going to manage the event loop, then we don't start one here start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { @@ -853,6 +942,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s return params; } +Common::ParamPackage BuildMotionParam(int port, std::string guid) { + Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + return params; +} + Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { switch (event.type) { case SDL_JOYAXISMOTION: { @@ -907,6 +1003,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve } break; } + case SDL_CONTROLLERSENSORUPDATE: { + bool is_motion_shaking = false; + constexpr float gyro_threshold = 5.0f; + constexpr float accel_threshold = 11.0f; + if (event.csensor.sensor == SDL_SENSOR_ACCEL) { + const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2], + -event.csensor.data[1]}; + if (acceleration.Length() > accel_threshold) { + is_motion_shaking = true; + } + } + + if (event.csensor.sensor == SDL_SENSOR_GYRO) { + const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2], + event.csensor.data[1]}; + if (gyroscope.Length() > gyro_threshold) { + is_motion_shaking = true; + } + } + + if (!is_motion_shaking) { + break; + } + + if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) { + return BuildMotionParam(joystick->GetPort(), joystick->GetGUID()); + } + break; + } } return {}; } @@ -1036,6 +1161,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa return mapping; } +MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + joystick->EnableMotion(); + + if (!joystick->HasGyro() && !joystick->HasAccel()) { + return {}; + } + + MotionMapping mapping = {}; + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + return mapping; +} namespace Polling { class SDLPoller : public InputCommon::Polling::DevicePoller { public: @@ -1149,6 +1295,7 @@ public: [[fallthrough]]; case SDL_JOYBUTTONUP: case SDL_JOYHATMOTION: + case SDL_CONTROLLERSENSORUPDATE: return {SDLEventToMotionParamPackage(state, event)}; } return std::nullopt; diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h index 8b7363f56..121e01913 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/sdl/sdl_impl.h @@ -57,6 +57,7 @@ public: ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; + MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; private: void InitJoystick(int joystick_index); diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 4eb71efbd..eb58ac6b6 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -7,7 +7,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/memory.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0863904e9..a5dbb9adf 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -19,7 +19,7 @@ #include "common/scope_exit.h" #include "common/settings.h" #include "core/core.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/memory.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 97fb11ac6..dbcb751cb 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp @@ -15,7 +15,7 @@ #include "common/settings.h" #include "common/zstd_compression.h" #include "core/core.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "video_core/engines/shader_type.h" #include "video_core/renderer_opengl/gl_shader_cache.h" #include "video_core/renderer_opengl/gl_shader_disk_cache.h" diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 7ff9491f4..86495803e 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -32,7 +32,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/frontend/framebuffer_layout.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "input_common/keyboard.h" #include "input_common/main.h" #include "input_common/mouse/mouse_input.h" diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index c9318c562..ab3512810 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -153,6 +153,10 @@ QString ButtonToText(const Common::ParamPackage& param) { return QObject::tr("Button %1").arg(button_str); } + if (param.Has("motion")) { + return QObject::tr("SDL Motion"); + } + return {}; } @@ -1245,12 +1249,16 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { const auto& device = input_devices[ui->comboDevices->currentIndex()]; auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); + auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device); for (std::size_t i = 0; i < buttons_param.size(); ++i) { buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; } for (std::size_t i = 0; i < analogs_param.size(); ++i) { analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)]; } + for (std::size_t i = 0; i < motions_param.size(); ++i) { + motions_param[i] = motion_mapping[static_cast<Settings::NativeMotion::Values>(i)]; + } UpdateUI(); } diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index f35c89e04..0cdaea8a4 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -46,6 +46,7 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur SetConfiguration(); // Force game list reload if any of the relevant settings are changed. + connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ConfigureUi::RequestGameListUpdate); connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 3bca6277b..bdfda6c54 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -12,12 +12,13 @@ #include "common/assert.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_class_token.h" +#include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_types.h" #include "core/memory.h" @@ -91,7 +92,7 @@ std::size_t WaitTreeItem::Row() const { std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { std::vector<std::unique_ptr<WaitTreeThread>> item_list; std::size_t row = 0; - auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) { + auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { for (std::size_t i = 0; i < threads.size(); ++i) { if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i])); @@ -114,11 +115,11 @@ QString WaitTreeText::GetText() const { return text; } -WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table) +WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table) : mutex_address(mutex_address) { mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address); owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); - owner = handle_table.Get<Kernel::KThread>(owner_handle); + owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe(); } WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; @@ -183,18 +184,20 @@ bool WaitTreeExpandableItem::IsExpandable() const { } QString WaitTreeSynchronizationObject::GetText() const { - return tr("[%1]%2 %3") - .arg(object.GetObjectId()) - .arg(QString::fromStdString(object.GetTypeName()), + return tr("[%1] %2 %3") + .arg(object.GetId()) + .arg(QString::fromStdString(object.GetTypeObj().GetName()), QString::fromStdString(object.GetName())); } std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make( const Kernel::KSynchronizationObject& object) { - switch (object.GetHandleType()) { - case Kernel::HandleType::ReadableEvent: + const auto type = + static_cast<Kernel::KClassTokenGenerator::ObjectType>(object.GetTypeObj().GetClassToken()); + switch (type) { + case Kernel::KClassTokenGenerator::ObjectType::KReadableEvent: return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object)); - case Kernel::HandleType::Thread: + case Kernel::KClassTokenGenerator::ObjectType::KThread: return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object)); default: return std::make_unique<WaitTreeSynchronizationObject>(object); @@ -204,12 +207,13 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const { std::vector<std::unique_ptr<WaitTreeItem>> list; - const auto& threads = object.GetWaitingThreadsForDebugging(); + auto threads = object.GetWaitingThreadsForDebugging(); if (threads.empty()) { list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread"))); } else { - list.push_back(std::make_unique<WaitTreeThreadList>(threads)); + list.push_back(std::make_unique<WaitTreeThreadList>(std::move(threads))); } + return list; } @@ -377,8 +381,8 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object) : WaitTreeSynchronizationObject(object) {} WaitTreeEvent::~WaitTreeEvent() = default; -WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::KThread*>& list) - : thread_list(list) {} +WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list) + : thread_list(std::move(list)) {} WaitTreeThreadList::~WaitTreeThreadList() = default; QString WaitTreeThreadList::GetText() const { diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index 3da2fdfd2..d450345df 100644 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h @@ -11,13 +11,15 @@ #include <QAbstractItemModel> #include <QDockWidget> #include <QTreeView> + #include "common/common_types.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/svc_common.h" class EmuThread; namespace Kernel { -class HandleTable; +class KHandleTable; class KReadableEvent; class KSynchronizationObject; class KThread; @@ -73,17 +75,17 @@ public: class WaitTreeMutexInfo : public WaitTreeExpandableItem { Q_OBJECT public: - explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table); + explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table); ~WaitTreeMutexInfo() override; QString GetText() const override; std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; private: - VAddr mutex_address; - u32 mutex_value; - Kernel::Handle owner_handle; - std::shared_ptr<Kernel::KThread> owner; + VAddr mutex_address{}; + u32 mutex_value{}; + Kernel::Handle owner_handle{}; + Kernel::KThread* owner{}; }; class WaitTreeCallstack : public WaitTreeExpandableItem { @@ -149,14 +151,14 @@ public: class WaitTreeThreadList : public WaitTreeExpandableItem { Q_OBJECT public: - explicit WaitTreeThreadList(const std::vector<Kernel::KThread*>& list); + explicit WaitTreeThreadList(std::vector<Kernel::KThread*>&& list); ~WaitTreeThreadList() override; QString GetText() const override; std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; private: - const std::vector<Kernel::KThread*>& thread_list; + std::vector<Kernel::KThread*> thread_list; }; class WaitTreeModel : public QAbstractItemModel { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 00d4cfe67..9e72acbf7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -92,7 +92,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/file_sys/romfs.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/submission_package.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/am/am.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/nfp/nfp.h" diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 4871ac3bb..e2812ca61 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -27,7 +27,7 @@ #include "core/crypto/key_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/vfs_real.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "core/telemetry_session.h" |