diff options
Diffstat (limited to 'src/core/hle')
59 files changed, 978 insertions, 406 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index db189c8e3..8475b698c 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -8,7 +8,6 @@ #include "common/assert.h" #include "common/common_types.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/scheduler.h" @@ -202,42 +201,39 @@ void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) { void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) { const VAddr arb_addr = thread->GetArbiterWaitAddress(); std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; - auto it = thread_list.begin(); - while (it != thread_list.end()) { - const std::shared_ptr<Thread>& current_thread = *it; - if (current_thread->GetPriority() >= thread->GetPriority()) { - thread_list.insert(it, thread); - return; - } - ++it; + + const auto iter = + std::find_if(thread_list.cbegin(), thread_list.cend(), [&thread](const auto& entry) { + return entry->GetPriority() >= thread->GetPriority(); + }); + + if (iter == thread_list.cend()) { + thread_list.push_back(std::move(thread)); + } else { + thread_list.insert(iter, std::move(thread)); } - thread_list.push_back(std::move(thread)); } void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) { const VAddr arb_addr = thread->GetArbiterWaitAddress(); std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; - auto it = thread_list.begin(); - while (it != thread_list.end()) { - const std::shared_ptr<Thread>& current_thread = *it; - if (current_thread.get() == thread.get()) { - thread_list.erase(it); - return; - } - ++it; - } - UNREACHABLE(); + + const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(), + [&thread](const auto& entry) { return thread == entry; }); + + ASSERT(iter != thread_list.cend()); + + thread_list.erase(iter); } -std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) { - std::vector<std::shared_ptr<Thread>> result; - std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[address]; - auto it = thread_list.begin(); - while (it != thread_list.end()) { - std::shared_ptr<Thread> current_thread = *it; - result.push_back(std::move(current_thread)); - ++it; +std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress( + VAddr address) const { + const auto iter = arb_threads.find(address); + if (iter == arb_threads.cend()) { + return {}; } - return result; + + const std::list<std::shared_ptr<Thread>>& thread_list = iter->second; + return {thread_list.cbegin(), thread_list.cend()}; } } // namespace Kernel diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 386983e54..f958eee5a 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -86,7 +86,7 @@ private: void RemoveThread(std::shared_ptr<Thread> thread); // Gets the threads waiting on an address. - std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address); + std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; /// List of threads waiting for a address arbiter std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> arb_threads; diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 4669a14ad..6d66276bc 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -12,7 +12,7 @@ namespace Kernel { -ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} +ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {} ClientSession::~ClientSession() { // This destructor will be called automatically when the last ClientSession handle is closed by @@ -31,6 +31,11 @@ void ClientSession::Acquire(Thread* thread) { UNIMPLEMENTED(); } +bool ClientSession::IsSignaled() const { + UNIMPLEMENTED(); + return true; +} + ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, std::shared_ptr<Session> parent, std::string name) { diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index b4289a9a8..d15b09554 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -7,7 +7,7 @@ #include <memory> #include <string> -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" union ResultCode; @@ -22,7 +22,7 @@ class KernelCore; class Session; class Thread; -class ClientSession final : public WaitObject { +class ClientSession final : public SynchronizationObject { public: explicit ClientSession(KernelCore& kernel); ~ClientSession() override; @@ -48,6 +48,8 @@ public: void Acquire(Thread* thread) override; + bool IsSignaled() const override; + private: static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, std::shared_ptr<Session> parent, diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 2db28dcf0..c558a2f33 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -47,15 +47,15 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, std::shared_ptr<WritableEvent> writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason, - std::shared_ptr<Thread> thread, - std::shared_ptr<WaitObject> object, - std::size_t index) mutable -> bool { - ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); - callback(thread, context, reason); - context.WriteToOutgoingCommandBuffer(*thread); - return true; - }); + thread->SetWakeupCallback( + [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<SynchronizationObject> object, + std::size_t index) mutable -> bool { + ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); + callback(thread, context, reason); + context.WriteToOutgoingCommandBuffer(*thread); + return true; + }); auto& kernel = Core::System::GetInstance().Kernel(); if (!writable_event) { @@ -67,7 +67,7 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread( const auto readable_event{writable_event->GetReadableEvent()}; writable_event->Clear(); thread->SetStatus(ThreadStatus::WaitHLEEvent); - thread->SetWaitObjects({readable_event}); + thread->SetSynchronizationObjects({readable_event}); readable_event->AddWaitingThread(thread); if (timeout > 0) { @@ -284,13 +284,18 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { std::vector<u8> buffer; - const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; + const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && + BufferDescriptorA()[buffer_index].Size()}; auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_a) { + ASSERT_MSG(BufferDescriptorA().size() > buffer_index, + "BufferDescriptorA invalid buffer_index {}", buffer_index); buffer.resize(BufferDescriptorA()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); } else { + ASSERT_MSG(BufferDescriptorX().size() > buffer_index, + "BufferDescriptorX invalid buffer_index {}", buffer_index); buffer.resize(BufferDescriptorX()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); } @@ -305,7 +310,8 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, return 0; } - const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; + const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && + BufferDescriptorB()[buffer_index].Size()}; const std::size_t buffer_size{GetWriteBufferSize(buffer_index)}; if (size > buffer_size) { LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, @@ -315,8 +321,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_b) { + ASSERT_MSG(BufferDescriptorB().size() > buffer_index, + "BufferDescriptorB invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorB()[buffer_index].Size() >= size, + "BufferDescriptorB buffer_index {} is not large enough", buffer_index); memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); } else { + ASSERT_MSG(BufferDescriptorC().size() > buffer_index, + "BufferDescriptorC invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorC()[buffer_index].Size() >= size, + "BufferDescriptorC buffer_index {} is not large enough", buffer_index); memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); } @@ -324,15 +338,35 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, } std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const { - const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; - return is_buffer_a ? BufferDescriptorA()[buffer_index].Size() - : BufferDescriptorX()[buffer_index].Size(); + const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && + BufferDescriptorA()[buffer_index].Size()}; + if (is_buffer_a) { + ASSERT_MSG(BufferDescriptorA().size() > buffer_index, + "BufferDescriptorA invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorA()[buffer_index].Size() > 0, + "BufferDescriptorA buffer_index {} is empty", buffer_index); + return BufferDescriptorA()[buffer_index].Size(); + } else { + ASSERT_MSG(BufferDescriptorX().size() > buffer_index, + "BufferDescriptorX invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorX()[buffer_index].Size() > 0, + "BufferDescriptorX buffer_index {} is empty", buffer_index); + return BufferDescriptorX()[buffer_index].Size(); + } } std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const { - const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; - return is_buffer_b ? BufferDescriptorB()[buffer_index].Size() - : BufferDescriptorC()[buffer_index].Size(); + const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && + BufferDescriptorB()[buffer_index].Size()}; + if (is_buffer_b) { + ASSERT_MSG(BufferDescriptorB().size() > buffer_index, + "BufferDescriptorB invalid buffer_index {}", buffer_index); + return BufferDescriptorB()[buffer_index].Size(); + } else { + ASSERT_MSG(BufferDescriptorC().size() > buffer_index, + "BufferDescriptorC invalid buffer_index {}", buffer_index); + return BufferDescriptorC()[buffer_index].Size(); + } } std::string HLERequestContext::Description() const { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1d0783bd3..4eb1d8703 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -3,13 +3,15 @@ // Refer to the license.txt file included. #include <atomic> +#include <functional> #include <memory> #include <mutex> #include <utility> #include "common/assert.h" #include "common/logging/log.h" - +#include "core/arm/arm_interface.h" +#include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -17,9 +19,11 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" #include "core/hle/lock.h" #include "core/hle/result.h" @@ -51,10 +55,10 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ if (thread->GetStatus() == ThreadStatus::WaitSynch || thread->GetStatus() == ThreadStatus::WaitHLEEvent) { // Remove the thread from each of its waiting objects' waitlists - for (const auto& object : thread->GetWaitObjects()) { + for (const auto& object : thread->GetSynchronizationObjects()) { object->RemoveWaitingThread(thread); } - thread->ClearWaitObjects(); + thread->ClearSynchronizationObjects(); // Invoke the wakeup callback before clearing the wait objects if (thread->HasWakeupCallback()) { @@ -93,11 +97,13 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ } struct KernelCore::Impl { - explicit Impl(Core::System& system) : system{system}, global_scheduler{system} {} + explicit Impl(Core::System& system) + : system{system}, global_scheduler{system}, synchronization{system} {} void Initialize(KernelCore& kernel) { Shutdown(); + InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); InitializeThreads(); InitializePreemption(); @@ -121,6 +127,21 @@ struct KernelCore::Impl { global_scheduler.Shutdown(); named_ports.clear(); + + for (auto& core : cores) { + core.Shutdown(); + } + cores.clear(); + + exclusive_monitor.reset(); + } + + void InitializePhysicalCores() { + exclusive_monitor = + Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount()); + for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) { + cores.emplace_back(system, i, *exclusive_monitor); + } } // Creates the default system resource limit @@ -172,6 +193,7 @@ struct KernelCore::Impl { std::vector<std::shared_ptr<Process>> process_list; Process* current_process = nullptr; Kernel::GlobalScheduler global_scheduler; + Kernel::Synchronization synchronization; std::shared_ptr<ResourceLimit> system_resource_limit; @@ -186,6 +208,9 @@ struct KernelCore::Impl { /// the ConnectToPort SVC. NamedPortTable named_ports; + std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; + std::vector<Kernel::PhysicalCore> cores; + // System context Core::System& system; }; @@ -240,6 +265,42 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { return impl->global_scheduler; } +Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { + return impl->cores[id]; +} + +const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { + return impl->cores[id]; +} + +Kernel::Synchronization& KernelCore::Synchronization() { + return impl->synchronization; +} + +const Kernel::Synchronization& KernelCore::Synchronization() const { + return impl->synchronization; +} + +Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { + return *impl->exclusive_monitor; +} + +const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { + return *impl->exclusive_monitor; +} + +void KernelCore::InvalidateAllInstructionCaches() { + for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) { + PhysicalCore(i).ArmInterface().ClearInstructionCache(); + } +} + +void KernelCore::PrepareReschedule(std::size_t id) { + if (id < impl->global_scheduler.CpuCoresCount()) { + impl->cores[id].Stop(); + } +} + void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { impl->named_ports.emplace(std::move(name), std::move(port)); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3bf0068ed..1eede3063 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,8 +11,9 @@ #include "core/hle/kernel/object.h" namespace Core { +class ExclusiveMonitor; class System; -} +} // namespace Core namespace Core::Timing { class CoreTiming; @@ -25,8 +26,10 @@ class AddressArbiter; class ClientPort; class GlobalScheduler; class HandleTable; +class PhysicalCore; class Process; class ResourceLimit; +class Synchronization; class Thread; /// Represents a single instance of the kernel. @@ -84,6 +87,27 @@ public: /// Gets the sole instance of the global scheduler const Kernel::GlobalScheduler& GlobalScheduler() const; + /// Gets the an instance of the respective physical CPU core. + Kernel::PhysicalCore& PhysicalCore(std::size_t id); + + /// Gets the an instance of the respective physical CPU core. + const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; + + /// Gets the an instance of the Synchronization Interface. + Kernel::Synchronization& Synchronization(); + + /// Gets the an instance of the Synchronization Interface. + const Kernel::Synchronization& Synchronization() const; + + /// Stops execution of 'id' core, in order to reschedule a new thread. + void PrepareReschedule(std::size_t id); + + Core::ExclusiveMonitor& GetExclusiveMonitor(); + + const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + + void InvalidateAllInstructionCaches(); + /// Adds a port to the named port table void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp new file mode 100644 index 000000000..9303dd273 --- /dev/null +++ b/src/core/hle/kernel/physical_core.cpp @@ -0,0 +1,51 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/arm/arm_interface.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic.h" +#endif +#include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" +#include "core/core.h" +#include "core/hle/kernel/physical_core.h" +#include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, + Core::ExclusiveMonitor& exclusive_monitor) + : core_index{id} { +#ifdef ARCHITECTURE_x86_64 + arm_interface = std::make_unique<Core::ARM_Dynarmic>(system, exclusive_monitor, core_index); +#else + arm_interface = std::make_shared<Core::ARM_Unicorn>(system); + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif + + scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index); +} + +PhysicalCore::~PhysicalCore() = default; + +void PhysicalCore::Run() { + arm_interface->Run(); + arm_interface->ClearExclusiveState(); +} + +void PhysicalCore::Step() { + arm_interface->Step(); +} + +void PhysicalCore::Stop() { + arm_interface->PrepareReschedule(); +} + +void PhysicalCore::Shutdown() { + scheduler->Shutdown(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h new file mode 100644 index 000000000..4c32c0f1b --- /dev/null +++ b/src/core/hle/kernel/physical_core.h @@ -0,0 +1,77 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> +#include <memory> + +namespace Kernel { +class Scheduler; +} // namespace Kernel + +namespace Core { +class ARM_Interface; +class ExclusiveMonitor; +class System; +} // namespace Core + +namespace Kernel { + +class PhysicalCore { +public: + PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor); + ~PhysicalCore(); + + PhysicalCore(const PhysicalCore&) = delete; + PhysicalCore& operator=(const PhysicalCore&) = delete; + + PhysicalCore(PhysicalCore&&) = default; + PhysicalCore& operator=(PhysicalCore&&) = default; + + /// Execute current jit state + void Run(); + /// Execute a single instruction in current jit. + void Step(); + /// Stop JIT execution/exit + void Stop(); + + // Shutdown this physical core. + void Shutdown(); + + Core::ARM_Interface& ArmInterface() { + return *arm_interface; + } + + const Core::ARM_Interface& ArmInterface() const { + return *arm_interface; + } + + bool IsMainCore() const { + return core_index == 0; + } + + bool IsSystemCore() const { + return core_index == 3; + } + + std::size_t CoreIndex() const { + return core_index; + } + + Kernel::Scheduler& Scheduler() { + return *scheduler; + } + + const Kernel::Scheduler& Scheduler() const { + return *scheduler; + } + +private: + std::size_t core_index; + std::unique_ptr<Core::ARM_Interface> arm_interface; + std::unique_ptr<Kernel::Scheduler> scheduler; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index b9035a0be..2fcb7326c 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -337,7 +337,7 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { } Process::Process(Core::System& system) - : WaitObject{system.Kernel()}, vm_manager{system}, + : SynchronizationObject{system.Kernel()}, vm_manager{system}, address_arbiter{system}, mutex{system}, system{system} {} Process::~Process() = default; @@ -357,7 +357,7 @@ void Process::ChangeStatus(ProcessStatus new_status) { status = new_status; is_signaled = true; - WakeupAllWaitingThreads(); + Signal(); } void Process::AllocateMainThreadStack(u64 stack_size) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 3483fa19d..4887132a7 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -15,8 +15,8 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process_capability.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/kernel/vm_manager.h" -#include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" namespace Core { @@ -60,7 +60,7 @@ enum class ProcessStatus { DebugBreak, }; -class Process final : public WaitObject { +class Process final : public SynchronizationObject { public: explicit Process(Core::System& system); ~Process() override; @@ -359,10 +359,6 @@ private: /// specified by metadata provided to the process during loading. bool is_64bit_process = true; - /// Whether or not this process is signaled. This occurs - /// upon the process changing to a different state. - bool is_signaled = false; - /// Total running time for the process in ticks. u64 total_process_running_time_ticks = 0; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index d8ac97aa1..9d3d3a81b 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -11,30 +11,30 @@ namespace Kernel { -ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {} +ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {} ReadableEvent::~ReadableEvent() = default; bool ReadableEvent::ShouldWait(const Thread* thread) const { - return !signaled; + return !is_signaled; } void ReadableEvent::Acquire(Thread* thread) { - ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); + ASSERT_MSG(IsSignaled(), "object unavailable!"); } void ReadableEvent::Signal() { - if (!signaled) { - signaled = true; - WakeupAllWaitingThreads(); + if (!is_signaled) { + is_signaled = true; + SynchronizationObject::Signal(); }; } void ReadableEvent::Clear() { - signaled = false; + is_signaled = false; } ResultCode ReadableEvent::Reset() { - if (!signaled) { + if (!is_signaled) { return ERR_INVALID_STATE; } diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index 11ff71c3a..3264dd066 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h @@ -5,7 +5,7 @@ #pragma once #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" union ResultCode; @@ -14,7 +14,7 @@ namespace Kernel { class KernelCore; class WritableEvent; -class ReadableEvent final : public WaitObject { +class ReadableEvent final : public SynchronizationObject { friend class WritableEvent; public: @@ -46,13 +46,11 @@ public: /// then ERR_INVALID_STATE will be returned. ResultCode Reset(); + void Signal() override; + private: explicit ReadableEvent(KernelCore& kernel); - void Signal(); - - bool signaled{}; - std::string name; ///< Name of event (optional) }; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d36fcd7d9..86f1421bf 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -14,7 +14,6 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/core_timing.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -125,8 +124,8 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { "Thread yielding without being in front"); scheduled_queue[core_id].yield(priority); - std::array<Thread*, NUM_CPU_CORES> current_threads; - for (u32 i = 0; i < NUM_CPU_CORES; i++) { + std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads; + for (std::size_t i = 0; i < current_threads.size(); i++) { current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); } @@ -178,8 +177,8 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread // function... if (scheduled_queue[core_id].empty()) { // Here, "current_threads" is calculated after the ""yield"", unlike yield -1 - std::array<Thread*, NUM_CPU_CORES> current_threads; - for (u32 i = 0; i < NUM_CPU_CORES; i++) { + std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads; + for (std::size_t i = 0; i < current_threads.size(); i++) { current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); } for (auto& thread : suggested_queue[core_id]) { @@ -209,7 +208,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } void GlobalScheduler::PreemptThreads() { - for (std::size_t core_id = 0; core_id < NUM_CPU_CORES; core_id++) { + for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { const u32 priority = preemption_priorities[core_id]; if (scheduled_queue[core_id].size(priority) > 0) { @@ -350,7 +349,7 @@ bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, } void GlobalScheduler::Shutdown() { - for (std::size_t core = 0; core < NUM_CPU_CORES; core++) { + for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { scheduled_queue[core].clear(); suggested_queue[core].clear(); } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 14b77960a..96db049cb 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "common/multi_level_queue.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/thread.h" namespace Core { @@ -23,8 +24,6 @@ class Process; class GlobalScheduler final { public: - static constexpr u32 NUM_CPU_CORES = 4; - explicit GlobalScheduler(Core::System& system); ~GlobalScheduler(); @@ -125,7 +124,7 @@ public: void PreemptThreads(); u32 CpuCoresCount() const { - return NUM_CPU_CORES; + return Core::Hardware::NUM_CPU_CORES; } void SetReselectionPending() { @@ -149,13 +148,15 @@ private: bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner); static constexpr u32 min_regular_priority = 2; - std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> scheduled_queue; - std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> suggested_queue; + std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES> + scheduled_queue; + std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES> + suggested_queue; std::atomic<bool> is_reselection_pending{false}; // The priority levels at which the global scheduler preempts threads every 10 ms. They are // ordered from Core 0 to Core 3. - std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; + std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; /// Lists all thread ids that aren't deleted/etc. std::vector<std::shared_ptr<Thread>> thread_list; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index a4ccfa35e..a549ae9d7 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {} +ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {} ServerPort::~ServerPort() = default; ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { @@ -39,6 +39,10 @@ void ServerPort::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } +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); diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 8be8a75ea..41b191b86 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -10,7 +10,7 @@ #include <vector> #include "common/common_types.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" namespace Kernel { @@ -20,7 +20,7 @@ class KernelCore; class ServerSession; class SessionRequestHandler; -class ServerPort final : public WaitObject { +class ServerPort final : public SynchronizationObject { public: explicit ServerPort(KernelCore& kernel); ~ServerPort() override; @@ -82,6 +82,8 @@ public: bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; + bool IsSignaled() const override; + private: /// ServerSessions waiting to be accepted by the port std::vector<std::shared_ptr<ServerSession>> pending_sessions; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 7825e1ec4..4604e35c5 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -24,7 +24,7 @@ namespace Kernel { -ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} +ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} ServerSession::~ServerSession() = default; ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, @@ -50,6 +50,16 @@ bool ServerSession::ShouldWait(const Thread* thread) const { return pending_requesting_threads.empty() || currently_handling != nullptr; } +bool ServerSession::IsSignaled() const { + // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. + if (!parent->Client()) { + return true; + } + + // Wait if we have no pending requests, or if we're currently handling a request. + return !pending_requesting_threads.empty() && currently_handling == nullptr; +} + void ServerSession::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); // We are now handling a request, pop it from the stack. diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index d6e48109e..77e4f6721 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -10,7 +10,7 @@ #include <vector> #include "common/threadsafe_queue.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" namespace Memory { @@ -41,7 +41,7 @@ class Thread; * 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 WaitObject { +class ServerSession final : public SynchronizationObject { public: explicit ServerSession(KernelCore& kernel); ~ServerSession() override; @@ -73,6 +73,8 @@ public: return parent.get(); } + bool IsSignaled() const override; + /** * Sets the HLE handler for the session. This handler will be called to service IPC requests * instead of the regular IPC machinery. (The regular IPC machinery is currently not diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index dee6e2b72..e4dd53e24 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp @@ -9,7 +9,7 @@ namespace Kernel { -Session::Session(KernelCore& kernel) : WaitObject{kernel} {} +Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {} Session::~Session() = default; Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { @@ -29,6 +29,11 @@ bool Session::ShouldWait(const Thread* thread) const { return {}; } +bool Session::IsSignaled() const { + UNIMPLEMENTED(); + return true; +} + void Session::Acquire(Thread* thread) { UNIMPLEMENTED(); } diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 15a5ac15f..7cd9c0d77 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -8,7 +8,7 @@ #include <string> #include <utility> -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" namespace Kernel { @@ -19,7 +19,7 @@ class ServerSession; * Parent structure to link the client and server endpoints of a session with their associated * client port. */ -class Session final : public WaitObject { +class Session final : public SynchronizationObject { public: explicit Session(KernelCore& kernel); ~Session() override; @@ -39,6 +39,8 @@ public: bool ShouldWait(const Thread* thread) const override; + bool IsSignaled() const override; + void Acquire(Thread* thread) override; std::shared_ptr<ClientSession> Client() { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dbcdb0b88..fd91779a3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -15,7 +15,7 @@ #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" -#include "core/core_cpu.h" +#include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/hle/kernel/address_arbiter.h" @@ -32,6 +32,7 @@ #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_wrap.h" +#include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/kernel/writable_event.h" @@ -433,22 +434,6 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han return ERR_INVALID_HANDLE; } -/// Default thread wakeup callback for WaitSynchronization -static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, - std::shared_ptr<WaitObject> object, std::size_t index) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); - - if (reason == ThreadWakeupReason::Timeout) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return true; - } - - ASSERT(reason == ThreadWakeupReason::Signal); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - thread->SetWaitSynchronizationOutput(static_cast<u32>(index)); - return true; -}; - /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, u64 handle_count, s64 nano_seconds) { @@ -472,14 +457,14 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr } auto* const thread = system.CurrentScheduler().GetCurrentThread(); - - using ObjectPtr = Thread::ThreadWaitObjects::value_type; - Thread::ThreadWaitObjects objects(handle_count); - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + auto& kernel = system.Kernel(); + using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type; + Thread::ThreadSynchronizationObjects objects(handle_count); + const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); for (u64 i = 0; i < handle_count; ++i) { const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); - const auto object = handle_table.Get<WaitObject>(handle); + const auto object = handle_table.Get<SynchronizationObject>(handle); if (object == nullptr) { LOG_ERROR(Kernel_SVC, "Object is a nullptr"); @@ -488,47 +473,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr objects[i] = object; } - - // Find the first object that is acquirable in the provided list of objects - auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { - return !object->ShouldWait(thread); - }); - - if (itr != objects.end()) { - // We found a ready object, acquire it and set the result value - WaitObject* object = itr->get(); - object->Acquire(thread); - *index = static_cast<s32>(std::distance(objects.begin(), itr)); - return RESULT_SUCCESS; - } - - // No objects were ready to be acquired, prepare to suspend the thread. - - // If a timeout value of 0 was provided, just return the Timeout error code instead of - // suspending the thread. - if (nano_seconds == 0) { - return RESULT_TIMEOUT; - } - - if (thread->IsSyncCancelled()) { - thread->SetSyncCancelled(false); - return ERR_SYNCHRONIZATION_CANCELED; - } - - for (auto& object : objects) { - object->AddWaitingThread(SharedFrom(thread)); - } - - thread->SetWaitObjects(std::move(objects)); - thread->SetStatus(ThreadStatus::WaitSynch); - - // Create an event to wake the thread up after the specified nanosecond delay has passed - thread->WakeAfterDelay(nano_seconds); - thread->SetWakeupCallback(DefaultThreadWakeupCallback); - - system.PrepareReschedule(thread->GetProcessorID()); - - return RESULT_TIMEOUT; + auto& synchronization = kernel.Synchronization(); + const auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds); + *index = handle_result; + return result; } /// Resumes a thread waiting on WaitSynchronization @@ -1863,10 +1811,14 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd } auto& kernel = system.Kernel(); - auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms); + auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); + + if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { + return reserve_result; + } auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const auto result = handle_table.Create(std::move(transfer_mem_handle)); + const auto result{handle_table.Create(std::move(transfer_mem_handle))}; if (result.Failed()) { return result.Code(); } diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp new file mode 100644 index 000000000..dc37fad1a --- /dev/null +++ b/src/core/hle/kernel/synchronization.cpp @@ -0,0 +1,87 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/synchronization.h" +#include "core/hle/kernel/synchronization_object.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +/// Default thread wakeup callback for WaitSynchronization +static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<SynchronizationObject> object, + std::size_t index) { + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); + + if (reason == ThreadWakeupReason::Timeout) { + thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); + return true; + } + + ASSERT(reason == ThreadWakeupReason::Signal); + thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + thread->SetWaitSynchronizationOutput(static_cast<u32>(index)); + return true; +} + +Synchronization::Synchronization(Core::System& system) : system{system} {} + +void Synchronization::SignalObject(SynchronizationObject& obj) const { + if (obj.IsSignaled()) { + obj.WakeupAllWaitingThreads(); + } +} + +std::pair<ResultCode, Handle> Synchronization::WaitFor( + std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { + auto* const thread = system.CurrentScheduler().GetCurrentThread(); + // Find the first object that is acquirable in the provided list of objects + const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), + [thread](const std::shared_ptr<SynchronizationObject>& object) { + return object->IsSignaled(); + }); + + if (itr != sync_objects.end()) { + // We found a ready object, acquire it and set the result value + SynchronizationObject* object = itr->get(); + object->Acquire(thread); + const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); + return {RESULT_SUCCESS, index}; + } + + // No objects were ready to be acquired, prepare to suspend the thread. + + // If a timeout value of 0 was provided, just return the Timeout error code instead of + // suspending the thread. + if (nano_seconds == 0) { + return {RESULT_TIMEOUT, InvalidHandle}; + } + + if (thread->IsSyncCancelled()) { + thread->SetSyncCancelled(false); + return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; + } + + for (auto& object : sync_objects) { + object->AddWaitingThread(SharedFrom(thread)); + } + + thread->SetSynchronizationObjects(std::move(sync_objects)); + thread->SetStatus(ThreadStatus::WaitSynch); + + // Create an event to wake the thread up after the specified nanosecond delay has passed + thread->WakeAfterDelay(nano_seconds); + thread->SetWakeupCallback(DefaultThreadWakeupCallback); + + system.PrepareReschedule(thread->GetProcessorID()); + + return {RESULT_TIMEOUT, InvalidHandle}; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/synchronization.h b/src/core/hle/kernel/synchronization.h new file mode 100644 index 000000000..379f4b1d3 --- /dev/null +++ b/src/core/hle/kernel/synchronization.h @@ -0,0 +1,44 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <utility> +#include <vector> + +#include "core/hle/kernel/object.h" +#include "core/hle/result.h" + +namespace Core { +class System; +} // namespace Core + +namespace Kernel { + +class SynchronizationObject; + +/** + * The 'Synchronization' class is an interface for handling synchronization methods + * used by Synchronization objects and synchronization SVCs. This centralizes processing of + * such + */ +class Synchronization { +public: + explicit Synchronization(Core::System& system); + + /// Signals a synchronization object, waking up all its waiting threads + void SignalObject(SynchronizationObject& obj) const; + + /// Tries to see if waiting for any of the sync_objects is necessary, if not + /// it returns Success and the handle index of the signaled sync object. In + /// case not, the current thread will be locked and wait for nano_seconds or + /// for a synchronization object to signal. + std::pair<ResultCode, Handle> WaitFor( + std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds); + +private: + Core::System& system; +}; +} // namespace Kernel diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index 745f2c4e8..43f3eef18 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -7,24 +7,29 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/synchronization.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/kernel/thread.h" namespace Kernel { -WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {} -WaitObject::~WaitObject() = default; +SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} +SynchronizationObject::~SynchronizationObject() = default; -void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) { +void SynchronizationObject::Signal() { + kernel.Synchronization().SignalObject(*this); +} + +void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr == waiting_threads.end()) waiting_threads.push_back(std::move(thread)); } -void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) { +void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); // If a thread passed multiple handles to the same object, // the kernel might attempt to remove the thread from the object's @@ -33,7 +38,7 @@ void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) { waiting_threads.erase(itr); } -std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const { +std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const { Thread* candidate = nullptr; u32 candidate_priority = THREADPRIO_LOWEST + 1; @@ -51,23 +56,14 @@ std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const { if (ShouldWait(thread.get())) continue; - // A thread is ready to run if it's either in ThreadStatus::WaitSynch - // and the rest of the objects it is waiting on are ready. - bool ready_to_run = true; - if (thread_status == ThreadStatus::WaitSynch) { - ready_to_run = thread->AllWaitObjectsReady(); - } - - if (ready_to_run) { - candidate = thread.get(); - candidate_priority = thread->GetPriority(); - } + candidate = thread.get(); + candidate_priority = thread->GetPriority(); } return SharedFrom(candidate); } -void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { +void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { ASSERT(!ShouldWait(thread.get())); if (!thread) { @@ -75,7 +71,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { } if (thread->IsSleepingOnWait()) { - for (const auto& object : thread->GetWaitObjects()) { + for (const auto& object : thread->GetSynchronizationObjects()) { ASSERT(!object->ShouldWait(thread.get())); object->Acquire(thread.get()); } @@ -83,9 +79,9 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { Acquire(thread.get()); } - const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this)); + const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this)); - thread->ClearWaitObjects(); + thread->ClearSynchronizationObjects(); thread->CancelWakeupTimer(); @@ -96,17 +92,17 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { } if (resume) { thread->ResumeFromWait(); - Core::System::GetInstance().PrepareReschedule(thread->GetProcessorID()); + kernel.PrepareReschedule(thread->GetProcessorID()); } } -void WaitObject::WakeupAllWaitingThreads() { +void SynchronizationObject::WakeupAllWaitingThreads() { while (auto thread = GetHighestPriorityReadyThread()) { WakeupWaitingThread(thread); } } -const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const { +const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const { return waiting_threads; } diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/synchronization_object.h index 9a17958a4..741c31faf 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -15,10 +15,10 @@ class KernelCore; class Thread; /// Class that represents a Kernel object that a thread can be waiting on -class WaitObject : public Object { +class SynchronizationObject : public Object { public: - explicit WaitObject(KernelCore& kernel); - ~WaitObject() override; + explicit SynchronizationObject(KernelCore& kernel); + ~SynchronizationObject() override; /** * Check if the specified thread should wait until the object is available @@ -30,6 +30,13 @@ public: /// Acquire/lock the object for the specified thread if it is available virtual void Acquire(Thread* thread) = 0; + /// Signal this object + virtual void Signal(); + + virtual bool IsSignaled() const { + return is_signaled; + } + /** * Add a thread to wait on this object * @param thread Pointer to thread to add @@ -60,16 +67,20 @@ public: /// Get a const reference to the waiting threads list for debug use const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; +protected: + bool is_signaled{}; // Tells if this sync object is signalled; + private: /// Threads waiting for this object to become available std::vector<std::shared_ptr<Thread>> waiting_threads; }; -// Specialization of DynamicObjectCast for WaitObjects +// Specialization of DynamicObjectCast for SynchronizationObjects template <> -inline std::shared_ptr<WaitObject> DynamicObjectCast<WaitObject>(std::shared_ptr<Object> object) { +inline std::shared_ptr<SynchronizationObject> DynamicObjectCast<SynchronizationObject>( + std::shared_ptr<Object> object) { if (object != nullptr && object->IsWaitable()) { - return std::static_pointer_cast<WaitObject>(object); + return std::static_pointer_cast<SynchronizationObject>(object); } return nullptr; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e84e5ce0d..ae5f2c8bd 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,9 +13,9 @@ #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -32,11 +32,15 @@ bool Thread::ShouldWait(const Thread* thread) const { return status != ThreadStatus::Dead; } +bool Thread::IsSignaled() const { + return status == ThreadStatus::Dead; +} + void Thread::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } -Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {} +Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} Thread::~Thread() = default; void Thread::Stop() { @@ -46,7 +50,7 @@ void Thread::Stop() { kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); callback_handle = 0; SetStatus(ThreadStatus::Dead); - WakeupAllWaitingThreads(); + Signal(); // Clean up any dangling references in objects that this thread was waiting for for (auto& wait_object : wait_objects) { @@ -216,7 +220,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { context.cpu_registers[1] = output; } -s32 Thread::GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const { +s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const { ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1); @@ -337,14 +341,16 @@ void Thread::ChangeCore(u32 core, u64 mask) { SetCoreAndAffinityMask(core, mask); } -bool Thread::AllWaitObjectsReady() const { - return std::none_of( - wait_objects.begin(), wait_objects.end(), - [this](const std::shared_ptr<WaitObject>& object) { return object->ShouldWait(this); }); +bool Thread::AllSynchronizationObjectsReady() const { + return std::none_of(wait_objects.begin(), wait_objects.end(), + [this](const std::shared_ptr<SynchronizationObject>& object) { + return object->ShouldWait(this); + }); } bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, - std::shared_ptr<WaitObject> object, std::size_t index) { + std::shared_ptr<SynchronizationObject> object, + std::size_t index) { ASSERT(wakeup_callback); return wakeup_callback(reason, std::move(thread), std::move(object), index); } @@ -356,7 +362,7 @@ void Thread::SetActivity(ThreadActivity value) { // Set status if not waiting if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { SetStatus(ThreadStatus::Paused); - Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); + kernel.PrepareReschedule(processor_id); } } else if (status == ThreadStatus::Paused) { // Ready to reschedule @@ -426,7 +432,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { const s32 old_core = processor_id; if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { if (static_cast<s32>(ideal_core) < 0) { - processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES); + processor_id = HighestSetCore(affinity_mask, Core::Hardware::NUM_CPU_CORES); } else { processor_id = ideal_core; } @@ -450,7 +456,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(current_priority, core, this); } @@ -461,7 +467,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); } @@ -475,12 +481,12 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) { return; } - auto& scheduler = Core::System::GetInstance().GlobalScheduler(); + auto& scheduler = kernel.GlobalScheduler(); if (processor_id >= 0) { scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(old_priority, core, this); } @@ -497,7 +503,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { } } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); } @@ -507,13 +513,13 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { } void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { - auto& scheduler = Core::System::GetInstance().GlobalScheduler(); + auto& scheduler = kernel.GlobalScheduler(); if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || current_priority >= THREADPRIO_COUNT) { return; } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (((old_affinity_mask >> core) & 1) != 0) { if (core == static_cast<u32>(old_core)) { scheduler.Unschedule(current_priority, core, this); @@ -523,7 +529,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { } } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (((affinity_mask >> core) & 1) != 0) { if (core == static_cast<u32>(processor_id)) { scheduler.Schedule(current_priority, core, this); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 3bcf9e137..7a4916318 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" namespace Kernel { @@ -95,7 +95,7 @@ enum class ThreadSchedMasks : u32 { ForcePauseMask = 0x0070, }; -class Thread final : public WaitObject { +class Thread final : public SynchronizationObject { public: explicit Thread(KernelCore& kernel); ~Thread() override; @@ -104,11 +104,11 @@ public: using ThreadContext = Core::ARM_Interface::ThreadContext; - using ThreadWaitObjects = std::vector<std::shared_ptr<WaitObject>>; + using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>; using WakeupCallback = std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, - std::shared_ptr<WaitObject> object, std::size_t index)>; + std::shared_ptr<SynchronizationObject> object, std::size_t index)>; /** * Creates and returns a new thread. The new thread is immediately scheduled @@ -146,6 +146,7 @@ public: bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; + bool IsSignaled() const override; /** * Gets the thread's current priority @@ -233,7 +234,7 @@ public: * * @param object Object to query the index of. */ - s32 GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const; + s32 GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const; /** * Stops a thread, invalidating it from further use @@ -314,15 +315,15 @@ public: return owner_process; } - const ThreadWaitObjects& GetWaitObjects() const { + const ThreadSynchronizationObjects& GetSynchronizationObjects() const { return wait_objects; } - void SetWaitObjects(ThreadWaitObjects objects) { + void SetSynchronizationObjects(ThreadSynchronizationObjects objects) { wait_objects = std::move(objects); } - void ClearWaitObjects() { + void ClearSynchronizationObjects() { for (const auto& waiting_object : wait_objects) { waiting_object->RemoveWaitingThread(SharedFrom(this)); } @@ -330,7 +331,7 @@ public: } /// Determines whether all the objects this thread is waiting on are ready. - bool AllWaitObjectsReady() const; + bool AllSynchronizationObjectsReady() const; const MutexWaitingThreads& GetMutexWaitingThreads() const { return wait_mutex_threads; @@ -395,7 +396,7 @@ public: * will cause an assertion to trigger. */ bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, - std::shared_ptr<WaitObject> object, std::size_t index); + std::shared_ptr<SynchronizationObject> object, std::size_t index); u32 GetIdealCore() const { return ideal_core; @@ -494,7 +495,7 @@ private: /// Objects that the thread is waiting on, in the same order as they were /// passed to WaitSynchronization. - ThreadWaitObjects wait_objects; + ThreadSynchronizationObjects wait_objects; /// List of threads that are waiting for a mutex that is held by this thread. MutexWaitingThreads wait_mutex_threads; diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index f0e73f57b..f2d3f8b49 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp @@ -8,15 +8,23 @@ #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/result.h" +#include "core/memory.h" namespace Kernel { -TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} -TransferMemory::~TransferMemory() = default; +TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory) + : Object{kernel}, memory{memory} {} -std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, - u64 size, MemoryPermission permissions) { - std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; +TransferMemory::~TransferMemory() { + // Release memory region when transfer memory is destroyed + Reset(); +} + +std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory, + VAddr base_address, u64 size, + MemoryPermission permissions) { + std::shared_ptr<TransferMemory> transfer_memory{ + std::make_shared<TransferMemory>(kernel, memory)}; transfer_memory->base_address = base_address; transfer_memory->memory_size = size; @@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr } const u8* TransferMemory::GetPointer() const { - return backing_block.get()->data(); + return memory.GetPointer(base_address); } u64 TransferMemory::GetSize() const { @@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p return RESULT_SUCCESS; } +ResultCode TransferMemory::Reserve() { + auto& vm_manager{owner_process->VMManager()}; + const auto check_range_result{vm_manager.CheckRangeState( + base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, + MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All, + VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, + MemoryAttribute::IpcAndDeviceMapped)}; + + if (check_range_result.Failed()) { + return check_range_result.Code(); + } + + auto [state_, permissions_, attribute] = *check_range_result; + + if (const auto result{vm_manager.ReprotectRange( + base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))}; + result.IsError()) { + return result; + } + + return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, + attribute | MemoryAttribute::Locked); +} + +ResultCode TransferMemory::Reset() { + auto& vm_manager{owner_process->VMManager()}; + if (const auto result{vm_manager.CheckRangeState( + base_address, memory_size, + MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, + MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None, + VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, + MemoryAttribute::IpcAndDeviceMapped)}; + result.Failed()) { + return result.Code(); + } + + if (const auto result{ + vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)}; + result.IsError()) { + return result; + } + + return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, + MemoryAttribute::None); +} + ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { if (memory_size != size) { return ERR_INVALID_SIZE; diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 0a6e15d18..6e388536a 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h @@ -11,6 +11,10 @@ union ResultCode; +namespace Memory { +class Memory; +} + namespace Kernel { class KernelCore; @@ -26,12 +30,13 @@ enum class MemoryPermission : u32; /// class TransferMemory final : public Object { public: - explicit TransferMemory(KernelCore& kernel); + explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory); ~TransferMemory() override; static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; - static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, + static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory, + VAddr base_address, u64 size, MemoryPermission permissions); TransferMemory(const TransferMemory&) = delete; @@ -80,6 +85,14 @@ public: /// ResultCode UnmapMemory(VAddr address, u64 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(); + private: /// Memory block backing this instance. std::shared_ptr<PhysicalMemory> backing_block; @@ -98,6 +111,8 @@ private: /// Whether or not this transfer memory instance has mapped memory. bool is_mapped = false; + + Memory::Memory& memory; }; } // namespace Kernel diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 0b3500fce..024c22901 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -544,7 +544,8 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const { ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, MemoryAttribute attribute) { - constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped; + constexpr auto ignore_mask = + MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked; constexpr auto attribute_mask = ~ignore_mask; const auto result = CheckRangeState( diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 850a7ebc3..90b4b006a 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -98,6 +98,8 @@ enum class MemoryAttribute : u32 { DeviceMapped = 4, /// Uncached memory Uncached = 8, + + IpcAndDeviceMapped = LockedForIPC | DeviceMapped, }; constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { @@ -654,6 +656,35 @@ public: /// is scheduled. Common::PageTable page_table{Memory::PAGE_BITS}; + using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; + + /// Checks if an address range adheres to the specified states provided. + /// + /// @param address The starting address of the address range. + /// @param size The size of the address range. + /// @param state_mask The memory state mask. + /// @param state The state to compare the individual VMA states against, + /// which is done in the form of: (vma.state & state_mask) != state. + /// @param permission_mask The memory permissions mask. + /// @param permissions The permission to compare the individual VMA permissions against, + /// which is done in the form of: + /// (vma.permission & permission_mask) != permission. + /// @param attribute_mask The memory attribute mask. + /// @param attribute The memory attributes to compare the individual VMA attributes + /// against, which is done in the form of: + /// (vma.attributes & attribute_mask) != attribute. + /// @param ignore_mask The memory attributes to ignore during the check. + /// + /// @returns If successful, returns a tuple containing the memory attributes + /// (with ignored bits specified by ignore_mask unset), memory permissions, and + /// memory state across the memory range. + /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. + /// + CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, + VMAPermission permission_mask, VMAPermission permissions, + MemoryAttribute attribute_mask, MemoryAttribute attribute, + MemoryAttribute ignore_mask) const; + private: using VMAIter = VMAMap::iterator; @@ -707,35 +738,6 @@ private: /// Clears out the page table void ClearPageTable(); - using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; - - /// Checks if an address range adheres to the specified states provided. - /// - /// @param address The starting address of the address range. - /// @param size The size of the address range. - /// @param state_mask The memory state mask. - /// @param state The state to compare the individual VMA states against, - /// which is done in the form of: (vma.state & state_mask) != state. - /// @param permission_mask The memory permissions mask. - /// @param permissions The permission to compare the individual VMA permissions against, - /// which is done in the form of: - /// (vma.permission & permission_mask) != permission. - /// @param attribute_mask The memory attribute mask. - /// @param attribute The memory attributes to compare the individual VMA attributes - /// against, which is done in the form of: - /// (vma.attributes & attribute_mask) != attribute. - /// @param ignore_mask The memory attributes to ignore during the check. - /// - /// @returns If successful, returns a tuple containing the memory attributes - /// (with ignored bits specified by ignore_mask unset), memory permissions, and - /// memory state across the memory range. - /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. - /// - CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, - VMAPermission permission_mask, VMAPermission permissions, - MemoryAttribute attribute_mask, MemoryAttribute attribute, - MemoryAttribute ignore_mask) const; - /// Gets the amount of memory currently mapped (state != Unmapped) in a range. ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp index c9332e3e1..fc2f7c424 100644 --- a/src/core/hle/kernel/writable_event.cpp +++ b/src/core/hle/kernel/writable_event.cpp @@ -22,7 +22,6 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { writable_event->name = name + ":Writable"; writable_event->readable = readable_event; readable_event->name = name + ":Readable"; - readable_event->signaled = false; return {std::move(readable_event), std::move(writable_event)}; } @@ -40,7 +39,7 @@ void WritableEvent::Clear() { } bool WritableEvent::IsSignaled() const { - return readable->signaled; + return readable->IsSignaled(); } } // namespace Kernel diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 95aa5d23d..cc978713b 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -709,8 +709,34 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { apm_sys->SetCpuBoostMode(ctx); } -IStorage::IStorage(std::vector<u8> buffer) - : ServiceFramework("IStorage"), buffer(std::move(buffer)) { +IStorageImpl::~IStorageImpl() = default; + +class StorageDataImpl final : public IStorageImpl { +public: + explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {} + + std::vector<u8>& GetData() override { + return buffer; + } + + const std::vector<u8>& GetData() const override { + return buffer; + } + + std::size_t GetSize() const override { + return buffer.size(); + } + +private: + std::vector<u8> buffer; +}; + +IStorage::IStorage(std::vector<u8>&& buffer) + : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { + Register(); +} + +void IStorage::Register() { // clang-format off static const FunctionInfo functions[] = { {0, &IStorage::Open, "Open"}, @@ -723,8 +749,13 @@ IStorage::IStorage(std::vector<u8> buffer) IStorage::~IStorage() = default; -const std::vector<u8>& IStorage::GetData() const { - return buffer; +void IStorage::Open(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IStorageAccessor>(*this); } void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { @@ -816,7 +847,7 @@ private: LOG_DEBUG(Service_AM, "called"); IPC::RequestParser rp{ctx}; - applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>()); + applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -825,26 +856,25 @@ private: void PopOutData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - const auto storage = applet->GetBroker().PopNormalDataToGame(); if (storage == nullptr) { LOG_ERROR(Service_AM, "storage is a nullptr. There is no data in the current normal channel"); - + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IStorage>(std::move(*storage)); + rb.PushIpcInterface<IStorage>(std::move(storage)); } void PushInteractiveInData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::RequestParser rp{ctx}; - applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>()); + applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>()); ASSERT(applet->IsInitialized()); applet->ExecuteInteractive(); @@ -857,19 +887,18 @@ private: void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - const auto storage = applet->GetBroker().PopInteractiveDataToGame(); if (storage == nullptr) { LOG_ERROR(Service_AM, "storage is a nullptr. There is no data in the current interactive channel"); - + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IStorage>(std::move(*storage)); + rb.PushIpcInterface<IStorage>(std::move(storage)); } void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { @@ -891,15 +920,6 @@ private: std::shared_ptr<Applets::Applet> applet; }; -void IStorage::Open(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IStorageAccessor>(*this); -} - IStorageAccessor::IStorageAccessor(IStorage& storage) : ServiceFramework("IStorageAccessor"), backing(storage) { // clang-format off @@ -921,7 +941,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast<u64>(backing.buffer.size())); + rb.Push(static_cast<u64>(backing.GetSize())); } void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { @@ -932,17 +952,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); - if (data.size() > backing.buffer.size() - offset) { + if (data.size() > backing.GetSize() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", - backing.buffer.size(), data.size(), offset); + backing.GetSize(), data.size(), offset); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_SIZE_OUT_OF_BOUNDS); return; } - std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); + std::memcpy(backing.GetData().data() + offset, data.data(), data.size()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -956,16 +976,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); - if (size > backing.buffer.size() - offset) { + if (size > backing.GetSize() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", - backing.buffer.size(), size, offset); + backing.GetSize(), size, offset); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_SIZE_OUT_OF_BOUNDS); return; } - ctx.WriteBuffer(backing.buffer.data() + offset, size); + ctx.WriteBuffer(backing.GetData().data() + offset, size); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -1031,7 +1051,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex rp.SetCurrentOffset(3); const auto handle{rp.Pop<Kernel::Handle>()}; - const auto transfer_mem = + auto transfer_mem = system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); if (transfer_mem == nullptr) { @@ -1047,7 +1067,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); + rb.PushIpcInterface<IStorage>(std::move(memory)); } IApplicationFunctions::IApplicationFunctions(Core::System& system_) @@ -1189,13 +1209,11 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { u64 build_id{}; std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); - const auto data = - backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); - + auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); if (data.has_value()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<AM::IStorage>(*data); + rb.PushIpcInterface<IStorage>(std::move(*data)); launch_popped_application_specific = true; return; } @@ -1218,7 +1236,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); std::memcpy(buffer.data(), ¶ms, buffer.size()); - rb.PushIpcInterface<AM::IStorage>(buffer); + rb.PushIpcInterface<IStorage>(std::move(buffer)); launch_popped_account_preselect = true; return; } diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 448817be9..0b9a4332d 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -12,7 +12,8 @@ namespace Kernel { class KernelCore; -} +class TransferMemory; +} // namespace Kernel namespace Service::NVFlinger { class NVFlinger; @@ -188,19 +189,36 @@ private: std::shared_ptr<AppletMessageQueue> msg_queue; }; +class IStorageImpl { +public: + virtual ~IStorageImpl(); + virtual std::vector<u8>& GetData() = 0; + virtual const std::vector<u8>& GetData() const = 0; + virtual std::size_t GetSize() const = 0; +}; + class IStorage final : public ServiceFramework<IStorage> { public: - explicit IStorage(std::vector<u8> buffer); + explicit IStorage(std::vector<u8>&& buffer); ~IStorage() override; - const std::vector<u8>& GetData() const; + std::vector<u8>& GetData() { + return impl->GetData(); + } + + const std::vector<u8>& GetData() const { + return impl->GetData(); + } + + std::size_t GetSize() const { + return impl->GetSize(); + } private: + void Register(); void Open(Kernel::HLERequestContext& ctx); - std::vector<u8> buffer; - - friend class IStorageAccessor; + std::shared_ptr<IStorageImpl> impl; }; class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 92f995f8f..c3261f3e6 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -50,16 +50,17 @@ AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() co return {std::move(out_normal), std::move(out_interactive)}; } -std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { +std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { if (out_channel.empty()) return nullptr; auto out = std::move(out_channel.front()); out_channel.pop_front(); + pop_out_data_event.writable->Clear(); return out; } -std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { +std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { if (in_channel.empty()) return nullptr; @@ -68,16 +69,17 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { return out; } -std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { +std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { if (out_interactive_channel.empty()) return nullptr; auto out = std::move(out_interactive_channel.front()); out_interactive_channel.pop_front(); + pop_interactive_out_data_event.writable->Clear(); return out; } -std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { +std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { if (in_interactive_channel.empty()) return nullptr; @@ -86,21 +88,21 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { return out; } -void AppletDataBroker::PushNormalDataFromGame(IStorage storage) { - in_channel.push_back(std::make_unique<IStorage>(storage)); +void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) { + in_channel.emplace_back(std::move(storage)); } -void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { - out_channel.push_back(std::make_unique<IStorage>(storage)); +void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { + out_channel.emplace_back(std::move(storage)); pop_out_data_event.writable->Signal(); } -void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { - in_interactive_channel.push_back(std::make_unique<IStorage>(storage)); +void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { + in_interactive_channel.emplace_back(std::move(storage)); } -void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { - out_interactive_channel.push_back(std::make_unique<IStorage>(storage)); +void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { + out_interactive_channel.emplace_back(std::move(storage)); pop_interactive_out_data_event.writable->Signal(); } diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 16e61fc6f..e75be86a2 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -72,17 +72,17 @@ public: // Retrieves but does not pop the data sent to applet. RawChannelData PeekDataToAppletForDebug() const; - std::unique_ptr<IStorage> PopNormalDataToGame(); - std::unique_ptr<IStorage> PopNormalDataToApplet(); + std::shared_ptr<IStorage> PopNormalDataToGame(); + std::shared_ptr<IStorage> PopNormalDataToApplet(); - std::unique_ptr<IStorage> PopInteractiveDataToGame(); - std::unique_ptr<IStorage> PopInteractiveDataToApplet(); + std::shared_ptr<IStorage> PopInteractiveDataToGame(); + std::shared_ptr<IStorage> PopInteractiveDataToApplet(); - void PushNormalDataFromGame(IStorage storage); - void PushNormalDataFromApplet(IStorage storage); + void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage); + void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage); - void PushInteractiveDataFromGame(IStorage storage); - void PushInteractiveDataFromApplet(IStorage storage); + void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage); + void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage); void SignalStateChanged() const; @@ -94,16 +94,16 @@ private: // Queues are named from applet's perspective // PopNormalDataToApplet and PushNormalDataFromGame - std::deque<std::unique_ptr<IStorage>> in_channel; + std::deque<std::shared_ptr<IStorage>> in_channel; // PopNormalDataToGame and PushNormalDataFromApplet - std::deque<std::unique_ptr<IStorage>> out_channel; + std::deque<std::shared_ptr<IStorage>> out_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame - std::deque<std::unique_ptr<IStorage>> in_interactive_channel; + std::deque<std::shared_ptr<IStorage>> in_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet - std::deque<std::unique_ptr<IStorage>> out_interactive_channel; + std::deque<std::shared_ptr<IStorage>> out_interactive_channel; Kernel::EventPair state_changed_event; diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index eab0d42c9..f12fd7f89 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp @@ -186,7 +186,7 @@ void Error::Execute() { void Error::DisplayCompleted() { complete = true; - broker.PushNormalDataFromApplet(IStorage{{}}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{})); broker.SignalStateChanged(); } diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 328438a1d..104501ac5 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp @@ -20,7 +20,7 @@ namespace Service::AM::Applets { constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { - std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet(); + std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet(); for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { const auto data = storage->GetData(); LOG_INFO(Service_AM, @@ -148,7 +148,7 @@ void Auth::AuthFinished(bool successful) { std::vector<u8> out(sizeof(Return)); std::memcpy(out.data(), &return_, sizeof(Return)); - broker.PushNormalDataFromApplet(IStorage{out}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out))); broker.SignalStateChanged(); } @@ -198,7 +198,7 @@ void PhotoViewer::Execute() { } void PhotoViewer::ViewFinished() { - broker.PushNormalDataFromApplet(IStorage{{}}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{})); broker.SignalStateChanged(); } @@ -234,8 +234,8 @@ void StubApplet::ExecuteInteractive() { LOG_WARNING(Service_AM, "called (STUBBED)"); LogCurrentStorage(broker, "ExecuteInteractive"); - broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); - broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); + broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); broker.SignalStateChanged(); } @@ -243,8 +243,8 @@ void StubApplet::Execute() { LOG_WARNING(Service_AM, "called (STUBBED)"); LogCurrentStorage(broker, "Execute"); - broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); - broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); + broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); broker.SignalStateChanged(); } diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 3eba696ca..70cc23552 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() { void ProfileSelect::Execute() { if (complete) { - broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); return; } @@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { final_data = std::vector<u8>(sizeof(UserSelectionOutput)); std::memcpy(final_data.data(), &output, final_data.size()); - broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); broker.SignalStateChanged(); } diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 748559cd0..54e63c138 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -102,7 +102,8 @@ void SoftwareKeyboard::ExecuteInteractive() { void SoftwareKeyboard::Execute() { if (complete) { - broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); + broker.SignalStateChanged(); return; } @@ -119,7 +120,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE); if (config.utf_8) { - const u64 size = text->size() + 8; + const u64 size = text->size() + sizeof(u64); const auto new_text = Common::UTF16ToUTF8(*text); std::memcpy(output_sub.data(), &size, sizeof(u64)); @@ -130,7 +131,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { std::memcpy(output_main.data() + 4, new_text.data(), std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); } else { - const u64 size = text->size() * 2 + 8; + const u64 size = text->size() * 2 + sizeof(u64); std::memcpy(output_sub.data(), &size, sizeof(u64)); std::memcpy(output_sub.data() + 8, text->data(), std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); @@ -144,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { final_data = output_main; if (complete) { - broker.PushNormalDataFromApplet(IStorage{output_main}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main))); broker.SignalStateChanged(); } else { - broker.PushInteractiveDataFromApplet(IStorage{output_sub}); + broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::move(output_sub))); } } else { output_main[0] = 1; complete = true; - broker.PushNormalDataFromApplet(IStorage{output_main}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main))); broker.SignalStateChanged(); } } diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 5546ef6e8..12443c910 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -284,7 +284,7 @@ void WebBrowser::Finalize() { std::vector<u8> data(sizeof(WebCommonReturnValue)); std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); - broker.PushNormalDataFromApplet(IStorage{data}); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data))); broker.SignalStateChanged(); if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index cb839e4a2..d19513cbb 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -170,8 +170,10 @@ public: {3, nullptr, "SetContextForMultiStream"}, {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"}, {5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"}, - {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, - {7, nullptr, "DecodeInterleavedForMultiStream"}, + {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"}, + {7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"}, + {8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, + {9, nullptr, "DecodeInterleavedForMultiStream"}, }; // clang-format on diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp index 6f5ea095a..def3410cc 100644 --- a/src/core/hle/service/bcat/backend/backend.cpp +++ b/src/core/hle/service/bcat/backend/backend.cpp @@ -117,13 +117,13 @@ bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name, } bool NullBackend::Clear(u64 title_id) { - LOG_DEBUG(Service_BCAT, "called, title_id={:016X}"); + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); return true; } void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) { - LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id, + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, Common::HexToString(passphrase)); } diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp index 67e39a5c4..f589864ee 100644 --- a/src/core/hle/service/bcat/backend/boxcat.cpp +++ b/src/core/hle/service/bcat/backend/boxcat.cpp @@ -200,7 +200,8 @@ private: DownloadResult DownloadInternal(const std::string& resolved_path, u32 timeout_seconds, const std::string& content_type_name) { if (client == nullptr) { - client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT, timeout_seconds); + client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT); + client->set_timeout_sec(timeout_seconds); } httplib::Headers headers{ @@ -448,8 +449,8 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, std::map<std::string, EventStatus>& games) { - httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT), - static_cast<int>(TIMEOUT_SECONDS)}; + httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)}; + client.set_timeout_sec(static_cast<int>(TIMEOUT_SECONDS)); httplib::Headers headers{ {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 55d62fc5e..e6811d5b5 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -420,7 +420,7 @@ public: return; } - IFile file(result.Unwrap()); + auto file = std::make_shared<IFile>(result.Unwrap()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -445,7 +445,7 @@ public: return; } - IDirectory directory(result.Unwrap()); + auto directory = std::make_shared<IDirectory>(result.Unwrap()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -794,8 +794,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called"); - IFileSystem filesystem(fsc.OpenSDMC().Unwrap(), - SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); + auto filesystem = std::make_shared<IFileSystem>( + fsc.OpenSDMC().Unwrap(), SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -846,7 +846,8 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) { id = FileSys::StorageId::NandSystem; } - IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id)); + auto filesystem = + std::make_shared<IFileSystem>(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id)); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -898,7 +899,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { return; } - IStorage storage(std::move(romfs.Unwrap())); + auto storage = std::make_shared<IStorage>(std::move(romfs.Unwrap())); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -937,7 +938,8 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { FileSys::PatchManager pm{title_id}; - IStorage storage(pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); + auto storage = std::make_shared<IStorage>( + pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 4d952adc0..15c09f04c 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -250,6 +250,10 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { auto& rstick_entry = npad_pad_states[controller_idx].r_stick; const auto& button_state = buttons[controller_idx]; const auto& analog_state = sticks[controller_idx]; + const auto [stick_l_x_f, stick_l_y_f] = + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); + const auto [stick_r_x_f, stick_r_y_f] = + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); using namespace Settings::NativeButton; pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); @@ -270,23 +274,32 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); - - pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l_stick_right.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::RIGHT)); + pad_state.l_stick_left.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::LEFT)); + pad_state.l_stick_up.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::UP)); + pad_state.l_stick_down.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::DOWN)); + + pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); + pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); + pad_state.r_stick_right.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); + pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); - const auto [stick_l_x_f, stick_l_y_f] = - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); - const auto [stick_r_x_f, stick_r_y_f] = - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 89bf8b815..e6b56a9f9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -10,6 +10,7 @@ #include "core/core_timing_util.h" #include "core/frontend/emu_window.h" #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" @@ -37,11 +38,11 @@ namespace Service::HID { // Updating period for each HID device. // TODO(ogniK): Find actual polling rate of hid -constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66); +constexpr s64 pad_update_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 66); [[maybe_unused]] constexpr s64 accelerometer_update_ticks = - static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); + static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100); [[maybe_unused]] constexpr s64 gyroscope_update_ticks = - static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); + static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100); constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system) diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index ed5059047..92adde6d4 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -129,12 +129,20 @@ public: {304, nullptr, "Disconnect"}, {400, nullptr, "Initialize"}, {401, nullptr, "Finalize"}, - {402, nullptr, "SetOperationMode"}, + {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+ }; // clang-format on RegisterHandlers(functions); } + + void Initialize2(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + // Result success seem make this services start network and continue. + // If we just pass result error then it will stop and maybe try again and again. + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_UNKNOWN); + } }; class LDNS final : public ServiceFramework<LDNS> { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 6d8bca8bb..f1966ac0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -44,6 +44,8 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve return GetWaitbase(input, output); case IoctlCommand::IocChannelSetTimeoutCommand: return ChannelSetTimeout(input, output); + case IoctlCommand::IocChannelSetTimeslice: + return ChannelSetTimeslice(input, output); default: break; } @@ -228,4 +230,14 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& return 0; } +u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlSetTimeslice params{}; + std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); + LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); + + channel_timeslice = params.timeslice; + + return 0; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index d056dd046..2ac74743f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -48,6 +48,7 @@ private: IocAllocObjCtxCommand = 0xC0104809, IocChannelGetWaitbaseCommand = 0xC0080003, IocChannelSetTimeoutCommand = 0x40044803, + IocChannelSetTimeslice = 0xC004481D, }; enum class CtxObjects : u32_le { @@ -101,6 +102,11 @@ private: static_assert(sizeof(IoctlChannelSetPriority) == 4, "IoctlChannelSetPriority is incorrect size"); + struct IoctlSetTimeslice { + u32_le timeslice; + }; + static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); + struct IoctlEventIdControl { u32_le cmd; // 0=disable, 1=enable, 2=clear u32_le id; @@ -174,6 +180,7 @@ private: u64_le user_data{}; IoctlZCullBind zcull_params{}; u32_le channel_priority{}; + u32_le channel_timeslice{}; u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); @@ -188,6 +195,7 @@ private: const std::vector<u8>& input2, IoctlVersion version); u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); + u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); std::shared_ptr<nvmap> nvmap_dev; u32 assigned_syncpoints{}; diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 62752e419..134152210 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -12,6 +12,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" @@ -26,8 +27,8 @@ namespace Service::NVFlinger { -constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); -constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30); +constexpr s64 frame_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 60); +constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 30); NVFlinger::NVFlinger(Core::System& system) : system(system) { displays.emplace_back(0, "Default", system); @@ -222,7 +223,7 @@ void NVFlinger::Compose() { s64 NVFlinger::GetNextTicks() const { constexpr s64 max_hertz = 120LL; - return (Core::Timing::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz; + return (Core::Hardware::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz; } } // namespace Service::NVFlinger diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 5eb26caf8..8f1be0e48 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -50,16 +50,16 @@ private: IPC::RequestParser rp{ctx}; const auto process_id = rp.PopRaw<u64>(); - const auto data1 = ctx.ReadBuffer(0); - const auto data2 = ctx.ReadBuffer(1); + std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; + if (Type == Core::Reporter::PlayReportType::New) { + data.emplace_back(ctx.ReadBuffer(1)); + } - LOG_DEBUG(Service_PREPO, - "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}", - static_cast<u8>(Type), process_id, data1.size(), data2.size()); + LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}", + static_cast<u8>(Type), process_id, data[0].size()); const auto& reporter{system.GetReporter()}; - reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, - process_id); + reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -70,19 +70,19 @@ private: IPC::RequestParser rp{ctx}; const auto user_id = rp.PopRaw<u128>(); const auto process_id = rp.PopRaw<u64>(); - - const auto data1 = ctx.ReadBuffer(0); - const auto data2 = ctx.ReadBuffer(1); + std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; + if (Type == Core::Reporter::PlayReportType::New) { + data.emplace_back(ctx.ReadBuffer(1)); + } LOG_DEBUG( Service_PREPO, - "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}, " - "data2_size={:016X}", - static_cast<u8>(Type), user_id[1], user_id[0], process_id, data1.size(), data2.size()); + "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}", + static_cast<u8>(Type), user_id[1], user_id[0], process_id, data[0].size()); const auto& reporter{system.GetReporter()}; - reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, - process_id, user_id); + reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id, + user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 884ad173b..f67fab2f9 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -42,6 +42,26 @@ void BSD::Socket(Kernel::HLERequestContext& ctx) { rb.Push<u32>(0); // bsd errno } +void BSD::Select(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // ret + rb.Push<u32>(0); // bsd errno +} + +void BSD::Bind(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // ret + rb.Push<u32>(0); // bsd errno +} + void BSD::Connect(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); @@ -52,6 +72,26 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) { rb.Push<u32>(0); // bsd errno } +void BSD::Listen(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // ret + rb.Push<u32>(0); // bsd errno +} + +void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // ret + rb.Push<u32>(0); // bsd errno +} + void BSD::SendTo(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); @@ -80,7 +120,7 @@ BSD::BSD(const char* name) : ServiceFramework(name) { {2, &BSD::Socket, "Socket"}, {3, nullptr, "SocketExempt"}, {4, nullptr, "Open"}, - {5, nullptr, "Select"}, + {5, &BSD::Select, "Select"}, {6, nullptr, "Poll"}, {7, nullptr, "Sysctl"}, {8, nullptr, "Recv"}, @@ -88,15 +128,15 @@ BSD::BSD(const char* name) : ServiceFramework(name) { {10, nullptr, "Send"}, {11, &BSD::SendTo, "SendTo"}, {12, nullptr, "Accept"}, - {13, nullptr, "Bind"}, + {13, &BSD::Bind, "Bind"}, {14, &BSD::Connect, "Connect"}, {15, nullptr, "GetPeerName"}, {16, nullptr, "GetSockName"}, {17, nullptr, "GetSockOpt"}, - {18, nullptr, "Listen"}, + {18, &BSD::Listen, "Listen"}, {19, nullptr, "Ioctl"}, {20, nullptr, "Fcntl"}, - {21, nullptr, "SetSockOpt"}, + {21, &BSD::SetSockOpt, "SetSockOpt"}, {22, nullptr, "Shutdown"}, {23, nullptr, "ShutdownAllSockets"}, {24, nullptr, "Write"}, diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 0fe0e65c6..3098e3baf 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -18,7 +18,11 @@ private: void RegisterClient(Kernel::HLERequestContext& ctx); void StartMonitoring(Kernel::HLERequestContext& ctx); void Socket(Kernel::HLERequestContext& ctx); + void Select(Kernel::HLERequestContext& ctx); + void Bind(Kernel::HLERequestContext& ctx); void Connect(Kernel::HLERequestContext& ctx); + void Listen(Kernel::HLERequestContext& ctx); + void SetSockOpt(Kernel::HLERequestContext& ctx); void SendTo(Kernel::HLERequestContext& ctx); void Close(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp index ca1a783fc..1575f0b49 100644 --- a/src/core/hle/service/time/standard_steady_clock_core.cpp +++ b/src/core/hle/service/time/standard_steady_clock_core.cpp @@ -5,6 +5,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/service/time/standard_steady_clock_core.h" namespace Service::Time::Clock { @@ -12,7 +13,7 @@ namespace Service::Time::Clock { TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp index c77b98189..44d5bc651 100644 --- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp +++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp @@ -5,6 +5,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/service/time/tick_based_steady_clock_core.h" namespace Service::Time::Clock { @@ -12,7 +13,7 @@ namespace Service::Time::Clock { SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; return {ticks_time_span.ToSeconds(), GetClockSourceId()}; } diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 8ef4efcef..749b7be70 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -6,6 +6,7 @@ #include "core/core.h" #include "core/core_timing.h" #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" @@ -233,7 +234,7 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { const auto ticks{Clock::TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; const s64 base_time_point{context.offset + current_time_point.time_point - ticks.ToSeconds()}; IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index 9b03191bf..fdaef233f 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -5,6 +5,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/steady_clock_core.h" #include "core/hle/service/time/time_sharedmemory.h" @@ -31,7 +32,7 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system, Clock::TimeSpanType current_time_point) { const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; const Clock::SteadyClockContext context{ static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), clock_source_id}; |