diff options
Diffstat (limited to 'src/core/hle')
187 files changed, 6293 insertions, 2513 deletions
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index a6602e12c..eaa5395ac 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -29,9 +29,14 @@ enum class ControlCommand : u32 { }; enum class CommandType : u32 { + Invalid = 0, + LegacyRequest = 1, Close = 2, + LegacyControl = 3, Request = 4, Control = 5, + RequestWithContext = 6, + ControlWithContext = 7, Unspecified, }; @@ -167,6 +172,7 @@ struct DomainMessageHeader { struct { union { BitField<0, 8, CommandType> command; + BitField<8, 8, u32_le> input_object_count; BitField<16, 16, u32_le> size; }; u32_le object_id; diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 3f87c4297..24605a273 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -298,6 +298,13 @@ public: template <typename T> Kernel::SharedPtr<T> GetCopyObject(size_t index); + + template <class T> + std::shared_ptr<T> PopIpcInterface() { + ASSERT(context->Session()->IsDomain()); + ASSERT(context->GetDomainMessageHeader()->input_object_count > 0); + return context->GetDomainRequestHandler<T>(Pop<u32>() - 1); + } }; /// Pop /// diff --git a/src/core/hle/kernel/condition_variable.cpp b/src/core/hle/kernel/condition_variable.cpp deleted file mode 100644 index a786d7f74..000000000 --- a/src/core/hle/kernel/condition_variable.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/hle/kernel/condition_variable.h" -#include "core/hle/kernel/errors.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object_address_table.h" -#include "core/hle/kernel/thread.h" - -namespace Kernel { - -ConditionVariable::ConditionVariable() {} -ConditionVariable::~ConditionVariable() {} - -ResultVal<SharedPtr<ConditionVariable>> ConditionVariable::Create(VAddr guest_addr, - std::string name) { - SharedPtr<ConditionVariable> condition_variable(new ConditionVariable); - - condition_variable->name = std::move(name); - condition_variable->guest_addr = guest_addr; - condition_variable->mutex_addr = 0; - - // Condition variables are referenced by guest address, so track this in the kernel - g_object_address_table.Insert(guest_addr, condition_variable); - - return MakeResult<SharedPtr<ConditionVariable>>(std::move(condition_variable)); -} - -bool ConditionVariable::ShouldWait(Thread* thread) const { - return GetAvailableCount() <= 0; -} - -void ConditionVariable::Acquire(Thread* thread) { - if (GetAvailableCount() <= 0) - return; - - SetAvailableCount(GetAvailableCount() - 1); -} - -ResultCode ConditionVariable::Release(s32 target) { - if (target == -1) { - // When -1, wake up all waiting threads - SetAvailableCount(static_cast<s32>(GetWaitingThreads().size())); - WakeupAllWaitingThreads(); - } else { - // Otherwise, wake up just a single thread - SetAvailableCount(target); - WakeupWaitingThread(GetHighestPriorityReadyThread()); - } - - return RESULT_SUCCESS; -} - -s32 ConditionVariable::GetAvailableCount() const { - return Memory::Read32(guest_addr); -} - -void ConditionVariable::SetAvailableCount(s32 value) const { - Memory::Write32(guest_addr, value); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/condition_variable.h b/src/core/hle/kernel/condition_variable.h deleted file mode 100644 index 1c9f06769..000000000 --- a/src/core/hle/kernel/condition_variable.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <string> -#include <queue> -#include "common/common_types.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/wait_object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class ConditionVariable final : public WaitObject { -public: - /** - * Creates a condition variable. - * @param guest_addr Address of the object tracking the condition variable in guest memory. If - * specified, this condition variable will update the guest object when its state changes. - * @param name Optional name of condition variable. - * @return The created condition variable. - */ - static ResultVal<SharedPtr<ConditionVariable>> Create(VAddr guest_addr, - std::string name = "Unknown"); - - std::string GetTypeName() const override { - return "ConditionVariable"; - } - std::string GetName() const override { - return name; - } - - static const HandleType HANDLE_TYPE = HandleType::ConditionVariable; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - s32 GetAvailableCount() const; - void SetAvailableCount(s32 value) const; - - std::string name; ///< Name of condition variable (optional) - VAddr guest_addr; ///< Address of the guest condition variable value - VAddr mutex_addr; ///< (optional) Address of guest mutex value associated with this condition - ///< variable, used for implementing events - - bool ShouldWait(Thread* thread) const override; - void Acquire(Thread* thread) override; - - /** - * Releases a slot from a condition variable. - * @param target The number of threads to wakeup, -1 is all. - * @return ResultCode indicating if the operation succeeded. - */ - ResultCode Release(s32 target); - -private: - ConditionVariable(); - ~ConditionVariable() override; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 29d8dfdaa..e1b5430bf 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -20,7 +20,10 @@ enum { MaxConnectionsReached = 52, // Confirmed Switch OS error codes + MisalignedAddress = 102, + InvalidProcessorId = 113, InvalidHandle = 114, + InvalidCombination = 116, Timeout = 117, SynchronizationCanceled = 118, TooLarge = 119, diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 3beb55753..f7a9920d8 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -5,6 +5,7 @@ #include <utility> #include "common/assert.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -25,7 +26,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { u16 slot = next_free_slot; if (slot >= generations.size()) { - LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); + NGLOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); return ERR_OUT_OF_HANDLES; } next_free_slot = generations[slot]; @@ -47,7 +48,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { ResultVal<Handle> HandleTable::Duplicate(Handle handle) { SharedPtr<Object> object = GetGeneric(handle); if (object == nullptr) { - LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle); + NGLOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); return ERR_INVALID_HANDLE; } return Create(std::move(object)); @@ -77,7 +78,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { return GetCurrentThread(); } else if (handle == CurrentProcess) { - return g_current_process; + return Core::CurrentProcess(); } if (!IsValid(handle)) { diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index d9faf4b53..01904467e 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -7,6 +7,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" @@ -26,6 +27,32 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s boost::range::remove_erase(connected_sessions, server_session); } +SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, + const std::string& reason, u64 timeout, + WakeupCallback&& callback) { + + // Put the client thread to sleep until the wait event is signaled or the timeout expires. + thread->wakeup_callback = + [context = *this, callback](ThreadWakeupReason reason, SharedPtr<Thread> thread, + SharedPtr<WaitObject> object, size_t index) mutable -> bool { + ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); + callback(thread, context, reason); + context.WriteToOutgoingCommandBuffer(*thread); + return true; + }; + + auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); + thread->status = THREADSTATUS_WAIT_HLE_EVENT; + thread->wait_objects = {event}; + event->AddWaitingThread(thread); + + if (timeout > 0) { + thread->WakeAfterDelay(timeout); + } + + return event; +} + HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) : server_session(std::move(server_session)) { cmd_buf[0] = 0; @@ -35,7 +62,7 @@ HLERequestContext::~HLERequestContext() = default; void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { IPC::RequestParser rp(src_cmdbuf); - command_header = std::make_unique<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); + command_header = std::make_shared<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); if (command_header->type == IPC::CommandType::Close) { // Close does not populate the rest of the IPC header @@ -45,7 +72,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { // If handle descriptor is present, add size of it if (command_header->enable_handle_descriptor) { handle_descriptor_header = - std::make_unique<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>()); + std::make_shared<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>()); if (handle_descriptor_header->send_current_pid) { rp.Skip(2, false); } @@ -83,20 +110,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { // Padding to align to 16 bytes rp.AlignWithPadding(); - if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) { + if (Session()->IsDomain() && ((command_header->type == IPC::CommandType::Request || + command_header->type == IPC::CommandType::RequestWithContext) || + !incoming)) { // If this is an incoming message, only CommandType "Request" has a domain header // All outgoing domain messages have the domain header, if only incoming has it if (incoming || domain_message_header) { domain_message_header = - std::make_unique<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); + std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); } else { if (Session()->IsDomain()) - LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); + NGLOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); } } data_payload_header = - std::make_unique<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>()); + std::make_shared<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>()); data_payload_offset = rp.GetCurrentOffset(); @@ -159,8 +188,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb return RESULT_SUCCESS; } -ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, - HandleTable& dst_table) { +ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { + std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; + Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); + // The header was already built in the internal command buffer. Attempt to parse it to verify // the integrity and then copy it over to the target command buffer. ParseCommandBuffer(cmd_buf.data(), false); @@ -171,7 +203,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P if (domain_message_header) size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); - std::copy_n(cmd_buf.begin(), size, dst_cmdbuf); + std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data()); if (command_header->enable_handle_descriptor) { ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(), @@ -213,50 +245,63 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P dst_cmdbuf[domain_offset++] = static_cast<u32_le>(request_handlers.size()); } } + + // Copy the translated command buffer back into the thread's command buffer area. + Memory::WriteBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); + return RESULT_SUCCESS; } -std::vector<u8> HLERequestContext::ReadBuffer() const { +std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { std::vector<u8> buffer; - const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[0].Size()}; + const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; if (is_buffer_a) { - buffer.resize(BufferDescriptorA()[0].Size()); - Memory::ReadBlock(BufferDescriptorA()[0].Address(), buffer.data(), buffer.size()); + buffer.resize(BufferDescriptorA()[buffer_index].Size()); + Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), + buffer.size()); } else { - buffer.resize(BufferDescriptorX()[0].Size()); - Memory::ReadBlock(BufferDescriptorX()[0].Address(), buffer.data(), buffer.size()); + buffer.resize(BufferDescriptorX()[buffer_index].Size()); + Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), + buffer.size()); } return buffer; } -size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size) const { - const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()}; - - ASSERT_MSG(size <= GetWriteBufferSize(), "Size %d is too big", size); +size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const { + const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; + const size_t buffer_size{GetWriteBufferSize(buffer_index)}; + if (size > buffer_size) { + NGLOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, + buffer_size); + size = buffer_size; // TODO(bunnei): This needs to be HW tested + } if (is_buffer_b) { - Memory::WriteBlock(BufferDescriptorB()[0].Address(), buffer, size); + Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); } else { - Memory::WriteBlock(BufferDescriptorC()[0].Address(), buffer, size); + Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); } return size; } -size_t HLERequestContext::WriteBuffer(const std::vector<u8>& buffer) const { +size_t HLERequestContext::WriteBuffer(const std::vector<u8>& buffer, int buffer_index) const { return WriteBuffer(buffer.data(), buffer.size()); } -size_t HLERequestContext::GetReadBufferSize() const { - const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[0].Size()}; - return is_buffer_a ? BufferDescriptorA()[0].Size() : BufferDescriptorX()[0].Size(); +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(); } -size_t HLERequestContext::GetWriteBufferSize() const { - const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()}; - return is_buffer_b ? BufferDescriptorB()[0].Size() : BufferDescriptorC()[0].Size(); +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(); } std::string HLERequestContext::Description() const { diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index b5631b773..376263eac 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -6,6 +6,7 @@ #include <array> #include <memory> +#include <string> #include <vector> #include <boost/container/small_vector.hpp> #include "common/common_types.h" @@ -13,6 +14,7 @@ #include "core/hle/ipc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/thread.h" namespace Service { class ServiceFrameworkBase; @@ -24,6 +26,7 @@ class Domain; class HandleTable; class HLERequestContext; class Process; +class Event; /** * Interface implemented by HLE Session handlers. @@ -102,14 +105,31 @@ public: return server_session; } + using WakeupCallback = std::function<void(SharedPtr<Thread> thread, HLERequestContext& context, + ThreadWakeupReason reason)>; + + /** + * Puts the specified guest thread to sleep until the returned event is signaled or until the + * specified timeout expires. + * @param thread Thread to be put to sleep. + * @param reason Reason for pausing the thread, to be used for debugging purposes. + * @param timeout Timeout in nanoseconds after which the thread will be awoken and the callback + * invoked with a Timeout reason. + * @param callback Callback to be invoked when the thread is resumed. This callback must write + * the entire command response once again, regardless of the state of it before this function + * was called. + * @returns Event that when signaled will resume the thread and call the callback function. + */ + SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, + u64 timeout, WakeupCallback&& callback); + void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming); /// Populates this context with data from the requesting process/thread. ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, HandleTable& src_table); /// Writes data from this context back to the requesting process/thread. - ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, - HandleTable& dst_table); + ResultCode WriteToOutgoingCommandBuffer(Thread& thread); u32_le GetCommand() const { return command; @@ -139,24 +159,24 @@ public: return buffer_c_desciptors; } - const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { + const std::shared_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { return domain_message_header; } /// Helper function to read a buffer using the appropriate buffer descriptor - std::vector<u8> ReadBuffer() const; + std::vector<u8> ReadBuffer(int buffer_index = 0) const; /// Helper function to write a buffer using the appropriate buffer descriptor - size_t WriteBuffer(const void* buffer, size_t size) const; + size_t WriteBuffer(const void* buffer, size_t size, int buffer_index = 0) const; /// Helper function to write a buffer using the appropriate buffer descriptor - size_t WriteBuffer(const std::vector<u8>& buffer) const; + size_t WriteBuffer(const std::vector<u8>& buffer, int buffer_index = 0) const; /// Helper function to get the size of the input buffer - size_t GetReadBufferSize() const; + size_t GetReadBufferSize(int buffer_index = 0) const; /// Helper function to get the size of the output buffer - size_t GetWriteBufferSize() const; + size_t GetWriteBufferSize(int buffer_index = 0) const; template <typename T> SharedPtr<T> GetCopyObject(size_t index) { @@ -182,6 +202,16 @@ public: domain_objects.emplace_back(std::move(object)); } + template <typename T> + std::shared_ptr<T> GetDomainRequestHandler(size_t index) const { + return std::static_pointer_cast<T>(domain_request_handlers[index]); + } + + void SetDomainRequestHandlers( + const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) { + domain_request_handlers = handlers; + } + /// Clears the list of objects so that no lingering objects are written accidentally to the /// response buffer. void ClearIncomingObjects() { @@ -212,10 +242,10 @@ private: boost::container::small_vector<SharedPtr<Object>, 8> copy_objects; boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; - std::unique_ptr<IPC::CommandHeader> command_header; - std::unique_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; - std::unique_ptr<IPC::DataPayloadHeader> data_payload_header; - std::unique_ptr<IPC::DomainMessageHeader> domain_message_header; + std::shared_ptr<IPC::CommandHeader> command_header; + std::shared_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; + std::shared_ptr<IPC::DataPayloadHeader> data_payload_header; + std::shared_ptr<IPC::DomainMessageHeader> domain_message_header; std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; @@ -225,6 +255,8 @@ private: unsigned data_payload_offset{}; unsigned buffer_c_offset{}; u32_le command{}; + + std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; }; } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b0c3f4ae1..b325b879b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -41,7 +41,6 @@ void Shutdown() { g_object_address_table.Clear(); Kernel::ThreadingShutdown(); - g_current_process = nullptr; Kernel::TimersShutdown(); Kernel::ResourceLimitsShutdown(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c77e58f3c..402ae900f 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -18,12 +18,10 @@ using Handle = u32; enum class HandleType : u32 { Unknown, Event, - Mutex, SharedMemory, Thread, Process, AddressArbiter, - ConditionVariable, Timer, ResourceLimit, CodeSet, @@ -33,10 +31,6 @@ enum class HandleType : u32 { ServerSession, }; -enum { - DEFAULT_STACK_SIZE = 0x10000, -}; - enum class ResetType { OneShot, Sticky, @@ -67,9 +61,7 @@ public: bool IsWaitable() const { switch (GetHandleType()) { case HandleType::Event: - case HandleType::Mutex: case HandleType::Thread: - case HandleType::ConditionVariable: case HandleType::Timer: case HandleType::ServerPort: case HandleType::ServerSession: diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 0b9dc700c..bc144f3de 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -7,6 +7,7 @@ #include <boost/range/algorithm_ext/erase.hpp> #include "common/assert.h" #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/mutex.h" @@ -15,124 +16,119 @@ namespace Kernel { -void ReleaseThreadMutexes(Thread* thread) { - for (auto& mtx : thread->held_mutexes) { - mtx->SetHasWaiters(false); - mtx->SetHoldingThread(nullptr); - mtx->WakeupAllWaitingThreads(); - } - thread->held_mutexes.clear(); -} +/// Returns the number of threads that are waiting for a mutex, and the highest priority one among +/// those. +static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread( + SharedPtr<Thread> current_thread, VAddr mutex_addr) { -Mutex::Mutex() {} -Mutex::~Mutex() {} + SharedPtr<Thread> highest_priority_thread; + u32 num_waiters = 0; -SharedPtr<Mutex> Mutex::Create(SharedPtr<Kernel::Thread> holding_thread, VAddr guest_addr, - std::string name) { - SharedPtr<Mutex> mutex(new Mutex); + for (auto& thread : current_thread->wait_mutex_threads) { + if (thread->mutex_wait_address != mutex_addr) + continue; - mutex->guest_addr = guest_addr; - mutex->name = std::move(name); + ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX); - // If mutex was initialized with a holding thread, acquire it by the holding thread - if (holding_thread) { - mutex->Acquire(holding_thread.get()); + ++num_waiters; + if (highest_priority_thread == nullptr || + thread->GetPriority() < highest_priority_thread->GetPriority()) { + highest_priority_thread = thread; + } } - // Mutexes are referenced by guest address, so track this in the kernel - g_object_address_table.Insert(guest_addr, mutex); - - return mutex; + return {highest_priority_thread, num_waiters}; } -bool Mutex::ShouldWait(Thread* thread) const { - auto holding_thread = GetHoldingThread(); - return holding_thread != nullptr && thread != holding_thread; +/// Update the mutex owner field of all threads waiting on the mutex to point to the new owner. +static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_thread, + SharedPtr<Thread> new_owner) { + auto threads = current_thread->wait_mutex_threads; + for (auto& thread : threads) { + if (thread->mutex_wait_address != mutex_addr) + continue; + + ASSERT(thread->lock_owner == current_thread); + current_thread->RemoveMutexWaiter(thread); + if (new_owner != thread) + new_owner->AddMutexWaiter(thread); + } } -void Mutex::Acquire(Thread* thread) { - ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); +ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, + Handle requesting_thread_handle) { + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); + } - priority = thread->current_priority; - thread->held_mutexes.insert(this); - SetHoldingThread(thread); - thread->UpdatePriority(); - Core::System::GetInstance().PrepareReschedule(); -} + SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); + SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle); -ResultCode Mutex::Release(Thread* thread) { - auto holding_thread = GetHoldingThread(); - ASSERT(holding_thread); + // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another + // thread. + ASSERT(requesting_thread == GetCurrentThread()); - // We can only release the mutex if it's held by the calling thread. - ASSERT(thread == holding_thread); + u32 addr_value = Memory::Read32(address); + + // If the mutex isn't being held, just return success. + if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { + return RESULT_SUCCESS; + } + + if (holding_thread == nullptr) + return ERR_INVALID_HANDLE; + + // Wait until the mutex is released + GetCurrentThread()->mutex_wait_address = address; + GetCurrentThread()->wait_handle = requesting_thread_handle; + + GetCurrentThread()->status = THREADSTATUS_WAIT_MUTEX; + GetCurrentThread()->wakeup_callback = nullptr; + + // Update the lock holder thread's priority to prevent priority inversion. + holding_thread->AddMutexWaiter(GetCurrentThread()); - holding_thread->held_mutexes.erase(this); - holding_thread->UpdatePriority(); - SetHoldingThread(nullptr); - SetHasWaiters(!GetWaitingThreads().empty()); - WakeupAllWaitingThreads(); Core::System::GetInstance().PrepareReschedule(); return RESULT_SUCCESS; } -void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { - WaitObject::AddWaitingThread(thread); - thread->pending_mutexes.insert(this); - SetHasWaiters(true); - UpdatePriority(); -} - -void Mutex::RemoveWaitingThread(Thread* thread) { - WaitObject::RemoveWaitingThread(thread); - thread->pending_mutexes.erase(this); - if (!GetHasWaiters()) - SetHasWaiters(!GetWaitingThreads().empty()); - UpdatePriority(); -} +ResultCode Mutex::Release(VAddr address) { + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); + } -void Mutex::UpdatePriority() { - if (!GetHoldingThread()) - return; + auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); - u32 best_priority = THREADPRIO_LOWEST; - for (auto& waiter : GetWaitingThreads()) { - if (waiter->current_priority < best_priority) - best_priority = waiter->current_priority; + // There are no more threads waiting for the mutex, release it completely. + if (thread == nullptr) { + Memory::Write32(address, 0); + return RESULT_SUCCESS; } - if (best_priority != priority) { - priority = best_priority; - GetHoldingThread()->UpdatePriority(); - } -} + // Transfer the ownership of the mutex from the previous owner to the new one. + TransferMutexOwnership(address, GetCurrentThread(), thread); -Handle Mutex::GetOwnerHandle() const { - GuestState guest_state{Memory::Read32(guest_addr)}; - return guest_state.holding_thread_handle; -} + u32 mutex_value = thread->wait_handle; -SharedPtr<Thread> Mutex::GetHoldingThread() const { - GuestState guest_state{Memory::Read32(guest_addr)}; - return g_handle_table.Get<Thread>(guest_state.holding_thread_handle); -} + if (num_waiters >= 2) { + // Notify the guest that there are still some threads waiting for the mutex + mutex_value |= Mutex::MutexHasWaitersFlag; + } -void Mutex::SetHoldingThread(SharedPtr<Thread> thread) { - GuestState guest_state{Memory::Read32(guest_addr)}; - guest_state.holding_thread_handle.Assign(thread ? thread->guest_handle : 0); - Memory::Write32(guest_addr, guest_state.raw); -} + // Grant the mutex to the next waiting thread and resume it. + Memory::Write32(address, mutex_value); -bool Mutex::GetHasWaiters() const { - GuestState guest_state{Memory::Read32(guest_addr)}; - return guest_state.has_waiters != 0; -} + ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX); + thread->ResumeFromWait(); -void Mutex::SetHasWaiters(bool has_waiters) { - GuestState guest_state{Memory::Read32(guest_addr)}; - guest_state.has_waiters.Assign(has_waiters ? 1 : 0); - Memory::Write32(guest_addr, guest_state.raw); -} + thread->lock_owner = nullptr; + thread->condvar_wait_address = 0; + thread->mutex_wait_address = 0; + thread->wait_handle = 0; + return RESULT_SUCCESS; +} } // namespace Kernel diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 38db21005..3117e7c70 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -15,87 +15,23 @@ namespace Kernel { class Thread; -class Mutex final : public WaitObject { +class Mutex final { public: - /** - * Creates a mutex. - * @param holding_thread Specifies a thread already holding the mutex. If not nullptr, this - * thread will acquire the mutex. - * @param guest_addr Address of the object tracking the mutex in guest memory. If specified, - * this mutex will update the guest object when its state changes. - * @param name Optional name of mutex - * @return Pointer to new Mutex object - */ - static SharedPtr<Mutex> Create(SharedPtr<Kernel::Thread> holding_thread, VAddr guest_addr = 0, - std::string name = "Unknown"); + /// Flag that indicates that a mutex still has threads waiting for it. + static constexpr u32 MutexHasWaitersFlag = 0x40000000; + /// Mask of the bits in a mutex address value that contain the mutex owner. + static constexpr u32 MutexOwnerMask = 0xBFFFFFFF; - std::string GetTypeName() const override { - return "Mutex"; - } - std::string GetName() const override { - return name; - } + /// Attempts to acquire a mutex at the specified address. + static ResultCode TryAcquire(VAddr address, Handle holding_thread_handle, + Handle requesting_thread_handle); - static const HandleType HANDLE_TYPE = HandleType::Mutex; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - u32 priority; ///< The priority of the mutex, used for priority inheritance. - std::string name; ///< Name of mutex (optional) - VAddr guest_addr; ///< Address of the guest mutex value - - /** - * Elevate the mutex priority to the best priority - * among the priorities of all its waiting threads. - */ - void UpdatePriority(); - - bool ShouldWait(Thread* thread) const override; - void Acquire(Thread* thread) override; - - void AddWaitingThread(SharedPtr<Thread> thread) override; - void RemoveWaitingThread(Thread* thread) override; - - /** - * Attempts to release the mutex from the specified thread. - * @param thread Thread that wants to release the mutex. - * @returns The result code of the operation. - */ - ResultCode Release(Thread* thread); - - /// Gets the handle to the holding process stored in the guest state. - Handle GetOwnerHandle() const; - - /// Gets the Thread pointed to by the owner handle - SharedPtr<Thread> GetHoldingThread() const; - /// Sets the holding process handle in the guest state. - void SetHoldingThread(SharedPtr<Thread> thread); - - /// Returns the has_waiters bit in the guest state. - bool GetHasWaiters() const; - /// Sets the has_waiters bit in the guest state. - void SetHasWaiters(bool has_waiters); + /// Releases the mutex at the specified address. + static ResultCode Release(VAddr address); private: - Mutex(); - ~Mutex() override; - - /// Object in guest memory used to track the mutex state - union GuestState { - u32_le raw; - /// Handle of the thread that currently holds the mutex, 0 if available - BitField<0, 30, u32_le> holding_thread_handle; - /// 1 when there are threads waiting for this mutex, otherwise 0 - BitField<30, 1, u32_le> has_waiters; - }; - static_assert(sizeof(GuestState) == 4, "GuestState size is incorrect"); + Mutex() = default; + ~Mutex() = default; }; -/** - * Releases all the mutexes held by the specified thread - * @param thread Thread that is holding the mutexes - */ -void ReleaseThreadMutexes(Thread* thread); - } // namespace Kernel diff --git a/src/core/hle/kernel/object_address_table.cpp b/src/core/hle/kernel/object_address_table.cpp index 434c16add..ec97f6f8e 100644 --- a/src/core/hle/kernel/object_address_table.cpp +++ b/src/core/hle/kernel/object_address_table.cpp @@ -10,12 +10,12 @@ namespace Kernel { ObjectAddressTable g_object_address_table; void ObjectAddressTable::Insert(VAddr addr, SharedPtr<Object> obj) { - ASSERT_MSG(objects.find(addr) == objects.end(), "Object already exists with addr=0x%llx", addr); + ASSERT_MSG(objects.find(addr) == objects.end(), "Object already exists with addr=0x{:X}", addr); objects[addr] = obj; } void ObjectAddressTable::Close(VAddr addr) { - ASSERT_MSG(objects.find(addr) != objects.end(), "Object does not exist with addr=0x%llx", addr); + ASSERT_MSG(objects.find(addr) != objects.end(), "Object does not exist with addr=0x{:X}", addr); objects.erase(addr); } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 8e74059ea..651d932d3 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -20,12 +20,9 @@ namespace Kernel { // Lists all processes that exist in the current session. static std::vector<SharedPtr<Process>> process_list; -SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) { +SharedPtr<CodeSet> CodeSet::Create(std::string name) { SharedPtr<CodeSet> codeset(new CodeSet); - codeset->name = std::move(name); - codeset->program_id = program_id; - return codeset; } @@ -41,6 +38,7 @@ SharedPtr<Process> Process::Create(std::string&& name) { process->flags.raw = 0; process->flags.memory_region.Assign(MemoryRegion::APPLICATION); process->status = ProcessStatus::Created; + process->program_id = 0; process_list.push_back(process); return process; @@ -56,7 +54,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { continue; } else if ((type & 0xF00) == 0xE00) { // 0x0FFF // Allowed interrupts list - LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); + NGLOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); } else if ((type & 0xF80) == 0xF00) { // 0x07FF // Allowed syscalls mask unsigned int index = ((descriptor >> 24) & 7) * 24; @@ -76,7 +74,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { } else if ((type & 0xFFE) == 0xFF8) { // 0x001F // Mapped memory range if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) { - LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); + NGLOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); continue; } u32 end_desc = kernel_caps[i + 1]; @@ -111,19 +109,21 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { int minor = kernel_version & 0xFF; int major = (kernel_version >> 8) & 0xFF; - LOG_INFO(Loader, "ExHeader kernel version: %d.%d", major, minor); + NGLOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor); } else { - LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor); + NGLOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor); } } } void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { - // Allocate and map stack + // Allocate and map the main thread stack + // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part + // of the user address space. vm_manager - .MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, + .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size, std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, - MemoryState::Heap) + MemoryState::Mapped) .Unwrap(); misc_memory_used += stack_size; memory_region->used += stack_size; @@ -134,7 +134,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { HandleSpecialMapping(vm_manager, mapping); } - vm_manager.LogLayout(Log::Level::Debug); + vm_manager.LogLayout(); status = ProcessStatus::Running; Kernel::SetupMainThread(entry_point, main_thread_priority, this); @@ -155,9 +155,9 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { }; // Map CodeSet segments - MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::Code); - MapSegment(module_->rodata, VMAPermission::Read, MemoryState::Static); - MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::Static); + MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::CodeStatic); + MapSegment(module_->rodata, VMAPermission::Read, MemoryState::CodeMutable); + MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable); } VAddr Process::GetLinearHeapAreaAddress() const { @@ -184,6 +184,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per // Initialize heap heap_memory = std::make_shared<std::vector<u8>>(); heap_start = heap_end = target; + } else { + vm_manager.UnmapRange(heap_start, heap_end - heap_start); } // If necessary, expand backing vector to cover new heap extents. @@ -203,7 +205,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per size, MemoryState::Heap)); vm_manager.Reprotect(vma, perms); - heap_used += size; + heap_used = size; memory_region->used += size; return MakeResult<VAddr>(heap_end - size); @@ -290,7 +292,7 @@ ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { CASCADE_RESULT(auto new_vma, vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, - vma->second.meminfo_state)); + MemoryState::Mapped)); // Protect mirror with permissions from old region vm_manager.Reprotect(new_vma, vma->second.permissions); // Remove permissions from old region @@ -321,5 +323,4 @@ SharedPtr<Process> GetProcessById(u32 process_id) { return *itr; } -SharedPtr<Process> g_current_process; } // namespace Kernel diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index add98472f..68e77a4d1 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -56,7 +56,7 @@ class ResourceLimit; struct MemoryRegionInfo; struct CodeSet final : public Object { - static SharedPtr<CodeSet> Create(std::string name, u64 program_id); + static SharedPtr<CodeSet> Create(std::string name); std::string GetTypeName() const override { return "CodeSet"; @@ -72,8 +72,6 @@ struct CodeSet final : public Object { /// Name of the process std::string name; - /// Title ID corresponding to the process - u64 program_id; std::shared_ptr<std::vector<u8>> memory; @@ -113,6 +111,9 @@ public: static u32 next_process_id; + /// Title ID corresponding to the process + u64 program_id; + /// Resource limit descriptor for this process SharedPtr<ResourceLimit> resource_limit; @@ -202,5 +203,4 @@ void ClearProcessList(); /// Retrieves a process from the current list of processes. SharedPtr<Process> GetProcessById(u32 process_id); -extern SharedPtr<Process> g_current_process; } // namespace Kernel diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 0149a3ed6..0ef5fc57d 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp @@ -29,62 +29,62 @@ SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory cat case ResourceLimitCategory::OTHER: return resource_limits[static_cast<u8>(category)]; default: - LOG_CRITICAL(Kernel, "Unknown resource limit category"); + NGLOG_CRITICAL(Kernel, "Unknown resource limit category"); UNREACHABLE(); } } -s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const { +s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { switch (resource) { - case COMMIT: + case ResourceType::Commit: return current_commit; - case THREAD: + case ResourceType::Thread: return current_threads; - case EVENT: + case ResourceType::Event: return current_events; - case MUTEX: + case ResourceType::Mutex: return current_mutexes; - case SEMAPHORE: + case ResourceType::Semaphore: return current_semaphores; - case TIMER: + case ResourceType::Timer: return current_timers; - case SHARED_MEMORY: + case ResourceType::SharedMemory: return current_shared_mems; - case ADDRESS_ARBITER: + case ResourceType::AddressArbiter: return current_address_arbiters; - case CPU_TIME: + case ResourceType::CPUTime: return current_cpu_time; default: - LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); + NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); UNIMPLEMENTED(); return 0; } } -u32 ResourceLimit::GetMaxResourceValue(u32 resource) const { +u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { switch (resource) { - case PRIORITY: + case ResourceType::Priority: return max_priority; - case COMMIT: + case ResourceType::Commit: return max_commit; - case THREAD: + case ResourceType::Thread: return max_threads; - case EVENT: + case ResourceType::Event: return max_events; - case MUTEX: + case ResourceType::Mutex: return max_mutexes; - case SEMAPHORE: + case ResourceType::Semaphore: return max_semaphores; - case TIMER: + case ResourceType::Timer: return max_timers; - case SHARED_MEMORY: + case ResourceType::SharedMemory: return max_shared_mems; - case ADDRESS_ARBITER: + case ResourceType::AddressArbiter: return max_address_arbiters; - case CPU_TIME: + case ResourceType::CPUTime: return max_cpu_time; default: - LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); + NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); UNIMPLEMENTED(); return 0; } diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 1a0ca11f1..cc689a27a 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -16,17 +16,17 @@ enum class ResourceLimitCategory : u8 { OTHER = 3 }; -enum ResourceTypes { - PRIORITY = 0, - COMMIT = 1, - THREAD = 2, - EVENT = 3, - MUTEX = 4, - SEMAPHORE = 5, - TIMER = 6, - SHARED_MEMORY = 7, - ADDRESS_ARBITER = 8, - CPU_TIME = 9, +enum class ResourceType { + Priority = 0, + Commit = 1, + Thread = 2, + Event = 3, + Mutex = 4, + Semaphore = 5, + Timer = 6, + SharedMemory = 7, + AddressArbiter = 8, + CPUTime = 9, }; class ResourceLimit final : public Object { @@ -60,14 +60,14 @@ public: * @param resource Requested resource type * @returns The current value of the resource type */ - s32 GetCurrentResourceValue(u32 resource) const; + s32 GetCurrentResourceValue(ResourceType resource) const; /** * Gets the max value for the specified resource. * @param resource Requested resource type * @returns The max value of the resource type */ - u32 GetMaxResourceValue(u32 resource) const; + u32 GetMaxResourceValue(ResourceType resource) const; /// Name of resource limit object. std::string name; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 235068b22..9cb9e0e5c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -2,12 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" namespace Kernel { +std::mutex Scheduler::scheduler_mutex; + Scheduler::Scheduler(ARM_Interface* cpu_core) : cpu_core(cpu_core) {} Scheduler::~Scheduler() { @@ -17,6 +20,7 @@ Scheduler::~Scheduler() { } bool Scheduler::HaveReadyThreads() { + std::lock_guard<std::mutex> lock(scheduler_mutex); return ready_queue.get_first() != nullptr; } @@ -67,7 +71,7 @@ void Scheduler::SwitchContext(Thread* new_thread) { // Cancel any outstanding wakeup events for this thread new_thread->CancelWakeupTimer(); - auto previous_process = Kernel::g_current_process; + auto previous_process = Core::CurrentProcess(); current_thread = new_thread; @@ -75,8 +79,8 @@ void Scheduler::SwitchContext(Thread* new_thread) { new_thread->status = THREADSTATUS_RUNNING; if (previous_process != current_thread->owner_process) { - Kernel::g_current_process = current_thread->owner_process; - SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); + Core::CurrentProcess() = current_thread->owner_process; + SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); } cpu_core->LoadContext(new_thread->context); @@ -89,41 +93,53 @@ void Scheduler::SwitchContext(Thread* new_thread) { } void Scheduler::Reschedule() { + std::lock_guard<std::mutex> lock(scheduler_mutex); + Thread* cur = GetCurrentThread(); Thread* next = PopNextReadyThread(); if (cur && next) { - LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); + NGLOG_TRACE(Kernel, "context switch {} -> {}", cur->GetObjectId(), next->GetObjectId()); } else if (cur) { - LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); + NGLOG_TRACE(Kernel, "context switch {} -> idle", cur->GetObjectId()); } else if (next) { - LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); + NGLOG_TRACE(Kernel, "context switch idle -> {}", next->GetObjectId()); } SwitchContext(next); } void Scheduler::AddThread(SharedPtr<Thread> thread, u32 priority) { + std::lock_guard<std::mutex> lock(scheduler_mutex); + thread_list.push_back(thread); ready_queue.prepare(priority); } void Scheduler::RemoveThread(Thread* thread) { + std::lock_guard<std::mutex> lock(scheduler_mutex); + thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); } void Scheduler::ScheduleThread(Thread* thread, u32 priority) { + std::lock_guard<std::mutex> lock(scheduler_mutex); + ASSERT(thread->status == THREADSTATUS_READY); ready_queue.push_back(priority, thread); } void Scheduler::UnscheduleThread(Thread* thread, u32 priority) { + std::lock_guard<std::mutex> lock(scheduler_mutex); + ASSERT(thread->status == THREADSTATUS_READY); ready_queue.remove(priority, thread); } void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { + std::lock_guard<std::mutex> lock(scheduler_mutex); + // If thread was ready, adjust queues if (thread->status == THREADSTATUS_READY) ready_queue.move(thread, thread->current_priority, priority); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 27d0247d6..a3b5fb8ca 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -4,6 +4,7 @@ #pragma once +#include <mutex> #include <vector> #include "common/common_types.h" #include "common/thread_queue_list.h" @@ -68,6 +69,8 @@ private: SharedPtr<Thread> current_thread = nullptr; ARM_Interface* cpu_core; + + static std::mutex scheduler_mutex; }; } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 5f31cf19b..bf812c543 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -4,6 +4,7 @@ #include <tuple> +#include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -60,6 +61,9 @@ void ServerSession::Acquire(Thread* thread) { ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { auto& domain_message_header = context.GetDomainMessageHeader(); if (domain_message_header) { + // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs + context.SetDomainRequestHandlers(domain_request_handlers); + // If there is a DomainMessageHeader, then this is CommandType "Request" const u32 object_id{context.GetDomainMessageHeader()->object_id}; switch (domain_message_header->command) { @@ -67,7 +71,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { - LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); + NGLOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); domain_request_handlers[object_id - 1] = nullptr; @@ -77,7 +81,8 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con } } - LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); + NGLOG_CRITICAL(IPC, "Unknown domain command={}", + static_cast<int>(domain_message_header->command.Value())); ASSERT(false); } @@ -91,7 +96,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { Kernel::HLERequestContext context(this); u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); - context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, + context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), Kernel::g_handle_table); ResultCode result = RESULT_SUCCESS; diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index d4505061e..ac4921298 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -4,6 +4,7 @@ #include <cstring> #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/shared_memory.h" @@ -51,8 +52,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u } // Refresh the address mappings for the current process. - if (Kernel::g_current_process != nullptr) { - Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); + if (Core::CurrentProcess() != nullptr) { + Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); } } else { auto& vm_manager = shared_memory->owner_process->vm_manager; @@ -106,31 +107,19 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi // Error out if the requested permissions don't match what the creator process allows. if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { - LOG_ERROR(Kernel, "cannot map id=%u, address=0x%llx name=%s, permissions don't match", - GetObjectId(), address, name.c_str()); + NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", + GetObjectId(), address, name); return ERR_INVALID_COMBINATION; } // Error out if the provided permissions are not compatible with what the creator process needs. if (other_permissions != MemoryPermission::DontCare && static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { - LOG_ERROR(Kernel, "cannot map id=%u, address=0x%llx name=%s, permissions don't match", - GetObjectId(), address, name.c_str()); + NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", + GetObjectId(), address, name); return ERR_WRONG_PERMISSION; } - // TODO(Subv): The same process that created a SharedMemory object - // can not map it in its own address space unless it was created with addr=0, result 0xD900182C. - - if (address != 0) { - // TODO(shinyquagsire23): Check for virtual/mappable memory here too? - if (address >= Memory::HEAP_VADDR && address < Memory::HEAP_VADDR_END) { - LOG_ERROR(Kernel, "cannot map id=%u, address=0x%llx name=%s, invalid address", - GetObjectId(), address, name.c_str()); - return ERR_INVALID_ADDRESS; - } - } - VAddr target_address = address; if (base_address == 0 && target_address == 0) { @@ -142,10 +131,10 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi auto result = target_process->vm_manager.MapMemoryBlock( target_address, backing_block, backing_block_offset, size, MemoryState::Shared); if (result.Failed()) { - LOG_ERROR( + NGLOG_ERROR( Kernel, - "cannot map id=%u, target_address=0x%llx name=%s, error mapping to virtual memory", - GetObjectId(), target_address, name.c_str()); + "cannot map id={}, target_address=0x{:X} name={}, error mapping to virtual memory", + GetObjectId(), target_address, name); return result.Code(); } @@ -163,7 +152,7 @@ VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute); return static_cast<VMAPermission>(masked_permissions); -}; +} u8* SharedMemory::GetPointer(u32 offset) { return backing_block->data() + backing_block_offset + offset; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b2e8b5ce3..097416e9e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -4,14 +4,15 @@ #include <algorithm> #include <cinttypes> +#include <iterator> #include "common/logging/log.h" #include "common/microprofile.h" #include "common/string_util.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/condition_variable.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/mutex.h" @@ -30,30 +31,30 @@ namespace Kernel { /// Set the process heap to a given Size. It can both extend and shrink the heap. static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { - LOG_TRACE(Kernel_SVC, "called, heap_size=0x%llx", heap_size); - auto& process = *g_current_process; + NGLOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); + auto& process = *Core::CurrentProcess(); CASCADE_RESULT(*heap_addr, process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); return RESULT_SUCCESS; } static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x%llx", addr); + NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x{:X}", addr); return RESULT_SUCCESS; } /// Maps a memory range into a different range. static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, - src_addr, size); - return g_current_process->MirrorMemory(dst_addr, src_addr, size); + NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, + src_addr, size); + return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); } /// Unmaps a region that was previously mapped with svcMapMemory static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, - src_addr, size); - return g_current_process->UnmapMemory(dst_addr, src_addr, size); + NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, + src_addr, size); + return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); } /// Connect to an OS service given the port name, returns the handle to the port to out @@ -67,11 +68,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address if (port_name.size() > PortNameMaxLength) return ERR_PORT_NAME_TOO_LONG; - LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name.c_str()); + NGLOG_TRACE(Kernel_SVC, "called port_name={}", port_name); auto it = Service::g_kernel_named_ports.find(port_name); if (it == Service::g_kernel_named_ports.end()) { - LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name.c_str()); + NGLOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); return ERR_NOT_FOUND; } @@ -89,11 +90,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address static ResultCode SendSyncRequest(Handle handle) { SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle); if (!session) { - LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle); + NGLOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; } - LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); + NGLOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); Core::System::GetInstance().PrepareReschedule(); @@ -104,7 +105,7 @@ static ResultCode SendSyncRequest(Handle handle) { /// Get the ID for the specified thread. static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); + NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); if (!thread) { @@ -117,7 +118,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { /// Get the ID of the specified process static ResultCode GetProcessId(u32* process_id, Handle process_handle) { - LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); + NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle); if (!process) { @@ -144,41 +145,11 @@ static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thr return true; }; -/// Wait for a kernel object to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronization1( - SharedPtr<WaitObject> object, Thread* thread, s64 nano_seconds = -1, - std::function<Thread::WakeupCallback> wakeup_callback = DefaultThreadWakeupCallback) { - - if (!object) { - return ERR_INVALID_HANDLE; - } - - if (object->ShouldWait(thread)) { - if (nano_seconds == 0) { - return RESULT_TIMEOUT; - } - - thread->wait_objects = {object}; - object->AddWaitingThread(thread); - thread->status = THREADSTATUS_WAIT_SYNCH_ANY; - - // Create an event to wake the thread up after the specified nanosecond delay has passed - thread->WakeAfterDelay(nano_seconds); - thread->wakeup_callback = wakeup_callback; - - Core::System::GetInstance().PrepareReschedule(); - } else { - object->Acquire(thread); - } - - return RESULT_SUCCESS; -} - /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count, s64 nano_seconds) { - LOG_TRACE(Kernel_SVC, "called handles_address=0x%llx, handle_count=%d, nano_seconds=%d", - handles_address, handle_count, nano_seconds); + NGLOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", + handles_address, handle_count, nano_seconds); if (!Memory::IsValidVirtualAddress(handles_address)) return ERR_INVALID_POINTER; @@ -231,14 +202,14 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 thread->WakeAfterDelay(nano_seconds); thread->wakeup_callback = DefaultThreadWakeupCallback; - Core::System::GetInstance().PrepareReschedule(); + Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); return RESULT_TIMEOUT; } /// Resumes a thread waiting on WaitSynchronization static ResultCode CancelSynchronization(Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); + NGLOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); if (!thread) { @@ -255,74 +226,56 @@ static ResultCode CancelSynchronization(Handle thread_handle) { /// Attempts to locks a mutex, creating it if it does not already exist static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, Handle requesting_thread_handle) { - LOG_TRACE(Kernel_SVC, - "called holding_thread_handle=0x%08X, mutex_addr=0x%llx, " - "requesting_current_thread_handle=0x%08X", - holding_thread_handle, mutex_addr, requesting_thread_handle); - - SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); - SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle); - - ASSERT(requesting_thread); - ASSERT(requesting_thread == GetCurrentThread()); - - SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr); - if (!mutex) { - // Create a new mutex for the specified address if one does not already exist - mutex = Mutex::Create(holding_thread, mutex_addr); - mutex->name = Common::StringFromFormat("mutex-%llx", mutex_addr); - } - - ASSERT(holding_thread == mutex->GetHoldingThread()); + NGLOG_TRACE(Kernel_SVC, + "called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, " + "requesting_current_thread_handle=0x{:08X}", + holding_thread_handle, mutex_addr, requesting_thread_handle); - return WaitSynchronization1(mutex, requesting_thread.get()); + return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle); } /// Unlock a mutex static ResultCode ArbitrateUnlock(VAddr mutex_addr) { - LOG_TRACE(Kernel_SVC, "called mutex_addr=0x%llx", mutex_addr); - - SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr); - ASSERT(mutex); + NGLOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); - return mutex->Release(GetCurrentThread()); + return Mutex::Release(mutex_addr); } /// Break program execution static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { - LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); + NGLOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); ASSERT(false); } /// Used to output a message on a debug hardware unit - does nothing on a retail unit static void OutputDebugString(VAddr address, s32 len) { - std::vector<char> string(len); - Memory::ReadBlock(address, string.data(), len); - LOG_DEBUG(Debug_Emulated, "%.*s", len, string.data()); + std::string str(len, '\0'); + Memory::ReadBlock(address, str.data(), str.size()); + NGLOG_DEBUG(Debug_Emulated, "{}", str); } /// Gets system/memory information for the current process static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) { - LOG_TRACE(Kernel_SVC, "called info_id=0x%X, info_sub_id=0x%X, handle=0x%08X", info_id, - info_sub_id, handle); + NGLOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, + info_sub_id, handle); - auto& vm_manager = g_current_process->vm_manager; + auto& vm_manager = Core::CurrentProcess()->vm_manager; switch (static_cast<GetInfoType>(info_id)) { case GetInfoType::AllowedCpuIdBitmask: - *result = g_current_process->allowed_processor_mask; + *result = Core::CurrentProcess()->allowed_processor_mask; break; case GetInfoType::AllowedThreadPrioBitmask: - *result = g_current_process->allowed_thread_priority_mask; + *result = Core::CurrentProcess()->allowed_thread_priority_mask; break; case GetInfoType::MapRegionBaseAddr: - *result = vm_manager.GetMapRegionBaseAddr(); + *result = Memory::MAP_REGION_VADDR; break; case GetInfoType::MapRegionSize: - *result = vm_manager.GetAddressSpaceSize(); + *result = Memory::MAP_REGION_SIZE; break; case GetInfoType::HeapRegionBaseAddr: - *result = vm_manager.GetNewMapRegionBaseAddr() + vm_manager.GetNewMapRegionSize(); + *result = Memory::HEAP_VADDR; break; case GetInfoType::HeapRegionSize: *result = Memory::HEAP_SIZE; @@ -346,21 +299,21 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) *result = vm_manager.GetAddressSpaceSize(); break; case GetInfoType::NewMapRegionBaseAddr: - *result = vm_manager.GetNewMapRegionBaseAddr(); + *result = Memory::NEW_MAP_REGION_VADDR; break; case GetInfoType::NewMapRegionSize: - *result = vm_manager.GetNewMapRegionSize(); + *result = Memory::NEW_MAP_REGION_SIZE; break; case GetInfoType::IsVirtualAddressMemoryEnabled: - *result = g_current_process->is_virtual_address_memory_enabled; + *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; break; case GetInfoType::TitleId: - LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); + NGLOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); *result = 0; break; case GetInfoType::PrivilegedProcessId: - LOG_WARNING(Kernel_SVC, - "(STUBBED) Attempted to query priviledged process id bounds, returned 0"); + NGLOG_WARNING(Kernel_SVC, + "(STUBBED) Attempted to query privileged process id bounds, returned 0"); *result = 0; break; case GetInfoType::UserExceptionContextAddr: @@ -375,6 +328,19 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) return RESULT_SUCCESS; } +/// Sets the thread activity +static ResultCode SetThreadActivity(Handle handle, u32 unknown) { + NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle, + unknown); + return RESULT_SUCCESS; +} + +/// Gets the thread context +static ResultCode GetThreadContext(Handle handle, VAddr addr) { + NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr); + return RESULT_SUCCESS; +} + /// Gets the priority for the specified thread static ResultCode GetThreadPriority(u32* priority, Handle handle) { const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(handle); @@ -397,33 +363,29 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { // Note: The kernel uses the current process's resource limit instead of // the one from the thread owner's resource limit. - SharedPtr<ResourceLimit>& resource_limit = g_current_process->resource_limit; - if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { + SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; + if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { return ERR_NOT_AUTHORIZED; } thread->SetPriority(priority); - thread->UpdatePriority(); - // Update the mutexes that this thread is waiting for - for (auto& mutex : thread->pending_mutexes) - mutex->UpdatePriority(); - - Core::System::GetInstance().PrepareReschedule(); + Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); return RESULT_SUCCESS; } /// Get which CPU core is executing the current thread static u32 GetCurrentProcessorNumber() { - LOG_WARNING(Kernel_SVC, "(STUBBED) called, defaulting to processor 0"); - return 0; + NGLOG_TRACE(Kernel_SVC, "called"); + return GetCurrentThread()->processor_id; } static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, u32 permissions) { - LOG_TRACE(Kernel_SVC, - "called, shared_memory_handle=0x%08X, addr=0x%llx, size=0x%llx, permissions=0x%08X", - shared_memory_handle, addr, size, permissions); + NGLOG_TRACE( + Kernel_SVC, + "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", + shared_memory_handle, addr, size, permissions); SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); if (!shared_memory) { @@ -440,23 +402,22 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s case MemoryPermission::WriteExecute: case MemoryPermission::ReadWriteExecute: case MemoryPermission::DontCare: - return shared_memory->Map(g_current_process.get(), addr, permissions_type, + return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, MemoryPermission::DontCare); default: - LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); + NGLOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); } return RESULT_SUCCESS; } static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { - LOG_WARNING(Kernel_SVC, - "called, shared_memory_handle=0x%08X, addr=0x%" PRIx64 ", size=0x%" PRIx64 "", - shared_memory_handle, addr, size); + NGLOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", + shared_memory_handle, addr, size); SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); - return shared_memory->Unmap(g_current_process.get(), addr); + return shared_memory->Unmap(Core::CurrentProcess().get(), addr); } /// Query process memory @@ -468,11 +429,11 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i } auto vma = process->vm_manager.FindVMA(addr); memory_info->attributes = 0; - if (vma == g_current_process->vm_manager.vma_map.end()) { + if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) { memory_info->base_address = 0; memory_info->permission = static_cast<u32>(VMAPermission::None); memory_info->size = 0; - memory_info->type = static_cast<u32>(MemoryState::Free); + memory_info->type = static_cast<u32>(MemoryState::Unmapped); } else { memory_info->base_address = vma->second.base; memory_info->permission = static_cast<u32>(vma->second.permissions); @@ -480,40 +441,47 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i memory_info->type = static_cast<u32>(vma->second.meminfo_state); } - LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=%llx", process_handle, addr); + NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr); return RESULT_SUCCESS; } /// Query memory static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) { - LOG_TRACE(Kernel_SVC, "called, addr=%llx", addr); + NGLOG_TRACE(Kernel_SVC, "called, addr={:X}", addr); return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr); } /// Exits the current process static void ExitProcess() { - LOG_INFO(Kernel_SVC, "Process %u exiting", g_current_process->process_id); + NGLOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id); - ASSERT_MSG(g_current_process->status == ProcessStatus::Running, "Process has already exited"); + ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running, + "Process has already exited"); - g_current_process->status = ProcessStatus::Exited; + Core::CurrentProcess()->status = ProcessStatus::Exited; - // Stop all the process threads that are currently waiting for objects. - auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); - for (auto& thread : thread_list) { - if (thread->owner_process != g_current_process) - continue; + auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) { + for (auto& thread : thread_list) { + if (thread->owner_process != Core::CurrentProcess()) + continue; - if (thread == GetCurrentThread()) - continue; + if (thread == GetCurrentThread()) + continue; - // TODO(Subv): When are the other running/ready threads terminated? - ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || - thread->status == THREADSTATUS_WAIT_SYNCH_ALL, - "Exiting processes with non-waiting threads is currently unimplemented"); + // TODO(Subv): When are the other running/ready threads terminated? + ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || + thread->status == THREADSTATUS_WAIT_SYNCH_ALL, + "Exiting processes with non-waiting threads is currently unimplemented"); - thread->Stop(); - } + thread->Stop(); + } + }; + + auto& system = Core::System::GetInstance(); + stop_threads(system.Scheduler(0)->GetThreadList()); + stop_threads(system.Scheduler(1)->GetThreadList()); + stop_threads(system.Scheduler(2)->GetThreadList()); + stop_threads(system.Scheduler(3)->GetThreadList()); // Kill the current thread GetCurrentThread()->Stop(); @@ -524,72 +492,71 @@ static void ExitProcess() { /// Creates a new thread static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, u32 priority, s32 processor_id) { - std::string name = Common::StringFromFormat("unknown-%llx", entry_point); + std::string name = fmt::format("unknown-{:X}", entry_point); if (priority > THREADPRIO_LOWEST) { return ERR_OUT_OF_RANGE; } - SharedPtr<ResourceLimit>& resource_limit = g_current_process->resource_limit; - if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { + SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; + if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { return ERR_NOT_AUTHORIZED; } if (processor_id == THREADPROCESSORID_DEFAULT) { // Set the target CPU to the one specified in the process' exheader. - processor_id = g_current_process->ideal_processor; + processor_id = Core::CurrentProcess()->ideal_processor; ASSERT(processor_id != THREADPROCESSORID_DEFAULT); } switch (processor_id) { case THREADPROCESSORID_0: - break; case THREADPROCESSORID_1: case THREADPROCESSORID_2: case THREADPROCESSORID_3: - // TODO(bunnei): Implement support for other processor IDs - LOG_ERROR(Kernel_SVC, - "Newly created thread must run in another thread (%u), unimplemented.", - processor_id); break; default: - ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id); + ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); break; } CASCADE_RESULT(SharedPtr<Thread> thread, Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, - g_current_process)); + Core::CurrentProcess())); CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); *out_handle = thread->guest_handle; Core::System::GetInstance().PrepareReschedule(); + Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); - LOG_TRACE(Kernel_SVC, - "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " - "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", - entry_point, name.c_str(), arg, stack_top, priority, processor_id, *out_handle); + NGLOG_TRACE(Kernel_SVC, + "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " + "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", + entry_point, name, arg, stack_top, priority, processor_id, *out_handle); return RESULT_SUCCESS; } /// Starts the thread for the provided handle static ResultCode StartThread(Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); + NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); if (!thread) { return ERR_INVALID_HANDLE; } + ASSERT(thread->status == THREADSTATUS_DORMANT); + thread->ResumeFromWait(); + Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); return RESULT_SUCCESS; } /// Called when a thread exits static void ExitThread() { - LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::CPU().GetPC()); + NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC()); ExitCurrentThread(); Core::System::GetInstance().PrepareReschedule(); @@ -597,11 +564,11 @@ static void ExitThread() { /// Sleep the current thread static void SleepThread(s64 nanoseconds) { - LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); + NGLOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); // Don't attempt to yield execution if there are no available threads to run, // this way we avoid a useless reschedule to the idle thread. - if (nanoseconds == 0 && !Core::System::GetInstance().Scheduler().HaveReadyThreads()) + if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads()) return; // Sleep current thread and check for next thread to schedule @@ -616,111 +583,107 @@ static void SleepThread(s64 nanoseconds) { /// Signal process wide key atomic static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, Handle thread_handle, s64 nano_seconds) { - LOG_TRACE( + NGLOG_TRACE( Kernel_SVC, - "called mutex_addr=%llx, condition_variable_addr=%llx, thread_handle=0x%08X, timeout=%d", + "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", mutex_addr, condition_variable_addr, thread_handle, nano_seconds); SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); ASSERT(thread); - SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr); - if (!mutex) { - // Create a new mutex for the specified address if one does not already exist - mutex = Mutex::Create(thread, mutex_addr); - mutex->name = Common::StringFromFormat("mutex-%llx", mutex_addr); - } + CASCADE_CODE(Mutex::Release(mutex_addr)); - SharedPtr<ConditionVariable> condition_variable = - g_object_address_table.Get<ConditionVariable>(condition_variable_addr); - if (!condition_variable) { - // Create a new condition_variable for the specified address if one does not already exist - condition_variable = ConditionVariable::Create(condition_variable_addr).Unwrap(); - condition_variable->name = - Common::StringFromFormat("condition-variable-%llx", condition_variable_addr); - } + SharedPtr<Thread> current_thread = GetCurrentThread(); + current_thread->condvar_wait_address = condition_variable_addr; + current_thread->mutex_wait_address = mutex_addr; + current_thread->wait_handle = thread_handle; + current_thread->status = THREADSTATUS_WAIT_MUTEX; + current_thread->wakeup_callback = nullptr; - if (condition_variable->mutex_addr) { - // Previously created the ConditionVariable using WaitProcessWideKeyAtomic, verify - // everything is correct - ASSERT(condition_variable->mutex_addr == mutex_addr); - } else { - // Previously created the ConditionVariable using SignalProcessWideKey, set the mutex - // associated with it - condition_variable->mutex_addr = mutex_addr; - } + current_thread->WakeAfterDelay(nano_seconds); - if (mutex->GetOwnerHandle()) { - // Release the mutex if the current thread is holding it - mutex->Release(thread.get()); - } + // Note: Deliberately don't attempt to inherit the lock owner's priority. - auto wakeup_callback = [mutex, nano_seconds](ThreadWakeupReason reason, - SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, size_t index) { - ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY); - - if (reason == ThreadWakeupReason::Timeout) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return true; - } - - ASSERT(reason == ThreadWakeupReason::Signal); + Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); + return RESULT_SUCCESS; +} - // Now try to acquire the mutex and don't resume if it's not available. - if (!mutex->ShouldWait(thread.get())) { - mutex->Acquire(thread.get()); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - return true; - } +/// Signal process wide key +static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) { + NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", + condition_variable_addr, target); + + auto RetrieveWaitingThreads = + [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) { + const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); + auto& thread_list = scheduler->GetThreadList(); + + for (auto& thread : thread_list) { + if (thread->condvar_wait_address == condvar_addr) + waiting_threads.push_back(thread); + } + }; + + // Retrieve a list of all threads that are waiting for this condition variable. + std::vector<SharedPtr<Thread>> waiting_threads; + RetrieveWaitingThreads(0, waiting_threads, condition_variable_addr); + RetrieveWaitingThreads(1, waiting_threads, condition_variable_addr); + RetrieveWaitingThreads(2, waiting_threads, condition_variable_addr); + RetrieveWaitingThreads(3, waiting_threads, condition_variable_addr); + // Sort them by priority, such that the highest priority ones come first. + std::sort(waiting_threads.begin(), waiting_threads.end(), + [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { + return lhs->current_priority < rhs->current_priority; + }); + + // Only process up to 'target' threads, unless 'target' is -1, in which case process + // them all. + size_t last = waiting_threads.size(); + if (target != -1) + last = target; + + // If there are no threads waiting on this condition variable, just exit + if (last > waiting_threads.size()) + return RESULT_SUCCESS; - if (nano_seconds == 0) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return true; - } + for (size_t index = 0; index < last; ++index) { + auto& thread = waiting_threads[index]; - thread->wait_objects = {mutex}; - mutex->AddWaitingThread(thread); - thread->status = THREADSTATUS_WAIT_SYNCH_ANY; + ASSERT(thread->condvar_wait_address == condition_variable_addr); - // Create an event to wake the thread up after the - // specified nanosecond delay has passed - thread->WakeAfterDelay(nano_seconds); - thread->wakeup_callback = DefaultThreadWakeupCallback; + // If the mutex is not yet acquired, acquire it. + u32 mutex_val = Memory::Read32(thread->mutex_wait_address); - Core::System::GetInstance().PrepareReschedule(); + if (mutex_val == 0) { + // We were able to acquire the mutex, resume this thread. + Memory::Write32(thread->mutex_wait_address, thread->wait_handle); + ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX); + thread->ResumeFromWait(); - return false; - }; - CASCADE_CODE( - WaitSynchronization1(condition_variable, thread.get(), nano_seconds, wakeup_callback)); + auto lock_owner = thread->lock_owner; + if (lock_owner) + lock_owner->RemoveMutexWaiter(thread); - return RESULT_SUCCESS; -} + thread->lock_owner = nullptr; + thread->mutex_wait_address = 0; + thread->condvar_wait_address = 0; + thread->wait_handle = 0; + } else { + // Couldn't acquire the mutex, block the thread. + Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); + auto owner = g_handle_table.Get<Thread>(owner_handle); + ASSERT(owner); + ASSERT(thread->status != THREADSTATUS_RUNNING); + thread->status = THREADSTATUS_WAIT_MUTEX; + thread->wakeup_callback = nullptr; -/// Signal process wide key -static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) { - LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x%llx, target=0x%08x", - condition_variable_addr, target); - - // Wakeup all or one thread - Any other value is unimplemented - ASSERT(target == -1 || target == 1); - - SharedPtr<ConditionVariable> condition_variable = - g_object_address_table.Get<ConditionVariable>(condition_variable_addr); - if (!condition_variable) { - // Create a new condition_variable for the specified address if one does not already exist - condition_variable = ConditionVariable::Create(condition_variable_addr).Unwrap(); - condition_variable->name = - Common::StringFromFormat("condition-variable-%llx", condition_variable_addr); - } + // Signal that the mutex now has a waiting thread. + Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag); - CASCADE_CODE(condition_variable->Release(target)); + owner->AddMutexWaiter(thread); - if (condition_variable->mutex_addr) { - // If a mutex was created for this condition_variable, wait the current thread on it - SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(condition_variable->mutex_addr); - return WaitSynchronization1(mutex, GetCurrentThread()); + Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); + } } return RESULT_SUCCESS; @@ -738,13 +701,13 @@ static u64 GetSystemTick() { /// Close a handle static ResultCode CloseHandle(Handle handle) { - LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle); + NGLOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); return g_handle_table.Close(handle); } /// Reset an event static ResultCode ResetSignal(Handle handle) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x%08X", handle); + NGLOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); auto event = g_handle_table.Get<Event>(handle); ASSERT(event != nullptr); event->Clear(); @@ -753,21 +716,69 @@ static ResultCode ResetSignal(Handle handle) { /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%llx, size=0x%llx, perms=%08X", addr, size, - permissions); + NGLOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, + size, permissions); *handle = 0; return RESULT_SUCCESS; } -static ResultCode SetThreadCoreMask(u64, u64, u64) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called"); +static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) { + NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); + + const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); + if (!thread) { + return ERR_INVALID_HANDLE; + } + + *core = thread->ideal_core; + *mask = thread->affinity_mask; + + return RESULT_SUCCESS; +} + +static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { + NGLOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, + mask, core); + + const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); + if (!thread) { + return ERR_INVALID_HANDLE; + } + + if (core == THREADPROCESSORID_DEFAULT) { + ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT); + // Set the target CPU to the one specified in the process' exheader. + core = thread->owner_process->ideal_processor; + mask = 1 << core; + } + + if (mask == 0) { + return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); + } + + /// This value is used to only change the affinity mask without changing the current ideal core. + static constexpr u32 OnlyChangeMask = static_cast<u32>(-3); + + if (core == OnlyChangeMask) { + core = thread->ideal_core; + } else if (core >= Core::NUM_CPU_CORES && core != -1) { + return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); + } + + // Error out if the input core isn't enabled in the input mask. + if (core < Core::NUM_CPU_CORES && (mask & (1 << core)) == 0) { + return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); + } + + thread->ChangeCore(core, mask); + return RESULT_SUCCESS; } static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions, u32 remote_permissions) { - LOG_TRACE(Kernel_SVC, "called, size=0x%llx, localPerms=0x%08x, remotePerms=0x%08x", size, - local_permissions, remote_permissions); + NGLOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, + local_permissions, remote_permissions); auto sharedMemHandle = SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size, static_cast<MemoryPermission>(local_permissions), @@ -778,7 +789,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss } static ResultCode ClearEvent(Handle handle) { - LOG_TRACE(Kernel_SVC, "called, event=0xX", handle); + NGLOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); SharedPtr<Event> evt = g_handle_table.Get<Event>(handle); if (evt == nullptr) @@ -812,7 +823,7 @@ static const FunctionDef SVC_Table[] = { {0x0B, SvcWrap<SleepThread>, "SleepThread"}, {0x0C, SvcWrap<GetThreadPriority>, "GetThreadPriority"}, {0x0D, SvcWrap<SetThreadPriority>, "SetThreadPriority"}, - {0x0E, nullptr, "GetThreadCoreMask"}, + {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"}, {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, {0x11, nullptr, "SignalEvent"}, @@ -844,14 +855,14 @@ static const FunctionDef SVC_Table[] = { {0x2B, nullptr, "FlushDataCache"}, {0x2C, nullptr, "MapPhysicalMemory"}, {0x2D, nullptr, "UnmapPhysicalMemory"}, - {0x2E, nullptr, "Unknown"}, + {0x2E, nullptr, "GetNextThreadInfo"}, {0x2F, nullptr, "GetLastThreadInfo"}, {0x30, nullptr, "GetResourceLimitLimitValue"}, {0x31, nullptr, "GetResourceLimitCurrentValue"}, - {0x32, nullptr, "SetThreadActivity"}, - {0x33, nullptr, "GetThreadContext"}, - {0x34, nullptr, "Unknown"}, - {0x35, nullptr, "Unknown"}, + {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, + {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, + {0x34, nullptr, "WaitForAddress"}, + {0x35, nullptr, "SignalToAddress"}, {0x36, nullptr, "Unknown"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, @@ -859,7 +870,7 @@ static const FunctionDef SVC_Table[] = { {0x3A, nullptr, "Unknown"}, {0x3B, nullptr, "Unknown"}, {0x3C, nullptr, "DumpInfo"}, - {0x3D, nullptr, "Unknown"}, + {0x3D, nullptr, "DumpInfoNew"}, {0x3E, nullptr, "Unknown"}, {0x3F, nullptr, "Unknown"}, {0x40, nullptr, "CreateSession"}, @@ -870,9 +881,9 @@ static const FunctionDef SVC_Table[] = { {0x45, nullptr, "CreateEvent"}, {0x46, nullptr, "Unknown"}, {0x47, nullptr, "Unknown"}, - {0x48, nullptr, "Unknown"}, - {0x49, nullptr, "Unknown"}, - {0x4A, nullptr, "Unknown"}, + {0x48, nullptr, "AllocateUnsafeMemory"}, + {0x49, nullptr, "FreeUnsafeMemory"}, + {0x4A, nullptr, "SetUnsafeAllocationLimit"}, {0x4B, nullptr, "CreateJitMemory"}, {0x4C, nullptr, "MapJitMemory"}, {0x4D, nullptr, "SleepSystem"}, @@ -909,7 +920,7 @@ static const FunctionDef SVC_Table[] = { {0x6C, nullptr, "SetHardwareBreakPoint"}, {0x6D, nullptr, "GetDebugThreadParam"}, {0x6E, nullptr, "Unknown"}, - {0x6F, nullptr, "Unknown"}, + {0x6F, nullptr, "GetMemoryInfo"}, {0x70, nullptr, "CreatePort"}, {0x71, nullptr, "ManageNamedPort"}, {0x72, nullptr, "ConnectToPort"}, @@ -929,8 +940,8 @@ static const FunctionDef SVC_Table[] = { }; static const FunctionDef* GetSVCInfo(u32 func_num) { - if (func_num >= ARRAY_SIZE(SVC_Table)) { - LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num); + if (func_num >= std::size(SVC_Table)) { + NGLOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num); return nullptr; } return &SVC_Table[func_num]; @@ -949,10 +960,10 @@ void CallSVC(u32 immediate) { if (info->func) { info->func(); } else { - LOG_CRITICAL(Kernel_SVC, "unimplemented SVC function %s(..)", info->name); + NGLOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name); } } else { - LOG_CRITICAL(Kernel_SVC, "unknown SVC function 0x%x", immediate); + NGLOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } } diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index bc471d01e..70148c4fe 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h @@ -47,9 +47,12 @@ enum class GetInfoType : u64 { NewMapRegionSize = 15, // 3.0.0+ IsVirtualAddressMemoryEnabled = 16, + PersonalMmHeapUsage = 17, TitleId = 18, // 4.0.0+ PrivilegedProcessId = 19, + // 5.0.0+ + UserExceptionContextAddr = 20, }; void CallSVC(u32 immediate); diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index b224f5e67..40aa88cc1 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -13,14 +13,14 @@ namespace Kernel { -#define PARAM(n) Core::CPU().GetReg(n) +#define PARAM(n) Core::CurrentArmInterface().GetReg(n) /** * HLE a function return from the current ARM userland process * @param res Result to return */ static inline void FuncReturn(u64 res) { - Core::CPU().SetReg(0, res); + Core::CurrentArmInterface().SetReg(0, res); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -45,7 +45,7 @@ template <ResultCode func(u32*, u32)> void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, (u32)PARAM(1)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -53,7 +53,7 @@ template <ResultCode func(u32*, u64)> void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -66,10 +66,30 @@ template <ResultCode func(u64*, u64)> void SvcWrap() { u64 param_1 = 0; u32 retval = func(¶m_1, PARAM(1)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } +template <ResultCode func(u32, u64)> +void SvcWrap() { + FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), PARAM(1)).raw); +} + +template <ResultCode func(u32, u32, u64)> +void SvcWrap() { + FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), (u32)(PARAM(1) & 0xFFFFFFFF), PARAM(2)).raw); +} + +template <ResultCode func(u32, u32*, u64*)> +void SvcWrap() { + u32 param_1 = 0; + u64 param_2 = 0; + ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), ¶m_1, ¶m_2); + Core::CurrentArmInterface().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(2, param_2); + FuncReturn(retval.raw); +} + template <ResultCode func(u64, u64, u32, u32)> void SvcWrap() { FuncReturn( @@ -100,7 +120,7 @@ template <ResultCode func(u32*, u64, u64, s64)> void SvcWrap() { u32 param_1 = 0; ResultCode retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)); - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval.raw); } @@ -113,7 +133,7 @@ template <ResultCode func(u64*, u64, u64, u64)> void SvcWrap() { u64 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -123,7 +143,7 @@ void SvcWrap() { u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), (u32)PARAM(4), (s32)(PARAM(5) & 0xFFFFFFFF)) .raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -146,7 +166,7 @@ template <ResultCode func(u32*, u64, u64, u32)> void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -155,7 +175,7 @@ void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index dd0a8ae48..cffa7ca83 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -55,16 +55,6 @@ inline static u32 const NewThreadId() { Thread::Thread() {} Thread::~Thread() {} -/** - * Check if the specified thread is waiting on the specified address to be arbitrated - * @param thread The thread to test - * @param wait_address The address to test against - * @return True if the thread is waiting, false otherwise - */ -static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { - return thread->status == THREADSTATUS_WAIT_ARB && wait_address == thread->wait_address; -} - void Thread::Stop() { // Cancel any outstanding wakeup events for this thread CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); @@ -74,7 +64,7 @@ void Thread::Stop() { // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) if (status == THREADSTATUS_READY) { - Core::System::GetInstance().Scheduler().UnscheduleThread(this, current_priority); + scheduler->UnscheduleThread(this, current_priority); } status = THREADSTATUS_DEAD; @@ -87,14 +77,11 @@ void Thread::Stop() { } wait_objects.clear(); - // Release all the mutexes that this thread holds - ReleaseThreadMutexes(this); - // Mark the TLS slot in the thread's page as free. u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; u64 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; - Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); + Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot); } void WaitCurrentThread_Sleep() { @@ -102,16 +89,10 @@ void WaitCurrentThread_Sleep() { thread->status = THREADSTATUS_WAIT_SLEEP; } -void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { - Thread* thread = GetCurrentThread(); - thread->wait_address = wait_address; - thread->status = THREADSTATUS_WAIT_ARB; -} - void ExitCurrentThread() { Thread* thread = GetCurrentThread(); thread->Stop(); - Core::System::GetInstance().Scheduler().RemoveThread(thread); + Core::System::GetInstance().CurrentScheduler().RemoveThread(thread); } /** @@ -120,16 +101,18 @@ void ExitCurrentThread() { * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time */ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { - SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle); + const auto proper_handle = static_cast<Handle>(thread_handle); + SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle); if (thread == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid thread %08X", (Handle)thread_handle); + NGLOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); return; } bool resume = true; if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || - thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { + thread->status == THREADSTATUS_WAIT_SYNCH_ALL || + thread->status == THREADSTATUS_WAIT_HLE_EVENT) { // Remove the thread from each of its waiting objects' waitlists for (auto& object : thread->wait_objects) @@ -141,6 +124,22 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0); } + if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 || + thread->wait_handle) { + ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX); + thread->mutex_wait_address = 0; + thread->condvar_wait_address = 0; + thread->wait_handle = 0; + + auto lock_owner = thread->lock_owner; + // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance + // and don't have a lock owner unless SignalProcessWideKey was called first and the thread + // wasn't awakened due to the mutex already being acquired. + if (lock_owner) { + lock_owner->RemoveMutexWaiter(thread); + } + } + if (resume) thread->ResumeFromWait(); } @@ -150,22 +149,36 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { if (nanoseconds == -1) return; - CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, callback_handle); + CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType, + callback_handle); } void Thread::CancelWakeupTimer() { CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); } +static boost::optional<s32> GetNextProcessorId(u64 mask) { + for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { + if (mask & (1ULL << index)) { + if (!Core::System().GetInstance().Scheduler(index)->GetCurrentThread()) { + // Core is enabled and not running any threads, use this one + return index; + } + } + } + return {}; +} + void Thread::ResumeFromWait() { ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); switch (status) { case THREADSTATUS_WAIT_SYNCH_ALL: case THREADSTATUS_WAIT_SYNCH_ANY: - case THREADSTATUS_WAIT_ARB: + case THREADSTATUS_WAIT_HLE_EVENT: case THREADSTATUS_WAIT_SLEEP: case THREADSTATUS_WAIT_IPC: + case THREADSTATUS_WAIT_MUTEX: break; case THREADSTATUS_READY: @@ -178,11 +191,11 @@ void Thread::ResumeFromWait() { return; case THREADSTATUS_RUNNING: - DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); + DEBUG_ASSERT_MSG(false, "Thread with object id {} has already resumed.", GetObjectId()); return; case THREADSTATUS_DEAD: // This should never happen, as threads must complete before being stopped. - DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.", + DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.", GetObjectId()); return; } @@ -190,8 +203,37 @@ void Thread::ResumeFromWait() { wakeup_callback = nullptr; status = THREADSTATUS_READY; - Core::System::GetInstance().Scheduler().ScheduleThread(this, current_priority); - Core::System::GetInstance().PrepareReschedule(); + + boost::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); + if (!new_processor_id) { + new_processor_id = processor_id; + } + if (ideal_core != -1 && + Core::System().GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { + new_processor_id = ideal_core; + } + + ASSERT(*new_processor_id < 4); + + // Add thread to new core's scheduler + auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id); + + if (*new_processor_id != processor_id) { + // Remove thread from previous core's scheduler + scheduler->RemoveThread(this); + next_scheduler->AddThread(this, current_priority); + } + + processor_id = *new_processor_id; + + // If the thread was ready, unschedule from the previous core and schedule on the new core + scheduler->UnscheduleThread(this, current_priority); + next_scheduler->ScheduleThread(this, current_priority); + + // Change thread's scheduler + scheduler = next_scheduler; + + Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); } /** @@ -242,27 +284,25 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, SharedPtr<Process> owner_process) { // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > THREADPRIO_LOWEST) { - LOG_ERROR(Kernel_SVC, "Invalid thread priority: %u", priority); + NGLOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); return ERR_OUT_OF_RANGE; } if (processor_id > THREADPROCESSORID_MAX) { - LOG_ERROR(Kernel_SVC, "Invalid processor id: %d", processor_id); + NGLOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); return ERR_OUT_OF_RANGE_KERNEL; } // TODO(yuriks): Other checks, returning 0xD9001BEA if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { - LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %016" PRIx64, name.c_str(), entry_point); + NGLOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); // TODO (bunnei): Find the correct error code to use here return ResultCode(-1); } SharedPtr<Thread> thread(new Thread); - Core::System::GetInstance().Scheduler().AddThread(thread, priority); - thread->thread_id = NewThreadId(); thread->status = THREADSTATUS_DORMANT; thread->entry_point = entry_point; @@ -270,11 +310,17 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->nominal_priority = thread->current_priority = priority; thread->last_running_ticks = CoreTiming::GetTicks(); thread->processor_id = processor_id; + thread->ideal_core = processor_id; + thread->affinity_mask = 1ULL << processor_id; thread->wait_objects.clear(); - thread->wait_address = 0; + thread->mutex_wait_address = 0; + thread->condvar_wait_address = 0; + thread->wait_handle = 0; thread->name = std::move(name); thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); thread->owner_process = owner_process; + thread->scheduler = Core::System().GetInstance().Scheduler(processor_id); + thread->scheduler->AddThread(thread, priority); // Find the next available TLS index, and mark it as used auto& tls_slots = owner_process->tls_slots; @@ -291,8 +337,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, auto& linheap_memory = memory_region->linear_heap_memory; if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { - LOG_ERROR(Kernel_SVC, - "Not enough space in region to allocate a new TLS page for thread"); + NGLOG_ERROR(Kernel_SVC, + "Not enough space in region to allocate a new TLS page for thread"); return ERR_OUT_OF_MEMORY; } @@ -314,7 +360,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, // TODO(Subv): Find the correct MemoryState for this region. vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, linheap_memory, offset, Memory::PAGE_SIZE, - MemoryState::ThreadLocalStorage); + MemoryState::ThreadLocal); } // Mark the slot as used @@ -332,32 +378,23 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, void Thread::SetPriority(u32 priority) { ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, "Invalid priority value."); - Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); - nominal_priority = current_priority = priority; -} - -void Thread::UpdatePriority() { - u32 best_priority = nominal_priority; - for (auto& mutex : held_mutexes) { - if (mutex->priority < best_priority) - best_priority = mutex->priority; - } - BoostPriority(best_priority); + nominal_priority = priority; + UpdatePriority(); } void Thread::BoostPriority(u32 priority) { - Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); + scheduler->SetThreadPriority(this, priority); current_priority = priority; } SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, SharedPtr<Process> owner_process) { // Setup page table so we can write to memory - SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); + SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); // Initialize new "main" thread auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, - Memory::HEAP_VADDR_END, owner_process); + Memory::STACK_AREA_VADDR_END, owner_process); SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); @@ -392,13 +429,86 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + CommandHeaderOffset; } +void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { + thread->lock_owner = this; + wait_mutex_threads.emplace_back(std::move(thread)); + UpdatePriority(); +} + +void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) { + boost::remove_erase(wait_mutex_threads, thread); + thread->lock_owner = nullptr; + UpdatePriority(); +} + +void Thread::UpdatePriority() { + // Find the highest priority among all the threads that are waiting for this thread's lock + u32 new_priority = nominal_priority; + for (const auto& thread : wait_mutex_threads) { + if (thread->nominal_priority < new_priority) + new_priority = thread->nominal_priority; + } + + if (new_priority == current_priority) + return; + + scheduler->SetThreadPriority(this, new_priority); + + current_priority = new_priority; + + // Recursively update the priority of the thread that depends on the priority of this one. + if (lock_owner) + lock_owner->UpdatePriority(); +} + +void Thread::ChangeCore(u32 core, u64 mask) { + ideal_core = core; + affinity_mask = mask; + + if (status != THREADSTATUS_READY) { + return; + } + + boost::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; + + if (!new_processor_id) { + new_processor_id = processor_id; + } + if (ideal_core != -1 && + Core::System().GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { + new_processor_id = ideal_core; + } + + ASSERT(*new_processor_id < 4); + + // Add thread to new core's scheduler + auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id); + + if (*new_processor_id != processor_id) { + // Remove thread from previous core's scheduler + scheduler->RemoveThread(this); + next_scheduler->AddThread(this, current_priority); + } + + processor_id = *new_processor_id; + + // If the thread was ready, unschedule from the previous core and schedule on the new core + scheduler->UnscheduleThread(this, current_priority); + next_scheduler->ScheduleThread(this, current_priority); + + // Change thread's scheduler + scheduler = next_scheduler; + + Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the current thread */ Thread* GetCurrentThread() { - return Core::System::GetInstance().Scheduler().GetCurrentThread(); + return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); } void ThreadingInit() { @@ -406,6 +516,8 @@ void ThreadingInit() { next_thread_id = 1; } -void ThreadingShutdown() {} +void ThreadingShutdown() { + Kernel::ClearProcessList(); +} } // namespace Kernel diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 4fd2fc2f8..1d2da6d50 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -4,6 +4,7 @@ #pragma once +#include <memory> #include <string> #include <unordered_map> #include <vector> @@ -18,7 +19,7 @@ enum ThreadPriority : u32 { THREADPRIO_HIGHEST = 0, ///< Highest thread priority THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps - THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps + THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps THREADPRIO_LOWEST = 63, ///< Lowest thread priority }; @@ -38,11 +39,12 @@ enum ThreadProcessorId : s32 { enum ThreadStatus { THREADSTATUS_RUNNING, ///< Currently running THREADSTATUS_READY, ///< Ready to run - THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter + THREADSTATUS_WAIT_HLE_EVENT, ///< Waiting for hle event to finish THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true + THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc THREADSTATUS_DORMANT, ///< Created but not yet made ready THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated }; @@ -54,8 +56,8 @@ enum class ThreadWakeupReason { namespace Kernel { -class Mutex; class Process; +class Scheduler; class Thread final : public WaitObject { public: @@ -104,17 +106,23 @@ public: void SetPriority(u32 priority); /** - * Boost's a thread's priority to the best priority among the thread's held mutexes. - * This prevents priority inversion via priority inheritance. - */ - void UpdatePriority(); - - /** * Temporarily boosts the thread's priority until the next time it is scheduled * @param priority The new priority */ void BoostPriority(u32 priority); + /// Adds a thread to the list of threads that are waiting for a lock held by this thread. + void AddMutexWaiter(SharedPtr<Thread> thread); + + /// Removes a thread from the list of threads that are waiting for a lock held by this thread. + void RemoveMutexWaiter(SharedPtr<Thread> thread); + + /// Recalculates the current priority taking into account priority inheritance. + void UpdatePriority(); + + /// Changes the core that the thread is running or scheduled to run on. + void ChangeCore(u32 core, u64 mask); + /** * Gets the thread's thread ID * @return The thread's ID @@ -205,19 +213,22 @@ public: VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread - /// Mutexes currently held by this thread, which will be released when it exits. - boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; - - /// Mutexes that this thread is currently waiting for. - boost::container::flat_set<SharedPtr<Mutex>> pending_mutexes; - SharedPtr<Process> owner_process; ///< Process that owns this thread /// Objects that the thread is waiting on, in the same order as they were // passed to WaitSynchronization1/N. std::vector<SharedPtr<WaitObject>> wait_objects; - VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address + /// List of threads that are waiting for a mutex that is held by this thread. + std::vector<SharedPtr<Thread>> wait_mutex_threads; + + /// Thread that owns the lock that this thread is waiting for. + SharedPtr<Thread> lock_owner; + + // If waiting on a ConditionVariable, this is the ConditionVariable address + VAddr condvar_wait_address; + VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address + Handle wait_handle; ///< The handle used to wait for the mutex. std::string name; @@ -234,6 +245,11 @@ public: // available. In case of a timeout, the object will be nullptr. std::function<WakeupCallback> wakeup_callback; + std::shared_ptr<Scheduler> scheduler; + + u32 ideal_core{0xFFFFFFFF}; + u64 affinity_mask{0x1}; + private: Thread(); ~Thread() override; diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 8da745634..661356a97 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -57,7 +57,8 @@ void Timer::Set(s64 initial, s64 interval) { // Immediately invoke the callback Signal(0); } else { - CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_handle); + CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), timer_callback_event_type, + callback_handle); } } @@ -77,7 +78,7 @@ void Timer::WakeupAllWaitingThreads() { } void Timer::Signal(int cycles_late) { - LOG_TRACE(Kernel, "Timer %u fired", GetObjectId()); + NGLOG_TRACE(Kernel, "Timer {} fired", GetObjectId()); signaled = true; @@ -86,7 +87,7 @@ void Timer::Signal(int cycles_late) { if (interval_delay != 0) { // Reschedule the timer with the interval delay - CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late, + CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(interval_delay) - cycles_late, timer_callback_event_type, callback_handle); } } @@ -97,7 +98,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle)); if (timer == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle); + NGLOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle); return; } diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index d5b36d71a..676e5b282 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <cinttypes> #include <iterator> #include "common/assert.h" #include "common/logging/log.h" @@ -18,8 +17,26 @@ namespace Kernel { static const char* GetMemoryStateName(MemoryState state) { static const char* names[] = { - "Free", "Reserved", "IO", "Static", "Code", "Private", - "Shared", "Continuous", "Aliased", "Alias", "AliasCode", "Locked", + "Unmapped", + "Io", + "Normal", + "CodeStatic", + "CodeMutable", + "Heap", + "Shared", + "Unknown1" + "ModuleCodeStatic", + "ModuleCodeMutable", + "IpcBuffer0", + "Mapped", + "ThreadLocal", + "TransferMemoryIsolated", + "TransferMemory", + "ProcessMemory", + "Unknown2" + "IpcBuffer1", + "IpcBuffer3", + "KernelStack", }; return names[(int)state]; @@ -87,8 +104,15 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, VirtualMemoryArea& final_vma = vma_handle->second; ASSERT(final_vma.size == size); - Core::CPU().MapBackingMemory(target, size, block->data() + offset, - VMAPermission::ReadWriteExecute); + auto& system = Core::System::GetInstance(); + system.ArmInterface(0).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); + system.ArmInterface(1).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); + system.ArmInterface(2).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); + system.ArmInterface(3).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); final_vma.type = VMAType::AllocatedMemoryBlock; final_vma.permissions = VMAPermission::ReadWrite; @@ -109,7 +133,11 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me VirtualMemoryArea& final_vma = vma_handle->second; ASSERT(final_vma.size == size); - Core::CPU().MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + auto& system = Core::System::GetInstance(); + system.ArmInterface(0).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + system.ArmInterface(1).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + system.ArmInterface(2).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + system.ArmInterface(3).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); final_vma.type = VMAType::BackingMemory; final_vma.permissions = VMAPermission::ReadWrite; @@ -142,7 +170,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) { VirtualMemoryArea& vma = vma_handle->second; vma.type = VMAType::Free; vma.permissions = VMAPermission::None; - vma.meminfo_state = MemoryState::Free; + vma.meminfo_state = MemoryState::Unmapped; vma.backing_block = nullptr; vma.offset = 0; @@ -166,6 +194,13 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) { } ASSERT(FindVMA(target)->second.size >= size); + + auto& system = Core::System::GetInstance(); + system.ArmInterface(0).UnmapMemory(target, size); + system.ArmInterface(1).UnmapMemory(target, size); + system.ArmInterface(2).UnmapMemory(target, size); + system.ArmInterface(3).UnmapMemory(target, size); + return RESULT_SUCCESS; } @@ -204,11 +239,10 @@ void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { } } -void VMManager::LogLayout(Log::Level log_level) const { +void VMManager::LogLayout() const { for (const auto& p : vma_map) { const VirtualMemoryArea& vma = p.second; - LOG_GENERIC(Log::Class::Kernel, log_level, - "%016" PRIx64 " - %016" PRIx64 " size: %16" PRIx64 " %c%c%c %s", vma.base, + NGLOG_DEBUG(Kernel, "{:016X} - {:016X} size: {:016X} {}{}{} {}", vma.base, vma.base + vma.size, vma.size, (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', @@ -224,8 +258,8 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) { } ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u64 size) { - ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%16" PRIx64, size); - ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%016" PRIx64, base); + ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x{:016X}", size); + ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x{:016X}", base); VMAIter vma_handle = StripIterConstness(FindVMA(base)); if (vma_handle == vma_map.end()) { @@ -260,8 +294,8 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u64 size) { } ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) { - ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%16" PRIx64, size); - ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%016" PRIx64, target); + ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x{:016X}", size); + ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x{:016X}", target); VAddr target_end = target + size; ASSERT(target_end >= target); @@ -358,38 +392,23 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { } u64 VMManager::GetTotalMemoryUsage() { - LOG_WARNING(Kernel, "(STUBBED) called"); - return 0xBE000000; + NGLOG_WARNING(Kernel, "(STUBBED) called"); + return 0xF8000000; } u64 VMManager::GetTotalHeapUsage() { - LOG_WARNING(Kernel, "(STUBBED) called"); + NGLOG_WARNING(Kernel, "(STUBBED) called"); return 0x0; } VAddr VMManager::GetAddressSpaceBaseAddr() { - LOG_WARNING(Kernel, "(STUBBED) called"); + NGLOG_WARNING(Kernel, "(STUBBED) called"); return 0x8000000; } u64 VMManager::GetAddressSpaceSize() { - LOG_WARNING(Kernel, "(STUBBED) called"); + NGLOG_WARNING(Kernel, "(STUBBED) called"); return MAX_ADDRESS; } -VAddr VMManager::GetMapRegionBaseAddr() { - LOG_WARNING(Kernel, "(STUBBED) called"); - return Memory::HEAP_VADDR; -} - -VAddr VMManager::GetNewMapRegionBaseAddr() { - LOG_WARNING(Kernel, "(STUBBED) called"); - return 0x8000000; -} - -u64 VMManager::GetNewMapRegionSize() { - LOG_WARNING(Kernel, "(STUBBED) called"); - return 0x8000000; -} - } // namespace Kernel diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 8de704a60..38e4ebcd3 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -41,15 +41,24 @@ enum class VMAPermission : u8 { /// Set of values returned in MemoryInfo.state by svcQueryMemory. enum class MemoryState : u32 { - Free = 0, - IO = 1, - Normal = 2, - Code = 3, - Static = 4, - Heap = 5, - Shared = 6, - Mapped = 6, - ThreadLocalStorage = 12, + Unmapped = 0x0, + Io = 0x1, + Normal = 0x2, + CodeStatic = 0x3, + CodeMutable = 0x4, + Heap = 0x5, + Shared = 0x6, + ModuleCodeStatic = 0x8, + ModuleCodeMutable = 0x9, + IpcBuffer0 = 0xA, + Mapped = 0xB, + ThreadLocal = 0xC, + TransferMemoryIsolated = 0xD, + TransferMemory = 0xE, + ProcessMemory = 0xF, + IpcBuffer1 = 0x11, + IpcBuffer3 = 0x12, + KernelStack = 0x13, }; /** @@ -66,7 +75,7 @@ struct VirtualMemoryArea { VMAType type = VMAType::Free; VMAPermission permissions = VMAPermission::None; /// Tag returned by svcQueryMemory. Not otherwise used. - MemoryState meminfo_state = MemoryState::Free; + MemoryState meminfo_state = MemoryState::Unmapped; // Settings for type = AllocatedMemoryBlock /// Memory block backing this VMA. @@ -178,7 +187,7 @@ public: void RefreshMemoryBlockMappings(const std::vector<u8>* block); /// Dumps the address space layout to the log, for debugging - void LogLayout(Log::Level log_level) const; + void LogLayout() const; /// Gets the total memory usage, used by svcGetInfo u64 GetTotalMemoryUsage(); @@ -192,15 +201,6 @@ public: /// Gets the total address space address size, used by svcGetInfo u64 GetAddressSpaceSize(); - /// Gets the map region base address, used by svcGetInfo - VAddr GetMapRegionBaseAddr(); - - /// Gets the base address for a new memory region, used by svcGetInfo - VAddr GetNewMapRegionBaseAddr(); - - /// Gets the size for a new memory region, used by svcGetInfo - u64 GetNewMapRegionSize(); - /// Each VMManager has its own page table, which is set as the main one when the owning process /// is scheduled. Memory::PageTable page_table; diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index ec147b84c..b08ac72c1 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -39,7 +39,8 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { for (const auto& thread : waiting_threads) { // The list of waiting threads must not contain threads that are not waiting to be awakened. ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || - thread->status == THREADSTATUS_WAIT_SYNCH_ALL, + thread->status == THREADSTATUS_WAIT_SYNCH_ALL || + thread->status == THREADSTATUS_WAIT_HLE_EVENT, "Inconsistent thread statuses in waiting_threads"); if (thread->current_priority >= candidate_priority) diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 656e1b4a7..3ebf7aadf 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -32,7 +32,8 @@ enum class ErrorModule : u32 { Common = 0, Kernel = 1, FS = 2, - NvidiaTransferMemory = 3, + OS = 3, // used for Memory, Thread, Mutex, Nvidia + HTCS = 4, NCM = 5, DD = 6, LR = 8, @@ -42,41 +43,80 @@ enum class ErrorModule : u32 { PM = 15, NS = 16, HTC = 18, + NCMContent = 20, SM = 21, RO = 22, SDMMC = 24, + OVLN = 25, SPL = 26, ETHC = 100, I2C = 101, + GPIO = 102, + UART = 103, Settings = 105, + WLAN = 107, + XCD = 108, NIFM = 110, - Display = 114, - NTC = 116, + Hwopus = 111, + Bluetooth = 113, + VI = 114, + NFP = 115, + Time = 116, FGM = 117, - PCIE = 120, + OE = 118, + PCIe = 120, Friends = 121, + BCAT = 122, SSL = 123, Account = 124, + News = 125, Mii = 126, + NFC = 127, AM = 128, PlayReport = 129, + AHID = 130, + Qlaunch = 132, PCV = 133, OMM = 134, + BPC = 135, + PSM = 136, NIM = 137, PSC = 138, + TC = 139, USB = 140, + NSD = 141, + PCTL = 142, BTM = 143, + ETicket = 145, + NGC = 146, ERPT = 147, APM = 148, + Profiler = 150, + ErrorUpload = 151, + Audio = 153, NPNS = 154, + NPNSHTTPSTREAM = 155, ARP = 157, - BOOT = 158, - NFC = 161, + SWKBD = 158, + BOOT = 159, + NFCMifare = 161, UserlandAssert = 162, + Fatal = 163, + NIMShop = 164, + SPSM = 165, + BGTC = 167, UserlandCrash = 168, - HID = 203, + SREPO = 180, + Dauth = 181, + HID = 202, + LDN = 203, + Irsensor = 205, Capture = 206, - TC = 651, + Manu = 208, + ATK = 209, + GRC = 212, + Migration = 216, + MigrationLdcServ = 217, GeneralWebApplet = 800, WifiWebAuthApplet = 809, WhitelistedApplet = 810, @@ -108,11 +148,11 @@ union ResultCode { } constexpr bool IsSuccess() const { - return is_error.ExtractValue(raw) == 0; + return raw == 0; } constexpr bool IsError() const { - return is_error.ExtractValue(raw) == 1; + return raw != 0; } }; @@ -200,6 +240,9 @@ public: } ResultVal& operator=(const ResultVal& o) { + if (this == &o) { + return *this; + } if (!empty()) { if (!o.empty()) { object = o.object; diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 5716577d6..f2fffa760 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -2,15 +2,149 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/service/acc/acc.h" +#include "core/hle/service/acc/acc_aa.h" +#include "core/hle/service/acc/acc_su.h" #include "core/hle/service/acc/acc_u0.h" +#include "core/hle/service/acc/acc_u1.h" -namespace Service { -namespace Account { +namespace Service::Account { + +// TODO: RE this structure +struct UserData { + INSERT_PADDING_WORDS(1); + u32 icon_id; + u8 bg_color_id; + INSERT_PADDING_BYTES(0x7); + INSERT_PADDING_BYTES(0x10); + INSERT_PADDING_BYTES(0x60); +}; +static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); + +struct ProfileBase { + u8 user_id[0x10]; + u64 timestamp; + u8 username[0x20]; +}; +static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase structure has incorrect size"); + +using Uid = std::array<u64, 2>; +static constexpr Uid DEFAULT_USER_ID{0x10ull, 0x20ull}; + +class IProfile final : public ServiceFramework<IProfile> { +public: + IProfile() : ServiceFramework("IProfile") { + static const FunctionInfo functions[] = { + {0, nullptr, "Get"}, + {1, &IProfile::GetBase, "GetBase"}, + {10, nullptr, "GetImageSize"}, + {11, nullptr, "LoadImage"}, + }; + RegisterHandlers(functions); + } + +private: + void GetBase(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + ProfileBase profile_base{}; + IPC::ResponseBuilder rb{ctx, 16}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw(profile_base); + } +}; + +class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { +public: + IManagerForApplication() : ServiceFramework("IManagerForApplication") { + static const FunctionInfo functions[] = { + {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, + {1, &IManagerForApplication::GetAccountId, "GetAccountId"}, + {2, nullptr, "EnsureIdTokenCacheAsync"}, + {3, nullptr, "LoadIdTokenCache"}, + {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"}, + {150, nullptr, "CreateAuthorizationRequest"}, + {160, nullptr, "StoreOpenContext"}, + }; + RegisterHandlers(functions); + } + +private: + void CheckAvailability(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(true); // TODO: Check when this is supposed to return true and when not + } + + void GetAccountId(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(0x12345678ABCDEF); + } +}; + +void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(true); // TODO: Check when this is supposed to return true and when not +} + +void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; + ctx.WriteBuffer(user_ids.data(), user_ids.size()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; + ctx.WriteBuffer(user_ids.data(), user_ids.size()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IProfile>(); + NGLOG_DEBUG(Service_ACC, "called"); +} + +void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IManagerForApplication>(); + NGLOG_DEBUG(Service_ACC, "called"); +} + +void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw(DEFAULT_USER_ID); +} + +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) + : ServiceFramework(name), module(std::move(module)) {} void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<ACC_U0>()->InstallAsService(service_manager); + auto module = std::make_shared<Module>(); + std::make_shared<ACC_AA>(module)->InstallAsService(service_manager); + std::make_shared<ACC_SU>(module)->InstallAsService(service_manager); + std::make_shared<ACC_U0>(module)->InstallAsService(service_manager); + std::make_shared<ACC_U1>(module)->InstallAsService(service_manager); } -} // namespace Account -} // namespace Service +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 44d024f48..58f8d260c 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -6,11 +6,28 @@ #include "core/hle/service/service.h" -namespace Service { -namespace Account { +namespace Service::Account { + +class Module final { +public: + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name); + + void GetUserExistence(Kernel::HLERequestContext& ctx); + void ListAllUsers(Kernel::HLERequestContext& ctx); + void ListOpenUsers(Kernel::HLERequestContext& ctx); + void GetLastOpenedUser(Kernel::HLERequestContext& ctx); + void GetProfile(Kernel::HLERequestContext& ctx); + void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); + void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + }; +}; /// Registers all ACC services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace Account -} // namespace Service +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp new file mode 100644 index 000000000..280b3e464 --- /dev/null +++ b/src/core/hle/service/acc/acc_aa.cpp @@ -0,0 +1,20 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/acc/acc_aa.h" + +namespace Service::Account { + +ACC_AA::ACC_AA(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:aa") { + static const FunctionInfo functions[] = { + {0, nullptr, "EnsureCacheAsync"}, + {1, nullptr, "LoadCache"}, + {2, nullptr, "GetDeviceAccountId"}, + {50, nullptr, "RegisterNotificationTokenAsync"}, + {51, nullptr, "UnregisterNotificationTokenAsync"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_aa.h b/src/core/hle/service/acc/acc_aa.h new file mode 100644 index 000000000..796f7ef85 --- /dev/null +++ b/src/core/hle/service/acc/acc_aa.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/acc/acc.h" + +namespace Service::Account { + +class ACC_AA final : public Module::Interface { +public: + explicit ACC_AA(std::shared_ptr<Module> module); +}; + +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp new file mode 100644 index 000000000..9ffb40b22 --- /dev/null +++ b/src/core/hle/service/acc/acc_su.cpp @@ -0,0 +1,53 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/acc/acc_su.h" + +namespace Service::Account { + +ACC_SU::ACC_SU(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:su") { + static const FunctionInfo functions[] = { + {0, nullptr, "GetUserCount"}, + {1, &ACC_SU::GetUserExistence, "GetUserExistence"}, + {2, &ACC_SU::ListAllUsers, "ListAllUsers"}, + {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"}, + {4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"}, + {5, &ACC_SU::GetProfile, "GetProfile"}, + {6, nullptr, "GetProfileDigest"}, + {50, nullptr, "IsUserRegistrationRequestPermitted"}, + {51, nullptr, "TrySelectUserWithoutInteraction"}, + {60, nullptr, "ListOpenContextStoredUsers"}, + {100, nullptr, "GetUserRegistrationNotifier"}, + {101, nullptr, "GetUserStateChangeNotifier"}, + {102, nullptr, "GetBaasAccountManagerForSystemService"}, + {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, + {104, nullptr, "GetProfileUpdateNotifier"}, + {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, + {110, nullptr, "StoreSaveDataThumbnail"}, + {111, nullptr, "ClearSaveDataThumbnail"}, + {112, nullptr, "LoadSaveDataThumbnail"}, + {113, nullptr, "GetSaveDataThumbnailExistence"}, + {190, nullptr, "GetUserLastOpenedApplication"}, + {191, nullptr, "ActivateOpenContextHolder"}, + {200, nullptr, "BeginUserRegistration"}, + {201, nullptr, "CompleteUserRegistration"}, + {202, nullptr, "CancelUserRegistration"}, + {203, nullptr, "DeleteUser"}, + {204, nullptr, "SetUserPosition"}, + {205, nullptr, "GetProfileEditor"}, + {206, nullptr, "CompleteUserRegistrationForcibly"}, + {210, nullptr, "CreateFloatingRegistrationRequest"}, + {230, nullptr, "AuthenticateServiceAsync"}, + {250, nullptr, "GetBaasAccountAdministrator"}, + {290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"}, + {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"}, + {299, nullptr, "SuspendBackgroundDaemon"}, + {997, nullptr, "DebugInvalidateTokenCacheForUser"}, + {998, nullptr, "DebugSetUserStateClose"}, + {999, nullptr, "DebugSetUserStateOpen"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_su.h b/src/core/hle/service/acc/acc_su.h new file mode 100644 index 000000000..3894a6991 --- /dev/null +++ b/src/core/hle/service/acc/acc_su.h @@ -0,0 +1,18 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/acc/acc.h" + +namespace Service { +namespace Account { + +class ACC_SU final : public Module::Interface { +public: + explicit ACC_SU(std::shared_ptr<Module> module); +}; + +} // namespace Account +} // namespace Service diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 52c3491d5..44e21ac09 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -2,123 +2,32 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" #include "core/hle/service/acc/acc_u0.h" -namespace Service { -namespace Account { +namespace Service::Account { -using Uid = std::array<u64, 2>; -static constexpr Uid DEFAULT_USER_ID{0x10ull, 0x20ull}; - -class IProfile final : public ServiceFramework<IProfile> { -public: - IProfile() : ServiceFramework("IProfile") { - static const FunctionInfo functions[] = { - {1, &IProfile::GetBase, "GetBase"}, - }; - RegisterHandlers(functions); - } - -private: - void GetBase(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - ProfileBase profile_base{}; - IPC::ResponseBuilder rb{ctx, 16}; - rb.Push(RESULT_SUCCESS); - rb.PushRaw(profile_base); - } -}; - -class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { -public: - IManagerForApplication() : ServiceFramework("IManagerForApplication") { - static const FunctionInfo functions[] = { - {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, - {1, &IManagerForApplication::GetAccountId, "GetAccountId"}, - }; - RegisterHandlers(functions); - } - -private: - void CheckAvailability(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push(true); // TODO: Check when this is supposed to return true and when not - } - - void GetAccountId(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.Push<u64>(0x12345678ABCDEF); - } -}; - -void ACC_U0::GetUserExistence(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push(true); // TODO: Check when this is supposed to return true and when not -} - -void ACC_U0::ListAllUsers(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; - ctx.WriteBuffer(user_ids.data(), user_ids.size()); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void ACC_U0::ListOpenUsers(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; - ctx.WriteBuffer(user_ids.data(), user_ids.size()); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IProfile>(); - LOG_DEBUG(Service_ACC, "called"); -} - -void ACC_U0::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void ACC_U0::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IManagerForApplication>(); - LOG_DEBUG(Service_ACC, "called"); -} - -void ACC_U0::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(RESULT_SUCCESS); - rb.PushRaw(DEFAULT_USER_ID); -} - -ACC_U0::ACC_U0() : ServiceFramework("acc:u0") { +ACC_U0::ACC_U0(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u0") { static const FunctionInfo functions[] = { + {0, nullptr, "GetUserCount"}, {1, &ACC_U0::GetUserExistence, "GetUserExistence"}, {2, &ACC_U0::ListAllUsers, "ListAllUsers"}, {3, &ACC_U0::ListOpenUsers, "ListOpenUsers"}, {4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"}, {5, &ACC_U0::GetProfile, "GetProfile"}, + {6, nullptr, "GetProfileDigest"}, + {50, nullptr, "IsUserRegistrationRequestPermitted"}, + {51, nullptr, "TrySelectUserWithoutInteraction"}, + {60, nullptr, "ListOpenContextStoredUsers"}, {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, + {102, nullptr, "AuthenticateApplicationAsync"}, + {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, + {110, nullptr, "StoreSaveDataThumbnail"}, + {111, nullptr, "ClearSaveDataThumbnail"}, + {120, nullptr, "CreateGuestLoginRequest"}, + {130, nullptr, "LoadOpenContext"}, }; RegisterHandlers(functions); } -} // namespace Account -} // namespace Service +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h index 222f37282..6ded596b3 100644 --- a/src/core/hle/service/acc/acc_u0.h +++ b/src/core/hle/service/acc/acc_u0.h @@ -4,37 +4,13 @@ #pragma once -#include "core/hle/service/service.h" +#include "core/hle/service/acc/acc.h" -namespace Service { -namespace Account { +namespace Service::Account { -// TODO: RE this structure -struct UserData { - INSERT_PADDING_BYTES(0x80); -}; -static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); - -// TODO: RE this structure -struct ProfileBase { - INSERT_PADDING_BYTES(0x38); -}; -static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase structure has incorrect size"); - -class ACC_U0 final : public ServiceFramework<ACC_U0> { +class ACC_U0 final : public Module::Interface { public: - ACC_U0(); - ~ACC_U0() = default; - -private: - void GetUserExistence(Kernel::HLERequestContext& ctx); - void ListAllUsers(Kernel::HLERequestContext& ctx); - void ListOpenUsers(Kernel::HLERequestContext& ctx); - void GetLastOpenedUser(Kernel::HLERequestContext& ctx); - void GetProfile(Kernel::HLERequestContext& ctx); - void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); - void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx); + explicit ACC_U0(std::shared_ptr<Module> module); }; -} // namespace Account -} // namespace Service +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp new file mode 100644 index 000000000..d101d4e0d --- /dev/null +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -0,0 +1,40 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/acc/acc_u1.h" + +namespace Service::Account { + +ACC_U1::ACC_U1(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u1") { + static const FunctionInfo functions[] = { + {0, nullptr, "GetUserCount"}, + {1, &ACC_U1::GetUserExistence, "GetUserExistence"}, + {2, &ACC_U1::ListAllUsers, "ListAllUsers"}, + {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"}, + {4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"}, + {5, &ACC_U1::GetProfile, "GetProfile"}, + {6, nullptr, "GetProfileDigest"}, + {50, nullptr, "IsUserRegistrationRequestPermitted"}, + {51, nullptr, "TrySelectUserWithoutInteraction"}, + {60, nullptr, "ListOpenContextStoredUsers"}, + {100, nullptr, "GetUserRegistrationNotifier"}, + {101, nullptr, "GetUserStateChangeNotifier"}, + {102, nullptr, "GetBaasAccountManagerForSystemService"}, + {103, nullptr, "GetProfileUpdateNotifier"}, + {104, nullptr, "CheckNetworkServiceAvailabilityAsync"}, + {105, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, + {110, nullptr, "StoreSaveDataThumbnail"}, + {111, nullptr, "ClearSaveDataThumbnail"}, + {112, nullptr, "LoadSaveDataThumbnail"}, + {113, nullptr, "GetSaveDataThumbnailExistence"}, + {190, nullptr, "GetUserLastOpenedApplication"}, + {191, nullptr, "ActivateOpenContextHolder"}, + {997, nullptr, "DebugInvalidateTokenCacheForUser"}, + {998, nullptr, "DebugSetUserStateClose"}, + {999, nullptr, "DebugSetUserStateOpen"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u1.h b/src/core/hle/service/acc/acc_u1.h new file mode 100644 index 000000000..5e3e7659b --- /dev/null +++ b/src/core/hle/service/acc/acc_u1.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/acc/acc.h" + +namespace Service::Account { + +class ACC_U1 final : public Module::Interface { +public: + explicit ACC_U1(std::shared_ptr<Module> module); +}; + +} // namespace Service::Account diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d3a674cf6..b8d6b8d4d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -2,34 +2,42 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cinttypes> +#include <stack> +#include "core/file_sys/filesystem.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/apm/apm.h" +#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/nvflinger/nvflinger.h" +#include "core/hle/service/set/set.h" +#include "core/settings.h" -namespace Service { -namespace AM { +namespace Service::AM { IWindowController::IWindowController() : ServiceFramework("IWindowController") { static const FunctionInfo functions[] = { + {0, nullptr, "CreateWindow"}, {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, + {11, nullptr, "ReleaseForegroundRights"}, + {12, nullptr, "RejectToChangeIntoBackground"}, }; RegisterHandlers(functions); } void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(0); } void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -48,34 +56,70 @@ IAudioController::IAudioController() : ServiceFramework("IAudioController") { } void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push(volume); } void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push(volume); } -IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {} +IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") { + static const FunctionInfo functions[] = { + {0, nullptr, "GetLastForegroundCaptureImage"}, + {1, nullptr, "UpdateLastForegroundCaptureImage"}, + {2, nullptr, "GetLastApplicationCaptureImage"}, + {3, nullptr, "GetCallerAppletCaptureImage"}, + {4, nullptr, "UpdateCallerAppletCaptureImage"}, + {5, nullptr, "GetLastForegroundCaptureImageEx"}, + {6, nullptr, "GetLastApplicationCaptureImageEx"}, + {7, nullptr, "GetCallerAppletCaptureImageEx"}, + {8, nullptr, "TakeScreenShotOfOwnLayer"}, // 2.0.0+ + {9, nullptr, "CopyBetweenCaptureBuffers"}, // 5.0.0+ + {10, nullptr, "AcquireLastApplicationCaptureBuffer"}, + {11, nullptr, "ReleaseLastApplicationCaptureBuffer"}, + {12, nullptr, "AcquireLastForegroundCaptureBuffer"}, + {13, nullptr, "ReleaseLastForegroundCaptureBuffer"}, + {14, nullptr, "AcquireCallerAppletCaptureBuffer"}, + {15, nullptr, "ReleaseCallerAppletCaptureBuffer"}, + {16, nullptr, "AcquireLastApplicationCaptureBufferEx"}, + {17, nullptr, "AcquireLastForegroundCaptureBufferEx"}, + {18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, + // 2.0.0+ + {20, nullptr, "ClearCaptureBuffer"}, + {21, nullptr, "ClearAppletTransitionBuffer"}, + // 4.0.0+ + {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, + {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, + {24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"}, + {25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"}, + {26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"}, + {27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"}, + }; + RegisterHandlers(functions); +} IDebugFunctions::IDebugFunctions() : ServiceFramework("IDebugFunctions") {} ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) { static const FunctionInfo functions[] = { + {0, nullptr, "Exit"}, {1, &ISelfController::LockExit, "LockExit"}, {2, &ISelfController::UnlockExit, "UnlockExit"}, + {3, nullptr, "EnterFatalSection"}, + {4, nullptr, "LeaveFatalSection"}, {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, {11, &ISelfController::SetOperationModeChangedNotification, @@ -84,13 +128,34 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger "SetPerformanceModeChangedNotification"}, {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, + {15, nullptr, "SetScreenShotAppletIdentityInfo"}, {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, + {17, nullptr, "SetControllerFirmwareUpdateSection"}, + {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, + {19, nullptr, "SetScreenShotImageOrientation"}, + {20, nullptr, "SetDesirableKeyboardLayout"}, {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, + {41, nullptr, "IsSystemBufferSharingEnabled"}, + {42, nullptr, "GetSystemSharedLayerHandle"}, + {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, + {51, nullptr, "ApproveToDisplay"}, + {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, + {61, nullptr, "SetMediaPlaybackState"}, + {62, nullptr, "SetIdleTimeDetectionExtension"}, + {63, nullptr, "GetIdleTimeDetectionExtension"}, + {64, nullptr, "SetInputDetectionSourceSet"}, + {65, nullptr, "ReportUserIsActive"}, + {66, nullptr, "GetCurrentIlluminance"}, + {67, nullptr, "IsIlluminanceAvailable"}, + {68, nullptr, "SetAutoSleepDisabled"}, + {69, nullptr, "IsAutoSleepDisabled"}, + {70, nullptr, "ReportMultimediaError"}, + {80, nullptr, "SetWirelessPriorityMode"}, }; RegisterHandlers(functions); launchable_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "ISelfController:LaunchableEvent"); + Kernel::Event::Create(Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); } void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { @@ -109,14 +174,14 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { @@ -127,14 +192,14 @@ void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestCo IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called flag=%u", static_cast<u32>(flag)); + NGLOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); } void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { @@ -145,7 +210,7 @@ void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestCont IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called flag=%u", static_cast<u32>(flag)); + NGLOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); } void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { @@ -158,21 +223,21 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called enabled=%u", static_cast<u32>(enabled)); + NGLOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); } void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { @@ -182,7 +247,7 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(launchable_event); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { @@ -195,16 +260,44 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) rb.Push(RESULT_SUCCESS); rb.Push(layer_id); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); +} + +void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") { static const FunctionInfo functions[] = { {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, + {2, nullptr, "GetThisAppletKind"}, + {3, nullptr, "AllowToEnterSleep"}, + {4, nullptr, "DisallowToEnterSleep"}, {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"}, {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"}, + {7, nullptr, "GetCradleStatus"}, + {8, nullptr, "GetBootMode"}, {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"}, + {10, nullptr, "RequestToAcquireSleepLock"}, + {11, nullptr, "ReleaseSleepLock"}, + {12, nullptr, "ReleaseSleepLockTransiently"}, + {13, nullptr, "GetAcquiredSleepLockEvent"}, + {20, nullptr, "PushToGeneralChannel"}, + {30, nullptr, "GetHomeButtonReaderLockAccessor"}, + {31, nullptr, "GetReaderLockAccessorEx"}, + {40, nullptr, "GetCradleFwVersion"}, + {50, nullptr, "IsVrModeEnabled"}, + {51, nullptr, "SetVrModeEnabled"}, + {52, nullptr, "SwitchLcdBacklight"}, + {55, nullptr, "IsInControllerFirmwareUpdateSection"}, + {60, nullptr, "GetDefaultDisplayResolution"}, + {61, nullptr, "GetDefaultDisplayResolutionChangeEvent"}, + {62, nullptr, "GetHdcpAuthenticationState"}, + {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, }; RegisterHandlers(functions); @@ -218,7 +311,7 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(event); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { @@ -226,7 +319,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push<u32>(15); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { @@ -234,44 +327,128 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push(static_cast<u8>(FocusState::InFocus)); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { + const bool use_docked_mode{Settings::values.use_docked_mode}; IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast<u8>(OperationMode::Handheld)); + rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { + const bool use_docked_mode{Settings::values.use_docked_mode}; IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast<u32>(APM::PerformanceMode::Handheld)); + rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked + : APM::PerformanceMode::Handheld)); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } +class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { +public: + explicit IStorageAccessor(std::vector<u8> buffer) + : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { + static const FunctionInfo functions[] = { + {0, &IStorageAccessor::GetSize, "GetSize"}, + {10, &IStorageAccessor::Write, "Write"}, + {11, &IStorageAccessor::Read, "Read"}, + }; + RegisterHandlers(functions); + } + +private: + std::vector<u8> buffer; + + void GetSize(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u64>(buffer.size())); + + NGLOG_DEBUG(Service_AM, "called"); + } + + void Write(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const u64 offset{rp.Pop<u64>()}; + const std::vector<u8> data{ctx.ReadBuffer()}; + + ASSERT(offset + data.size() <= buffer.size()); + + std::memcpy(&buffer[offset], data.data(), data.size()); + + IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; + rb.Push(RESULT_SUCCESS); + + NGLOG_DEBUG(Service_AM, "called, offset={}", offset); + } + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const u64 offset{rp.Pop<u64>()}; + const size_t size{ctx.GetWriteBufferSize()}; + + ASSERT(offset + size <= buffer.size()); + + ctx.WriteBuffer(buffer.data() + offset, size); + + IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; + rb.Push(RESULT_SUCCESS); + + NGLOG_DEBUG(Service_AM, "called, offset={}", offset); + } +}; + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(std::vector<u8> buffer) + : ServiceFramework("IStorage"), buffer(std::move(buffer)) { + static const FunctionInfo functions[] = { + {0, &IStorage::Open, "Open"}, + {1, nullptr, "OpenTransferStorage"}, + }; + RegisterHandlers(functions); + } + +private: + std::vector<u8> buffer; + + void Open(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<AM::IStorageAccessor>(buffer); + + NGLOG_DEBUG(Service_AM, "called"); + } +}; + class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { public: explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { static const FunctionInfo functions[] = { {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, {1, nullptr, "IsCompleted"}, - {10, nullptr, "Start"}, + {10, &ILibraryAppletAccessor::Start, "Start"}, {20, nullptr, "RequestExit"}, {25, nullptr, "Terminate"}, - {30, nullptr, "GetResult"}, + {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, - {100, nullptr, "PushInData"}, - {101, nullptr, "PopOutData"}, + {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, + {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, {102, nullptr, "PushExtraStorage"}, {103, nullptr, "PushInteractiveInData"}, {104, nullptr, "PopInteractiveOutData"}, {105, nullptr, "GetPopOutDataEvent"}, {106, nullptr, "GetPopInteractiveOutDataEvent"}, - {120, nullptr, "NeedsToExitProcess"}, + {110, nullptr, "NeedsToExitProcess"}, {120, nullptr, "GetLibraryAppletInfo"}, {150, nullptr, "RequestForAppletToGetForeground"}, {160, nullptr, "GetIndirectLayerConsumerHandle"}, @@ -290,9 +467,44 @@ private: rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(state_changed_event); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); + } + + void GetResult(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + NGLOG_WARNING(Service_AM, "(STUBBED) called"); + } + + void Start(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + NGLOG_WARNING(Service_AM, "(STUBBED) called"); + } + + void PushInData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + storage_stack.push(rp.PopIpcInterface<AM::IStorage>()); + + IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; + rb.Push(RESULT_SUCCESS); + + NGLOG_DEBUG(Service_AM, "called"); + } + + void PopOutData(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top())); + + storage_stack.pop(); + + NGLOG_DEBUG(Service_AM, "called"); } + std::stack<std::shared_ptr<AM::IStorage>> storage_stack; Kernel::SharedPtr<Kernel::Event> state_changed_event; }; @@ -301,7 +513,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, {1, nullptr, "TerminateAllLibraryApplets"}, {2, nullptr, "AreAnyLibraryAppletsLeft"}, - {10, nullptr, "CreateStorage"}, + {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, {11, nullptr, "CreateTransferMemoryStorage"}, {12, nullptr, "CreateHandleStorage"}, }; @@ -314,83 +526,61 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<AM::ILibraryAppletAccessor>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } -class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { -public: - explicit IStorageAccessor(std::vector<u8> buffer) - : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { - static const FunctionInfo functions[] = { - {0, &IStorageAccessor::GetSize, "GetSize"}, - {11, &IStorageAccessor::Read, "Read"}, - }; - RegisterHandlers(functions); - } - -private: - std::vector<u8> buffer; - - void GetSize(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 4}; - - rb.Push(RESULT_SUCCESS); - rb.Push(static_cast<u64>(buffer.size())); - - LOG_DEBUG(Service_AM, "called"); - } - - void Read(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - u64 offset = rp.Pop<u64>(); - - const size_t size{ctx.GetWriteBufferSize()}; - - ASSERT(offset + size <= buffer.size()); - - ctx.WriteBuffer(buffer.data() + offset, size); - - IPC::ResponseBuilder rb{ctx, 2}; - - rb.Push(RESULT_SUCCESS); - - LOG_DEBUG(Service_AM, "called"); - } -}; - -class IStorage final : public ServiceFramework<IStorage> { -public: - explicit IStorage(std::vector<u8> buffer) - : ServiceFramework("IStorage"), buffer(std::move(buffer)) { - static const FunctionInfo functions[] = { - {0, &IStorage::Open, "Open"}, - }; - RegisterHandlers(functions); - } - -private: - std::vector<u8> buffer; - - void Open(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 size{rp.Pop<u64>()}; + std::vector<u8> buffer(size); - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<AM::IStorageAccessor>(buffer); + IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 1)}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); - LOG_DEBUG(Service_AM, "called"); - } -}; + NGLOG_DEBUG(Service_AM, "called, size={}", size); +} IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { static const FunctionInfo functions[] = { {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, + {10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, + {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, + {12, nullptr, "CreateApplicationAndRequestToStart"}, + {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, + "CreateApplicationAndRequestToStartForQuest"}, {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, + {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, + {24, nullptr, "GetLaunchStorageInfoForDebug"}, + {25, nullptr, "ExtendSaveData"}, + {26, nullptr, "GetSaveDataSize"}, + {30, nullptr, "BeginBlockingHomeButtonShortAndLongPressed"}, + {31, nullptr, "EndBlockingHomeButtonShortAndLongPressed"}, + {32, nullptr, "BeginBlockingHomeButton"}, + {33, nullptr, "EndBlockingHomeButton"}, + {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, + {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, + {60, nullptr, "SetMediaPlaybackStateForApplication"}, + {65, nullptr, "IsGamePlayRecordingSupported"}, {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, - {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, + {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, + {70, nullptr, "RequestToShutdown"}, + {71, nullptr, "RequestToReboot"}, + {80, nullptr, "ExitAndRequestToShowThanksMessage"}, + {90, nullptr, "EnableApplicationCrashReport"}, + {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"}, + {101, nullptr, "SetApplicationCopyrightImage"}, + {102, nullptr, "SetApplicationCopyrightVisibility"}, + {110, nullptr, "QueryApplicationPlayStatistics"}, + {120, nullptr, "ExecuteProgram"}, + {121, nullptr, "ClearUserChannel"}, + {122, nullptr, "UnpopToUserChannel"}, + {500, nullptr, "StartContinuousRecordingFlushForDebug"}, + {1000, nullptr, "CreateMovieMaker"}, + {1001, nullptr, "PrepareForJit"}, }; RegisterHandlers(functions); } @@ -412,13 +602,35 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<AM::IStorage>(buffer); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); +} + +void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( + Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u128 uid = rp.PopRaw<u128>(); + + NGLOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); + IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); + + FileSys::Path unused; + auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData, unused); + if (savedata.Failed()) { + // Create the save data and return an error indicating that the operation was performed. + FileSystem::FormatFileSystem(FileSystem::Type::SaveData); + // TODO(Subv): Find out the correct error code for this. + rb.Push(ResultCode(ErrorModule::FS, 40)); + } else { + rb.Push(RESULT_SUCCESS); + } + rb.Push<u64>(0); } @@ -432,27 +644,36 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called, result=0x%08X", result); + NGLOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); +} + +void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(1); + rb.Push<u64>(0); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { + // TODO(bunnei): This should be configurable IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push<u64>(SystemLanguage::English); - LOG_WARNING(Service_AM, "(STUBBED) called"); + rb.Push(static_cast<u64>(Service::Set::LanguageCode::EN_US)); + NGLOG_DEBUG(Service_AM, "called"); } void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { @@ -460,7 +681,18 @@ void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push<u8>(0); // Unknown, seems to be ignored by official processes - LOG_WARNING(Service_AM, "(STUBBED) called"); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); +} + +void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + + // Returns a 128-bit UUID + rb.Push<u64>(0); + rb.Push<u64>(0); + + NGLOG_WARNING(Service_AM, "(STUBBED) called"); } void InstallInterfaces(SM::ServiceManager& service_manager, @@ -469,5 +701,64 @@ void InstallInterfaces(SM::ServiceManager& service_manager, std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager); } -} // namespace AM -} // namespace Service +IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") { + static const FunctionInfo functions[] = { + {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, + {11, nullptr, "LockForeground"}, + {12, nullptr, "UnlockForeground"}, + {20, nullptr, "PopFromGeneralChannel"}, + {21, nullptr, "GetPopFromGeneralChannelEvent"}, + {30, nullptr, "GetHomeButtonWriterLockAccessor"}, + {31, nullptr, "GetWriterLockAccessorEx"}, + }; + RegisterHandlers(functions); +} + +void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + NGLOG_WARNING(Service_AM, "(STUBBED) called"); +} + +IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { + static const FunctionInfo functions[] = { + {0, nullptr, "RequestToEnterSleep"}, + {1, nullptr, "EnterSleep"}, + {2, nullptr, "StartSleepSequence"}, + {3, nullptr, "StartShutdownSequence"}, + {4, nullptr, "StartRebootSequence"}, + {10, nullptr, "LoadAndApplyIdlePolicySettings"}, + {11, nullptr, "NotifyCecSettingsChanged"}, + {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, + {13, nullptr, "UpdateDefaultDisplayResolution"}, + {14, nullptr, "ShouldSleepOnBoot"}, + {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, + }; + RegisterHandlers(functions); +} + +IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") { + static const FunctionInfo functions[] = { + {0, nullptr, "CreateApplication"}, + {1, nullptr, "PopLaunchRequestedApplication"}, + {10, nullptr, "CreateSystemApplication"}, + {100, nullptr, "PopFloatingApplicationForDevelopment"}, + }; + RegisterHandlers(functions); +} + +IProcessWindingController::IProcessWindingController() + : ServiceFramework("IProcessWindingController") { + static const FunctionInfo functions[] = { + {0, nullptr, "GetLaunchReason"}, + {11, nullptr, "OpenCallingLibraryApplet"}, + {21, nullptr, "PushContext"}, + {22, nullptr, "PopContext"}, + {23, nullptr, "CancelWindingReservation"}, + {30, nullptr, "WindAndDoReserved"}, + {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"}, + {41, nullptr, "ReserveToStartAndWait"}, + }; + RegisterHandlers(functions); +} +} // namespace Service::AM diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 27dbd8c95..1da79fd01 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -18,10 +18,25 @@ class NVFlinger; namespace AM { -// TODO: Add more languages enum SystemLanguage { Japanese = 0, - English = 1, + English = 1, // en-US + French = 2, + German = 3, + Italian = 4, + Spanish = 5, + Chinese = 6, + Korean = 7, + Dutch = 8, + Portuguese = 9, + Russian = 10, + Taiwanese = 11, + BritishEnglish = 12, // en-GB + CanadianFrench = 13, + LatinAmericanSpanish = 14, // es-419 + // 4.0.0+ + SimplifiedChinese = 15, + TraditionalChinese = 16, }; class IWindowController final : public ServiceFramework<IWindowController> { @@ -70,6 +85,7 @@ private: void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); void SetScreenShotPermission(Kernel::HLERequestContext& ctx); + void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); std::shared_ptr<NVFlinger::NVFlinger> nvflinger; Kernel::SharedPtr<Kernel::Event> launchable_event; @@ -105,6 +121,7 @@ public: private: void CreateLibraryApplet(Kernel::HLERequestContext& ctx); + void CreateStorage(Kernel::HLERequestContext& ctx); }; class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { @@ -113,12 +130,38 @@ public: private: void PopLaunchParameter(Kernel::HLERequestContext& ctx); + void CreateApplicationAndRequestToStartForQuest(Kernel::HLERequestContext& ctx); void EnsureSaveData(Kernel::HLERequestContext& ctx); void SetTerminateResult(Kernel::HLERequestContext& ctx); + void GetDisplayVersion(Kernel::HLERequestContext& ctx); void GetDesiredLanguage(Kernel::HLERequestContext& ctx); void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx); void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx); void NotifyRunning(Kernel::HLERequestContext& ctx); + void GetPseudoDeviceId(Kernel::HLERequestContext& ctx); +}; + +class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { +public: + IHomeMenuFunctions(); + +private: + void RequestToGetForeground(Kernel::HLERequestContext& ctx); +}; + +class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { +public: + IGlobalStateController(); +}; + +class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { +public: + IApplicationCreator(); +}; + +class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { +public: + IProcessWindingController(); }; /// Registers all AM services with the specified service manager. diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 0e51caa70..7ce551de3 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -8,8 +8,7 @@ #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/nvflinger/nvflinger.h" -namespace Service { -namespace AM { +namespace Service::AM { class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { public: @@ -21,6 +20,7 @@ public: {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, + {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, {20, &ILibraryAppletProxy::GetApplicationFunctions, "GetApplicationFunctions"}, {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, @@ -33,74 +33,188 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ICommonStateGetter>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetSelfController(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISelfController>(nvflinger); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetWindowController(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IWindowController>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetAudioController(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IAudioController>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetDisplayController(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IDisplayController>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetProcessWindingController(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IProcessWindingController>(); + NGLOG_DEBUG(Service_AM, "called"); } void GetDebugFunctions(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IDebugFunctions>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ILibraryAppletCreator>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IApplicationFunctions>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); + } + + std::shared_ptr<NVFlinger::NVFlinger> nvflinger; +}; + +class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { +public: + explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) + : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) { + static const FunctionInfo functions[] = { + {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, + {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, + {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"}, + {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"}, + {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"}, + {10, nullptr, "GetProcessWindingController"}, + {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, + {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, + {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, + {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, + {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, + }; + RegisterHandlers(functions); + } + +private: + void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ICommonStateGetter>(); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetSelfController(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISelfController>(nvflinger); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetWindowController(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IWindowController>(); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetAudioController(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IAudioController>(); + NGLOG_DEBUG(Service_AM, "called"); } + void GetDisplayController(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDisplayController>(); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetDebugFunctions(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDebugFunctions>(); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ILibraryAppletCreator>(); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IHomeMenuFunctions>(); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetGlobalStateController(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IGlobalStateController>(); + NGLOG_DEBUG(Service_AM, "called"); + } + + void GetApplicationCreator(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IApplicationCreator>(); + NGLOG_DEBUG(Service_AM, "called"); + } std::shared_ptr<NVFlinger::NVFlinger> nvflinger; }; +void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISystemAppletProxy>(nvflinger); + NGLOG_DEBUG(Service_AM, "called"); +} + +void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); + NGLOG_DEBUG(Service_AM, "called"); +} + void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) { static const FunctionInfo functions[] = { - {100, nullptr, "OpenSystemAppletProxy"}, + {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"}, - {201, nullptr, "OpenLibraryAppletProxy"}, + {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"}, {300, nullptr, "OpenOverlayAppletProxy"}, {350, nullptr, "OpenSystemApplicationProxy"}, {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, @@ -108,5 +222,4 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) RegisterHandlers(functions); } -} // namespace AM -} // namespace Service +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 38fc428fb..f3a96651e 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -21,6 +21,8 @@ public: ~AppletAE() = default; private: + void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx); + void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); std::shared_ptr<NVFlinger::NVFlinger> nvflinger; diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index bdcebe689..587a922fe 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -8,8 +8,7 @@ #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/nvflinger/nvflinger.h" -namespace Service { -namespace AM { +namespace Service::AM { class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { public: @@ -21,6 +20,7 @@ public: {2, &IApplicationProxy::GetWindowController, "GetWindowController"}, {3, &IApplicationProxy::GetAudioController, "GetAudioController"}, {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"}, + {10, nullptr, "GetProcessWindingController"}, {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"}, {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"}, @@ -33,56 +33,56 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IAudioController>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetDisplayController(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IDisplayController>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetDebugFunctions(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IDebugFunctions>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetWindowController(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IWindowController>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetSelfController(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISelfController>(nvflinger); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ICommonStateGetter>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ILibraryAppletCreator>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IApplicationFunctions>(); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } std::shared_ptr<NVFlinger::NVFlinger> nvflinger; @@ -92,16 +92,15 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IApplicationProxy>(nvflinger); - LOG_DEBUG(Service_AM, "called"); + NGLOG_DEBUG(Service_AM, "called"); } AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) { static const FunctionInfo functions[] = { - {0x00000000, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, + {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, }; RegisterHandlers(functions); } -} // namespace AM -} // namespace Service +} // namespace Service::AM diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 8b55d2fcb..5b6dfb48f 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -6,8 +6,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/service/aoc/aoc_u.h" -namespace Service { -namespace AOC { +namespace Service::AOC { AOC_U::AOC_U() : ServiceFramework("aoc:u") { static const FunctionInfo functions[] = { @@ -19,6 +18,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u") { {5, nullptr, "GetAddOnContentBaseId"}, {6, nullptr, "PrepareAddOnContentByApplicationId"}, {7, nullptr, "PrepareAddOnContent"}, + {8, nullptr, "GetAddOnContentListChangedEvent"}, }; RegisterHandlers(functions); } @@ -27,19 +27,18 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(0); - LOG_WARNING(Service_AOC, "(STUBBED) called"); + NGLOG_WARNING(Service_AOC, "(STUBBED) called"); } void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(0); - LOG_WARNING(Service_AOC, "(STUBBED) called"); + NGLOG_WARNING(Service_AOC, "(STUBBED) called"); } void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<AOC_U>()->InstallAsService(service_manager); } -} // namespace AOC -} // namespace Service +} // namespace Service::AOC diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 6e0ba15a5..17d48ef30 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h @@ -6,8 +6,7 @@ #include "core/hle/service/service.h" -namespace Service { -namespace AOC { +namespace Service::AOC { class AOC_U final : public ServiceFramework<AOC_U> { public: @@ -22,5 +21,4 @@ private: /// Registers all AOC services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace AOC -} // namespace Service +} // namespace Service::AOC diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index c4b09b435..7a185c6c8 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -7,8 +7,7 @@ #include "core/hle/service/apm/apm.h" #include "core/hle/service/apm/interface.h" -namespace Service { -namespace APM { +namespace Service::APM { void InstallInterfaces(SM::ServiceManager& service_manager) { auto module_ = std::make_shared<Module>(); @@ -16,5 +15,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager); } -} // namespace APM -} // namespace Service +} // namespace Service::APM diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h index 070ab21f8..90a80d51b 100644 --- a/src/core/hle/service/apm/apm.h +++ b/src/core/hle/service/apm/apm.h @@ -6,8 +6,7 @@ #include "core/hle/service/service.h" -namespace Service { -namespace APM { +namespace Service::APM { enum class PerformanceMode : u8 { Handheld = 0, @@ -23,5 +22,4 @@ public: /// Registers all AM services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace APM -} // namespace Service +} // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index 0179351ba..3a03188ce 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp @@ -7,8 +7,7 @@ #include "core/hle/service/apm/apm.h" #include "core/hle/service/apm/interface.h" -namespace Service { -namespace APM { +namespace Service::APM { class ISession final : public ServiceFramework<ISession> { public: @@ -30,8 +29,8 @@ private: IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_APM, "(STUBBED) called mode=%u config=%u", static_cast<u32>(mode), - config); + NGLOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), + config); } void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { @@ -43,7 +42,7 @@ private: rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); // Performance configuration - LOG_WARNING(Service_APM, "(STUBBED) called mode=%u", static_cast<u32>(mode)); + NGLOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); } }; @@ -62,5 +61,4 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) { rb.PushIpcInterface<ISession>(); } -} // namespace APM -} // namespace Service +} // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h index 7d53721de..b99dbb412 100644 --- a/src/core/hle/service/apm/interface.h +++ b/src/core/hle/service/apm/interface.h @@ -6,8 +6,7 @@ #include "core/hle/service/service.h" -namespace Service { -namespace APM { +namespace Service::APM { class APM final : public ServiceFramework<APM> { public: @@ -23,5 +22,4 @@ private: /// Registers all AM services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace APM -} // namespace Service +} // namespace Service::APM diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index ee749fddd..cbc49e55e 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -7,22 +7,26 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/audin_u.h" -namespace Service { -namespace Audio { +namespace Service::Audio { class IAudioIn final : public ServiceFramework<IAudioIn> { public: IAudioIn() : ServiceFramework("IAudioIn") { static const FunctionInfo functions[] = { - {0x0, nullptr, "GetAudioInState"}, - {0x1, nullptr, "StartAudioIn"}, - {0x2, nullptr, "StopAudioIn"}, - {0x3, nullptr, "AppendAudioInBuffer_1"}, - {0x4, nullptr, "RegisterBufferEvent"}, - {0x5, nullptr, "GetReleasedAudioInBuffer_1"}, - {0x6, nullptr, "ContainsAudioInBuffer"}, - {0x7, nullptr, "AppendAudioInBuffer_2"}, - {0x8, nullptr, "GetReleasedAudioInBuffer_2"}, + {0, nullptr, "GetAudioInState"}, + {1, nullptr, "StartAudioIn"}, + {2, nullptr, "StopAudioIn"}, + {3, nullptr, "AppendAudioInBuffer"}, + {4, nullptr, "RegisterBufferEvent"}, + {5, nullptr, "GetReleasedAudioInBuffer"}, + {6, nullptr, "ContainsAudioInBuffer"}, + {7, nullptr, "AppendAudioInBufferWithUserEvent"}, + {8, nullptr, "AppendAudioInBufferAuto"}, + {9, nullptr, "GetReleasedAudioInBufferAuto"}, + {10, nullptr, "AppendAudioInBufferWithUserEventAuto"}, + {11, nullptr, "GetAudioInBufferCount"}, + {12, nullptr, "SetAudioInDeviceGain"}, + {13, nullptr, "GetAudioInDeviceGain"}, }; RegisterHandlers(functions); } @@ -31,11 +35,10 @@ public: AudInU::AudInU() : ServiceFramework("audin:u") { static const FunctionInfo functions[] = { - {0x00000000, nullptr, "ListAudioIns"}, - {0x00000001, nullptr, "OpenAudioIn"}, + {0, nullptr, "ListAudioIns"}, {1, nullptr, "OpenAudioIn"}, {2, nullptr, "Unknown"}, + {3, nullptr, "OpenAudioInAuto"}, {4, nullptr, "ListAudioInsAuto"}, }; RegisterHandlers(functions); } -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h index 2b8576756..2e65efb5b 100644 --- a/src/core/hle/service/audio/audin_u.h +++ b/src/core/hle/service/audio/audin_u.h @@ -10,8 +10,7 @@ namespace Kernel { class HLERequestContext; } -namespace Service { -namespace Audio { +namespace Service::Audio { class AudInU final : public ServiceFramework<AudInU> { public: @@ -19,5 +18,4 @@ public: ~AudInU() = default; }; -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 3f7fb44eb..92f910b5f 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp @@ -9,8 +9,7 @@ #include "core/hle/service/audio/audren_u.h" #include "core/hle/service/audio/codecctl.h" -namespace Service { -namespace Audio { +namespace Service::Audio { void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<AudOutU>()->InstallAsService(service_manager); @@ -20,5 +19,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<CodecCtl>()->InstallAsService(service_manager); } -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h index cbd56b2a8..95e5691f7 100644 --- a/src/core/hle/service/audio/audio.h +++ b/src/core/hle/service/audio/audio.h @@ -6,11 +6,9 @@ #include "core/hle/service/service.h" -namespace Service { -namespace Audio { +namespace Service::Audio { /// Registers all Audio services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 780a4e6e5..402eaa306 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -10,8 +10,7 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/audout_u.h" -namespace Service { -namespace Audio { +namespace Service::Audio { /// Switch sample rate frequency constexpr u32 sample_rate{48000}; @@ -19,21 +18,24 @@ constexpr u32 sample_rate{48000}; /// to more audio channels (probably when Docked I guess) constexpr u32 audio_channels{2}; /// TODO(st4rk): find a proper value for the audio_ticks -constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 500)}; +constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 500)}; class IAudioOut final : public ServiceFramework<IAudioOut> { public: IAudioOut() : ServiceFramework("IAudioOut"), audio_out_state(AudioState::Stopped) { static const FunctionInfo functions[] = { - {0x0, nullptr, "GetAudioOutState"}, - {0x1, &IAudioOut::StartAudioOut, "StartAudioOut"}, - {0x2, &IAudioOut::StopAudioOut, "StopAudioOut"}, - {0x3, &IAudioOut::AppendAudioOutBuffer_1, "AppendAudioOutBuffer_1"}, - {0x4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, - {0x5, &IAudioOut::GetReleasedAudioOutBuffer_1, "GetReleasedAudioOutBuffer_1"}, - {0x6, nullptr, "ContainsAudioOutBuffer"}, - {0x7, nullptr, "AppendAudioOutBuffer_2"}, - {0x8, nullptr, "GetReleasedAudioOutBuffer_2"}, + {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, + {1, &IAudioOut::StartAudioOut, "StartAudioOut"}, + {2, &IAudioOut::StopAudioOut, "StopAudioOut"}, + {3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"}, + {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, + {5, &IAudioOut::GetReleasedAudioOutBuffer, "GetReleasedAudioOutBuffer"}, + {6, nullptr, "ContainsAudioOutBuffer"}, + {7, nullptr, "AppendAudioOutBufferAuto"}, + {8, nullptr, "GetReleasedAudioOutBufferAuto"}, + {9, nullptr, "GetAudioOutBufferCount"}, + {10, nullptr, "GetAudioOutPlayedSampleCount"}, + {11, nullptr, "FlushAudioOutBuffers"}, }; RegisterHandlers(functions); @@ -52,11 +54,20 @@ public: CoreTiming::ScheduleEvent(audio_ticks, audio_event); } - ~IAudioOut() = default; + ~IAudioOut() { + CoreTiming::UnscheduleEvent(audio_event, 0); + } private: + void GetAudioOutState(Kernel::HLERequestContext& ctx) { + NGLOG_DEBUG(Service_Audio, "called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u32>(audio_out_state)); + } + void StartAudioOut(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); // Start audio audio_out_state = AudioState::Started; @@ -66,7 +77,7 @@ private: } void StopAudioOut(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); // Stop audio audio_out_state = AudioState::Stopped; @@ -78,15 +89,15 @@ private: } void RegisterBufferEvent(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(buffer_event); } - void AppendAudioOutBuffer_1(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + void AppendAudioOutBuffer(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); IPC::RequestParser rp{ctx}; const u64 key{rp.Pop<u64>()}; @@ -96,8 +107,8 @@ private: rb.Push(RESULT_SUCCESS); } - void GetReleasedAudioOutBuffer_1(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + void GetReleasedAudioOutBuffer(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(st4rk): This is how libtransistor currently implements the // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address @@ -153,7 +164,7 @@ private: }; void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); IPC::RequestParser rp{ctx}; const std::string audio_interface = "AudioInterface"; @@ -169,7 +180,7 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { } void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); if (!audio_out_interface) { audio_out_interface = std::make_shared<IAudioOut>(); @@ -185,12 +196,11 @@ void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) { } AudOutU::AudOutU() : ServiceFramework("audout:u") { - static const FunctionInfo functions[] = {{0x00000000, &AudOutU::ListAudioOuts, "ListAudioOuts"}, - {0x00000001, &AudOutU::OpenAudioOut, "OpenAudioOut"}, - {0x00000002, nullptr, "Unknown2"}, - {0x00000003, nullptr, "Unknown3"}}; + static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOuts, "ListAudioOuts"}, + {1, &AudOutU::OpenAudioOut, "OpenAudioOut"}, + {2, nullptr, "ListAudioOutsAuto"}, + {3, nullptr, "OpenAudioOutAuto"}}; RegisterHandlers(functions); } -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index 7fbce2225..1f9bb9bcf 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h @@ -10,8 +10,7 @@ namespace Kernel { class HLERequestContext; } -namespace Service { -namespace Audio { +namespace Service::Audio { class IAudioOut; @@ -37,5 +36,4 @@ private: }; }; -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp index f2626ec70..74909415c 100644 --- a/src/core/hle/service/audio/audrec_u.cpp +++ b/src/core/hle/service/audio/audrec_u.cpp @@ -7,20 +7,22 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/audrec_u.h" -namespace Service { -namespace Audio { +namespace Service::Audio { class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> { public: IFinalOutputRecorder() : ServiceFramework("IFinalOutputRecorder") { static const FunctionInfo functions[] = { - {0x0, nullptr, "GetFinalOutputRecorderState"}, - {0x1, nullptr, "StartFinalOutputRecorder"}, - {0x2, nullptr, "StopFinalOutputRecorder"}, - {0x3, nullptr, "AppendFinalOutputRecorderBuffer"}, - {0x4, nullptr, "RegisterBufferEvent"}, - {0x5, nullptr, "GetReleasedFinalOutputRecorderBuffer"}, - {0x6, nullptr, "ContainsFinalOutputRecorderBuffer"}, + {0, nullptr, "GetFinalOutputRecorderState"}, + {1, nullptr, "StartFinalOutputRecorder"}, + {2, nullptr, "StopFinalOutputRecorder"}, + {3, nullptr, "AppendFinalOutputRecorderBuffer"}, + {4, nullptr, "RegisterBufferEvent"}, + {5, nullptr, "GetReleasedFinalOutputRecorderBuffer"}, + {6, nullptr, "ContainsFinalOutputRecorderBuffer"}, + {7, nullptr, "Unknown"}, + {8, nullptr, "AppendFinalOutputRecorderBufferAuto"}, + {9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"}, }; RegisterHandlers(functions); } @@ -29,10 +31,9 @@ public: AudRecU::AudRecU() : ServiceFramework("audrec:u") { static const FunctionInfo functions[] = { - {0x00000000, nullptr, "OpenFinalOutputRecorder"}, + {0, nullptr, "OpenFinalOutputRecorder"}, }; RegisterHandlers(functions); } -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h index c31e412c1..46daa33a4 100644 --- a/src/core/hle/service/audio/audrec_u.h +++ b/src/core/hle/service/audio/audrec_u.h @@ -10,8 +10,7 @@ namespace Kernel { class HLERequestContext; } -namespace Service { -namespace Audio { +namespace Service::Audio { class AudRecU final : public ServiceFramework<AudRecU> { public: @@ -19,5 +18,4 @@ public: ~AudRecU() = default; }; -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index dda135d18..6e8002bc9 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/alignment.h" #include "common/logging/log.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" @@ -9,26 +10,27 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/audren_u.h" -namespace Service { -namespace Audio { +namespace Service::Audio { /// TODO(bunnei): Find a proper value for the audio_ticks -constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 200)}; +constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)}; class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { public: IAudioRenderer() : ServiceFramework("IAudioRenderer") { static const FunctionInfo functions[] = { - {0x0, nullptr, "GetAudioRendererSampleRate"}, - {0x1, nullptr, "GetAudioRendererSampleCount"}, - {0x2, nullptr, "GetAudioRendererMixBufferCount"}, - {0x3, nullptr, "GetAudioRendererState"}, - {0x4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"}, - {0x5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"}, - {0x6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"}, - {0x7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, - {0x8, nullptr, "SetAudioRendererRenderingTimeLimit"}, - {0x9, nullptr, "GetAudioRendererRenderingTimeLimit"}, + {0, nullptr, "GetAudioRendererSampleRate"}, + {1, nullptr, "GetAudioRendererSampleCount"}, + {2, nullptr, "GetAudioRendererMixBufferCount"}, + {3, nullptr, "GetAudioRendererState"}, + {4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"}, + {5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"}, + {6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"}, + {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, + {8, nullptr, "SetAudioRendererRenderingTimeLimit"}, + {9, nullptr, "GetAudioRendererRenderingTimeLimit"}, + {10, nullptr, "RequestUpdateAudioRendererAuto"}, + {11, nullptr, "ExecuteAudioRendererRendering"}, }; RegisterHandlers(functions); @@ -45,7 +47,9 @@ public: // Start the audio event CoreTiming::ScheduleEvent(audio_ticks, audio_event); } - ~IAudioRenderer() = default; + ~IAudioRenderer() { + CoreTiming::UnscheduleEvent(audio_event, 0); + } private: void UpdateAudioCallback() { @@ -53,16 +57,16 @@ private: } void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Audio, "%s", ctx.Description().c_str()); + NGLOG_DEBUG(Service_Audio, "{}", ctx.Description()); AudioRendererResponseData response_data{}; response_data.section_0_size = - response_data.state_entries.size() * sizeof(AudioRendererStateEntry); - response_data.section_1_size = response_data.section_1.size(); - response_data.section_2_size = response_data.section_2.size(); - response_data.section_3_size = response_data.section_3.size(); - response_data.section_4_size = response_data.section_4.size(); - response_data.section_5_size = response_data.section_5.size(); + static_cast<u32>(response_data.state_entries.size() * sizeof(AudioRendererStateEntry)); + response_data.section_1_size = static_cast<u32>(response_data.section_1.size()); + response_data.section_2_size = static_cast<u32>(response_data.section_2.size()); + response_data.section_3_size = static_cast<u32>(response_data.section_3.size()); + response_data.section_4_size = static_cast<u32>(response_data.section_4.size()); + response_data.section_5_size = static_cast<u32>(response_data.section_5.size()); response_data.total_size = sizeof(AudioRendererResponseData); for (unsigned i = 0; i < response_data.state_entries.size(); i++) { @@ -76,7 +80,7 @@ private: rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); } void StartAudioRenderer(Kernel::HLERequestContext& ctx) { @@ -84,7 +88,7 @@ private: rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); } void StopAudioRenderer(Kernel::HLERequestContext& ctx) { @@ -92,7 +96,7 @@ private: rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); } void QuerySystemEvent(Kernel::HLERequestContext& ctx) { @@ -102,7 +106,7 @@ private: rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(system_event); - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); } struct AudioRendererStateEntry { @@ -149,12 +153,96 @@ private: Kernel::SharedPtr<Kernel::Event> system_event; }; +class IAudioDevice final : public ServiceFramework<IAudioDevice> { +public: + IAudioDevice() : ServiceFramework("IAudioDevice") { + static const FunctionInfo functions[] = { + {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, + {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, + {2, nullptr, "GetAudioDeviceOutputVolume"}, + {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"}, + {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"}, + {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"}, + {6, &IAudioDevice::ListAudioDeviceName, + "ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto + {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"}, + {8, nullptr, "GetAudioDeviceOutputVolumeAuto"}, + {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"}, + {11, nullptr, "QueryAudioDeviceInputEvent"}, + {12, nullptr, "QueryAudioDeviceOutputEvent"}, + }; + RegisterHandlers(functions); + + buffer_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent"); + } + +private: + void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + + const std::string audio_interface = "AudioInterface"; + ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size()); + + IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(1); + } + + void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + f32 volume = static_cast<f32>(rp.Pop<u32>()); + + auto file_buffer = ctx.ReadBuffer(); + auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); + + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + rb.Push(RESULT_SUCCESS); + } + + void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + + const std::string audio_interface = "AudioDevice"; + ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size()); + + IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(1); + } + + void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); + + buffer_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(buffer_event); + } + + void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Audio, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(1); + } + + Kernel::SharedPtr<Kernel::Event> buffer_event; + +}; // namespace Audio + AudRenU::AudRenU() : ServiceFramework("audren:u") { static const FunctionInfo functions[] = { {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"}, - {2, &AudRenU::GetAudioRenderersProcessMasterVolume, "GetAudioRenderersProcessMasterVolume"}, - {3, nullptr, "SetAudioRenderersProcessMasterVolume"}, + {2, &AudRenU::GetAudioDevice, "GetAudioDevice"}, + {3, nullptr, "OpenAudioRendererAuto"}, + {4, nullptr, "GetAudioDeviceServiceWithRevisionInfo"}, }; RegisterHandlers(functions); } @@ -165,25 +253,85 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<Audio::IAudioRenderer>(); - LOG_DEBUG(Service_Audio, "called"); + NGLOG_DEBUG(Service_Audio, "called"); } void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto params = rp.PopRaw<WorkerBufferParameters>(); + + u64 buffer_sz = Common::AlignUp(4 * params.unknown8, 0x40); + buffer_sz += params.unknownC * 1024; + buffer_sz += 0x940 * (params.unknownC + 1); + buffer_sz += 0x3F0 * params.voice_count; + buffer_sz += Common::AlignUp(8 * (params.unknownC + 1), 0x10); + buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10); + buffer_sz += + Common::AlignUp((0x3C0 * (params.sink_count + params.unknownC) + 4 * params.sample_count) * + (params.unknown8 + 6), + 0x40); + + if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) { + u32 count = params.unknownC + 1; + u64 node_count = Common::AlignUp(count, 0x40); + u64 node_state_buffer_sz = + 4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8); + u64 edge_matrix_buffer_sz = 0; + node_count = Common::AlignUp(count * count, 0x40); + if (node_count >> 31 != 0) { + edge_matrix_buffer_sz = (node_count | 7) / 8; + } else { + edge_matrix_buffer_sz = node_count / 8; + } + buffer_sz += Common::AlignUp(node_state_buffer_sz + edge_matrix_buffer_sz, 0x10); + } + + buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50; + if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) { + buffer_sz += 0xE0 * params.unknown2c; + buffer_sz += 0x20 * params.splitter_count; + buffer_sz += Common::AlignUp(4 * params.unknown2c, 0x10); + } + buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count; + u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count + + ((params.voice_count * 256) | 0x40); + + if (params.unknown1c >= 1) { + output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count + + 16 * params.voice_count + 16) + + 0x658) * + (params.unknown1c + 1) + + 0xc0, + 0x40) + + output_sz; + } + output_sz = Common::AlignUp(output_sz + 0x1807e, 0x1000); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push<u64>(0x400); + rb.Push<u64>(output_sz); - LOG_WARNING(Service_Audio, "(STUBBED) called"); + NGLOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz); } -void AudRenU::GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 3}; +void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(100); - LOG_WARNING(Service_Audio, "(STUBBED) called"); + rb.PushIpcInterface<Audio::IAudioDevice>(); + + NGLOG_DEBUG(Service_Audio, "called"); +} + +bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { + u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap + switch (feature) { + case AudioFeatures::Splitter: + return version_num >= 2; + default: + return false; + } } -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 939d353a9..fe53de4ce 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -10,8 +10,7 @@ namespace Kernel { class HLERequestContext; } -namespace Service { -namespace Audio { +namespace Service::Audio { class AudRenU final : public ServiceFramework<AudRenU> { public: @@ -21,8 +20,32 @@ public: private: void OpenAudioRenderer(Kernel::HLERequestContext& ctx); void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); - void GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx); + void GetAudioDevice(Kernel::HLERequestContext& ctx); + + struct WorkerBufferParameters { + u32_le sample_rate; + u32_le sample_count; + u32_le unknown8; + u32_le unknownC; + u32_le voice_count; + u32_le sink_count; + u32_le effect_count; + u32_le unknown1c; + u8 unknown20; + u8 padding1[3]; + u32_le splitter_count; + u32_le unknown2c; + u8 padding2[4]; + u32_le magic; + }; + static_assert(sizeof(WorkerBufferParameters) == 52, + "WorkerBufferParameters is an invalid size"); + + enum class AudioFeatures : u32 { + Splitter, + }; + + bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const; }; -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp index d2a7f4cd0..212c8d448 100644 --- a/src/core/hle/service/audio/codecctl.cpp +++ b/src/core/hle/service/audio/codecctl.cpp @@ -7,27 +7,25 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/codecctl.h" -namespace Service { -namespace Audio { +namespace Service::Audio { CodecCtl::CodecCtl() : ServiceFramework("codecctl") { static const FunctionInfo functions[] = { - {0x00000000, nullptr, "InitializeCodecController"}, - {0x00000001, nullptr, "FinalizeCodecController"}, - {0x00000002, nullptr, "SleepCodecController"}, - {0x00000003, nullptr, "WakeCodecController"}, - {0x00000004, nullptr, "SetCodecVolume"}, - {0x00000005, nullptr, "GetCodecVolumeMax"}, - {0x00000006, nullptr, "GetCodecVolumeMin"}, - {0x00000007, nullptr, "SetCodecActiveTarget"}, - {0x00000008, nullptr, "Unknown"}, - {0x00000009, nullptr, "BindCodecHeadphoneMicJackInterrupt"}, - {0x0000000A, nullptr, "IsCodecHeadphoneMicJackInserted"}, - {0x0000000B, nullptr, "ClearCodecHeadphoneMicJackInterrupt"}, - {0x0000000C, nullptr, "IsCodecDeviceRequested"}, + {0, nullptr, "InitializeCodecController"}, + {1, nullptr, "FinalizeCodecController"}, + {2, nullptr, "SleepCodecController"}, + {3, nullptr, "WakeCodecController"}, + {4, nullptr, "SetCodecVolume"}, + {5, nullptr, "GetCodecVolumeMax"}, + {6, nullptr, "GetCodecVolumeMin"}, + {7, nullptr, "SetCodecActiveTarget"}, + {8, nullptr, "GetCodecActiveTarget"}, + {9, nullptr, "BindCodecHeadphoneMicJackInterrupt"}, + {10, nullptr, "IsCodecHeadphoneMicJackInserted"}, + {11, nullptr, "ClearCodecHeadphoneMicJackInterrupt"}, + {12, nullptr, "IsCodecDeviceRequested"}, }; RegisterHandlers(functions); } -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h index 1121ab0b1..d9ac29b67 100644 --- a/src/core/hle/service/audio/codecctl.h +++ b/src/core/hle/service/audio/codecctl.h @@ -10,8 +10,7 @@ namespace Kernel { class HLERequestContext; } -namespace Service { -namespace Audio { +namespace Service::Audio { class CodecCtl final : public ServiceFramework<CodecCtl> { public: @@ -19,5 +18,4 @@ public: ~CodecCtl() = default; }; -} // namespace Audio -} // namespace Service +} // namespace Service::Audio diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp new file mode 100644 index 000000000..20ce692dc --- /dev/null +++ b/src/core/hle/service/bcat/bcat.cpp @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/bcat/bcat.h" + +namespace Service::BCAT { + +BCAT::BCAT(std::shared_ptr<Module> module, const char* name) + : Module::Interface(std::move(module), name) { + static const FunctionInfo functions[] = { + {0, &BCAT::CreateBcatService, "CreateBcatService"}, + }; + RegisterHandlers(functions); +} +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h new file mode 100644 index 000000000..6632996a0 --- /dev/null +++ b/src/core/hle/service/bcat/bcat.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/bcat/module.h" + +namespace Service::BCAT { + +class BCAT final : public Module::Interface { +public: + explicit BCAT(std::shared_ptr<Module> module, const char* name); +}; + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp new file mode 100644 index 000000000..52be9db22 --- /dev/null +++ b/src/core/hle/service/bcat/module.cpp @@ -0,0 +1,53 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/bcat/bcat.h" +#include "core/hle/service/bcat/module.h" + +namespace Service::BCAT { + +class IBcatService final : public ServiceFramework<IBcatService> { +public: + IBcatService() : ServiceFramework("IBcatService") { + static const FunctionInfo functions[] = { + {10100, nullptr, "RequestSyncDeliveryCache"}, + {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"}, + {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, + {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, + {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, + {30100, nullptr, "SetPassphrase"}, + {30200, nullptr, "RegisterBackgroundDeliveryTask"}, + {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, + {30202, nullptr, "BlockDeliveryTask"}, + {30203, nullptr, "UnblockDeliveryTask"}, + {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, + {90200, nullptr, "GetDeliveryList"}, + {90201, nullptr, "ClearDeliveryCacheStorage"}, + {90300, nullptr, "GetPushNotificationLog"}, + }; + RegisterHandlers(functions); + } +}; + +void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IBcatService>(); + NGLOG_DEBUG(Service_BCAT, "called"); +} + +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) + : ServiceFramework(name), module(std::move(module)) {} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + auto module = std::make_shared<Module>(); + std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); + std::make_shared<BCAT>(module, "bcat:m")->InstallAsService(service_manager); + std::make_shared<BCAT>(module, "bcat:u")->InstallAsService(service_manager); + std::make_shared<BCAT>(module, "bcat:s")->InstallAsService(service_manager); +} + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h new file mode 100644 index 000000000..8366fb877 --- /dev/null +++ b/src/core/hle/service/bcat/module.h @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::BCAT { + +class Module final { +public: + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name); + + void CreateBcatService(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + }; +}; + +/// Registers all BCAT services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::BCAT diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp new file mode 100644 index 000000000..2d4282209 --- /dev/null +++ b/src/core/hle/service/fatal/fatal.cpp @@ -0,0 +1,36 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/fatal/fatal.h" +#include "core/hle/service/fatal/fatal_p.h" +#include "core/hle/service/fatal/fatal_u.h" + +namespace Service::Fatal { + +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) + : ServiceFramework(name), module(std::move(module)) {} + +void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + u32 error_code = rp.Pop<u32>(); + NGLOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_Fatal, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + auto module = std::make_shared<Module>(); + std::make_shared<Fatal_P>(module)->InstallAsService(service_manager); + std::make_shared<Fatal_U>(module)->InstallAsService(service_manager); +} + +} // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h new file mode 100644 index 000000000..5bd111a14 --- /dev/null +++ b/src/core/hle/service/fatal/fatal.h @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::Fatal { + +class Module final { +public: + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name); + + void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx); + void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + }; +}; + +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp new file mode 100644 index 000000000..a5254ac2f --- /dev/null +++ b/src/core/hle/service/fatal/fatal_p.cpp @@ -0,0 +1,12 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/fatal/fatal_p.h" + +namespace Service::Fatal { + +Fatal_P::Fatal_P(std::shared_ptr<Module> module) + : Module::Interface(std::move(module), "fatal:p") {} + +} // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h new file mode 100644 index 000000000..bfd8c8b74 --- /dev/null +++ b/src/core/hle/service/fatal/fatal_p.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/fatal/fatal.h" + +namespace Service::Fatal { + +class Fatal_P final : public Module::Interface { +public: + explicit Fatal_P(std::shared_ptr<Module> module); +}; + +} // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp new file mode 100644 index 000000000..f0631329e --- /dev/null +++ b/src/core/hle/service/fatal/fatal_u.cpp @@ -0,0 +1,18 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/fatal/fatal_u.h" + +namespace Service::Fatal { + +Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") { + static const FunctionInfo functions[] = { + {0, nullptr, "ThrowFatal"}, + {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, + {2, &Fatal_U::ThrowFatalWithCpuContext, "ThrowFatalWithCpuContext"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h new file mode 100644 index 000000000..9b1a9e97a --- /dev/null +++ b/src/core/hle/service/fatal/fatal_u.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/fatal/fatal.h" + +namespace Service::Fatal { + +class Fatal_U final : public Module::Interface { +public: + explicit Fatal_U(std::shared_ptr<Module> module); +}; + +} // namespace Service::Fatal diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 4b47548fd..68d1c90a5 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -3,12 +3,14 @@ // Refer to the license.txt file included. #include <boost/container/flat_map.hpp> +#include "common/file_util.h" #include "core/file_sys/filesystem.h" +#include "core/file_sys/savedata_factory.h" +#include "core/file_sys/sdmc_factory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" -namespace Service { -namespace FileSystem { +namespace Service::FileSystem { /** * Map of registered file systems, identified by type. Once an file system is registered here, it @@ -23,14 +25,14 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact ASSERT_MSG(inserted, "Tried to register more than one system with same id code"); auto& filesystem = result.first->second; - LOG_DEBUG(Service_FS, "Registered file system %s with id code 0x%08X", - filesystem->GetName().c_str(), static_cast<u32>(type)); + NGLOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}", + filesystem->GetName(), static_cast<u32>(type)); return RESULT_SUCCESS; } ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, FileSys::Path& path) { - LOG_TRACE(Service_FS, "Opening FileSystem with type=%d", type); + NGLOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type)); auto itr = filesystem_map.find(type); if (itr == filesystem_map.end()) { @@ -41,14 +43,35 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, return itr->second->Open(path); } -void UnregisterFileSystems() { +ResultCode FormatFileSystem(Type type) { + NGLOG_TRACE(Service_FS, "Formatting FileSystem with type={}", static_cast<u32>(type)); + + auto itr = filesystem_map.find(type); + if (itr == filesystem_map.end()) { + // TODO(bunnei): Find a better error code for this + return ResultCode(-1); + } + + FileSys::Path unused; + return itr->second->Format(unused); +} + +void RegisterFileSystems() { filesystem_map.clear(); + + std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); + std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); + + auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); + RegisterFileSystem(std::move(savedata), Type::SaveData); + + auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory)); + RegisterFileSystem(std::move(sdcard), Type::SDMC); } void InstallInterfaces(SM::ServiceManager& service_manager) { - UnregisterFileSystems(); + RegisterFileSystems(); std::make_shared<FSP_SRV>()->InstallAsService(service_manager); } -} // namespace FileSystem -} // namespace Service +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index a674c9493..56d26146e 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -25,6 +25,8 @@ namespace FileSystem { /// Supported FileSystem types enum class Type { RomFS = 1, + SaveData = 2, + SDMC = 3, }; /** @@ -43,6 +45,13 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, FileSys::Path& path); +/** + * Formats a file system + * @param type Type of the file system to format + * @return ResultCode of the operation + */ +ResultCode FormatFileSystem(Type type); + /// Registers all Filesystem services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 87a07e457..1cf97e876 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cinttypes> #include "common/logging/log.h" +#include "common/string_util.h" #include "core/core.h" +#include "core/file_sys/directory.h" #include "core/file_sys/filesystem.h" #include "core/file_sys/storage.h" #include "core/hle/ipc_helpers.h" @@ -12,8 +15,7 @@ #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" -namespace Service { -namespace FileSystem { +namespace Service::FileSystem { class IStorage final : public ServiceFramework<IStorage> { public: @@ -21,7 +23,7 @@ public: : ServiceFramework("IStorage"), backend(std::move(backend)) { static const FunctionInfo functions[] = { {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"}, - {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, + {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"}, }; RegisterHandlers(functions); } @@ -34,7 +36,7 @@ private: const s64 offset = rp.Pop<s64>(); const s64 length = rp.Pop<s64>(); - LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); + NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); // Error checking if (length < 0) { @@ -65,14 +67,421 @@ private: } }; +class IFile final : public ServiceFramework<IFile> { +public: + explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend) + : ServiceFramework("IFile"), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, + {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, + {4, &IFile::GetSize, "GetSize"}, {5, nullptr, "OperateRange"}, + }; + RegisterHandlers(functions); + } + +private: + std::unique_ptr<FileSys::StorageBackend> backend; + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 unk = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + + // Error checking + if (length < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + return; + } + if (offset < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + return; + } + + // Read the data from the Storage backend + std::vector<u8> output(length); + ResultVal<size_t> res = backend->Read(offset, length, output.data()); + if (res.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res.Code()); + return; + } + + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u64>(*res)); + } + + void Write(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 unk = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + + // Error checking + if (length < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + return; + } + if (offset < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + return; + } + + // Write the data to the Storage backend + std::vector<u8> data = ctx.ReadBuffer(); + ResultVal<size_t> res = backend->Write(offset, length, true, data.data()); + if (res.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res.Code()); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Flush(Kernel::HLERequestContext& ctx) { + NGLOG_DEBUG(Service_FS, "called"); + backend->Flush(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void SetSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 size = rp.Pop<u64>(); + backend->SetSize(size); + NGLOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void GetSize(Kernel::HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + NGLOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(size); + } +}; + +class IDirectory final : public ServiceFramework<IDirectory> { +public: + explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend) + : ServiceFramework("IDirectory"), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0, &IDirectory::Read, "Read"}, + {1, &IDirectory::GetEntryCount, "GetEntryCount"}, + }; + RegisterHandlers(functions); + } + +private: + std::unique_ptr<FileSys::DirectoryBackend> backend; + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 unk = rp.Pop<u64>(); + + NGLOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk); + + // Calculate how many entries we can fit in the output buffer + u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); + + // Read the data from the Directory backend + std::vector<FileSys::Entry> entries(count_entries); + u64 read_entries = backend->Read(count_entries, entries.data()); + + // Convert the data into a byte array + std::vector<u8> output(entries.size() * sizeof(FileSys::Entry)); + std::memcpy(output.data(), entries.data(), output.size()); + + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(read_entries); + } + + void GetEntryCount(Kernel::HLERequestContext& ctx) { + NGLOG_DEBUG(Service_FS, "called"); + + u64 count = backend->GetEntryCount(); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(count); + } +}; + +class IFileSystem final : public ServiceFramework<IFileSystem> { +public: + explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) + : ServiceFramework("IFileSystem"), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0, &IFileSystem::CreateFile, "CreateFile"}, + {1, &IFileSystem::DeleteFile, "DeleteFile"}, + {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, + {3, nullptr, "DeleteDirectory"}, + {4, nullptr, "DeleteDirectoryRecursively"}, + {5, &IFileSystem::RenameFile, "RenameFile"}, + {6, nullptr, "RenameDirectory"}, + {7, &IFileSystem::GetEntryType, "GetEntryType"}, + {8, &IFileSystem::OpenFile, "OpenFile"}, + {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, + {10, &IFileSystem::Commit, "Commit"}, + {11, nullptr, "GetFreeSpaceSize"}, + {12, nullptr, "GetTotalSpaceSize"}, + {13, nullptr, "CleanDirectoryRecursively"}, + {14, nullptr, "GetFileTimeStampRaw"}, + {15, nullptr, "QueryEntry"}, + }; + RegisterHandlers(functions); + } + + void CreateFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + u64 mode = rp.Pop<u64>(); + u32 size = rp.Pop<u32>(); + + NGLOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend->CreateFile(name, size)); + } + + void DeleteFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + NGLOG_DEBUG(Service_FS, "called file {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend->DeleteFile(name)); + } + + void CreateDirectory(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + NGLOG_DEBUG(Service_FS, "called directory {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend->CreateDirectory(name)); + } + + void RenameFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + std::vector<u8> buffer; + buffer.resize(ctx.BufferDescriptorX()[0].Size()); + Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size()); + std::string src_name = Common::StringFromBuffer(buffer); + + buffer.resize(ctx.BufferDescriptorX()[1].Size()); + Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size()); + std::string dst_name = Common::StringFromBuffer(buffer); + + NGLOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend->RenameFile(src_name, dst_name)); + } + + void OpenFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); + + NGLOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); + + auto result = backend->OpenFile(name, mode); + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } + + auto file = std::move(result.Unwrap()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IFile>(std::move(file)); + } + + void OpenDirectory(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + // TODO(Subv): Implement this filter. + u32 filter_flags = rp.Pop<u32>(); + + NGLOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); + + auto result = backend->OpenDirectory(name); + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } + + auto directory = std::move(result.Unwrap()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDirectory>(std::move(directory)); + } + + void GetEntryType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + std::string name = Common::StringFromBuffer(file_buffer); + + NGLOG_DEBUG(Service_FS, "called file {}", name); + + auto result = backend->GetEntryType(name); + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(*result)); + } + + void Commit(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + +private: + std::unique_ptr<FileSys::FileSystemBackend> backend; +}; + FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { static const FunctionInfo functions[] = { - {1, &FSP_SRV::Initalize, "Initalize"}, + {0, nullptr, "MountContent"}, + {1, &FSP_SRV::Initialize, "Initialize"}, + {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, + {7, nullptr, "OpenFileSystemWithPatch"}, + {8, nullptr, "OpenFileSystemWithId"}, + {9, nullptr, "OpenDataFileSystemByApplicationId"}, + {11, nullptr, "OpenBisFileSystem"}, + {12, nullptr, "OpenBisStorage"}, + {13, nullptr, "InvalidateBisCache"}, + {17, nullptr, "OpenHostFileSystem"}, {18, &FSP_SRV::MountSdCard, "MountSdCard"}, + {19, nullptr, "FormatSdCardFileSystem"}, + {21, nullptr, "DeleteSaveDataFileSystem"}, + {22, &FSP_SRV::CreateSaveData, "CreateSaveData"}, + {23, nullptr, "CreateSaveDataFileSystemBySystemSaveDataId"}, + {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"}, + {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"}, + {26, nullptr, "FormatSdCardDryRun"}, + {27, nullptr, "IsExFatSupported"}, + {28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"}, + {30, nullptr, "OpenGameCardStorage"}, + {31, nullptr, "OpenGameCardFileSystem"}, + {32, nullptr, "ExtendSaveDataFileSystem"}, + {33, nullptr, "DeleteCacheStorage"}, + {34, nullptr, "GetCacheStorageSize"}, + {51, &FSP_SRV::MountSaveData, "MountSaveData"}, + {52, nullptr, "OpenSaveDataFileSystemBySystemSaveDataId"}, + {53, nullptr, "OpenReadOnlySaveDataFileSystem"}, + {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, + {58, nullptr, "ReadSaveDataFileSystemExtraData"}, + {59, nullptr, "WriteSaveDataFileSystemExtraData"}, + {60, nullptr, "OpenSaveDataInfoReader"}, + {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, + {62, nullptr, "OpenCacheStorageList"}, + {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, + {65, nullptr, "UpdateSaveDataMacForDebug"}, + {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, + {80, nullptr, "OpenSaveDataMetaFile"}, + {81, nullptr, "OpenSaveDataTransferManager"}, + {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, + {100, nullptr, "OpenImageDirectoryFileSystem"}, + {110, nullptr, "OpenContentStorageFileSystem"}, {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, + {201, nullptr, "OpenDataStorageByProgramId"}, {202, nullptr, "OpenDataStorageByDataId"}, {203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"}, + {400, nullptr, "OpenDeviceOperator"}, + {500, nullptr, "OpenSdCardDetectionEventNotifier"}, + {501, nullptr, "OpenGameCardDetectionEventNotifier"}, + {510, nullptr, "OpenSystemDataUpdateEventNotifier"}, + {511, nullptr, "NotifySystemDataUpdateEvent"}, + {600, nullptr, "SetCurrentPosixTime"}, + {601, nullptr, "QuerySaveDataTotalSize"}, + {602, nullptr, "VerifySaveDataFileSystem"}, + {603, nullptr, "CorruptSaveDataFileSystem"}, + {604, nullptr, "CreatePaddingFile"}, + {605, nullptr, "DeleteAllPaddingFiles"}, + {606, nullptr, "GetRightsId"}, + {607, nullptr, "RegisterExternalKey"}, + {608, nullptr, "UnregisterAllExternalKey"}, + {609, nullptr, "GetRightsIdByPath"}, + {610, nullptr, "GetRightsIdAndKeyGenerationByPath"}, + {611, nullptr, "SetCurrentPosixTimeWithTimeDifference"}, + {612, nullptr, "GetFreeSpaceSizeForSaveData"}, + {613, nullptr, "VerifySaveDataFileSystemBySaveDataSpaceId"}, + {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"}, + {615, nullptr, "QuerySaveDataInternalStorageTotalSize"}, + {620, nullptr, "SetSdCardEncryptionSeed"}, + {630, nullptr, "SetSdCardAccessibility"}, + {631, nullptr, "IsSdCardAccessible"}, + {640, nullptr, "IsSignedSystemPartitionOnSdCardValid"}, + {700, nullptr, "OpenAccessFailureResolver"}, + {701, nullptr, "GetAccessFailureDetectionEvent"}, + {702, nullptr, "IsAccessFailureDetected"}, + {710, nullptr, "ResolveAccessFailure"}, + {720, nullptr, "AbandonAccessFailure"}, + {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"}, + {1000, nullptr, "SetBisRootForHost"}, + {1001, nullptr, "SetSaveDataSize"}, + {1002, nullptr, "SetSaveDataRootPath"}, + {1003, nullptr, "DisableAutoSaveDataCreation"}, + {1004, nullptr, "SetGlobalAccessLogMode"}, {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, + {1006, nullptr, "OutputAccessLogToSdCard"}, + {1007, nullptr, "RegisterUpdatePartition"}, + {1008, nullptr, "OpenRegisteredUpdatePartition"}, + {1009, nullptr, "GetAndClearMemoryReportInfo"}, + {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, }; RegisterHandlers(functions); } @@ -88,22 +497,50 @@ void FSP_SRV::TryLoadRomFS() { } } -void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); +void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_FS, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); + NGLOG_DEBUG(Service_FS, "called"); + + FileSys::Path unused; + auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); +} + +void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto save_struct = rp.PopRaw<std::array<u8, 0x40>>(); + auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); + u128 uid = rp.PopRaw<u128>(); + + NGLOG_WARNING(Service_FS, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } +void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_FS, "(STUBBED) called"); + + FileSys::Path unused; + auto filesystem = OpenFileSystem(Type::SaveData, unused).Unwrap(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); +} + void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); + NGLOG_WARNING(Service_FS, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -111,12 +548,12 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { } void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); + NGLOG_DEBUG(Service_FS, "called"); TryLoadRomFS(); if (!romfs) { // TODO (bunnei): Find the right error code to use here - LOG_CRITICAL(Service_FS, "no file system interface available!"); + NGLOG_CRITICAL(Service_FS, "no file system interface available!"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultCode(-1)); return; @@ -125,7 +562,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { // Attempt to open a StorageBackend interface to the RomFS auto storage = romfs->OpenFile({}, {}); if (storage.Failed()) { - LOG_CRITICAL(Service_FS, "no storage interface available!"); + NGLOG_CRITICAL(Service_FS, "no storage interface available!"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(storage.Code()); return; @@ -137,9 +574,8 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { } void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess"); + NGLOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess"); OpenDataStorageByCurrentProcess(ctx); } -} // namespace FileSystem -} // namespace Service +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 56afc4b90..acb78fac1 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -11,8 +11,7 @@ namespace FileSys { class FileSystemBackend; } -namespace Service { -namespace FileSystem { +namespace Service::FileSystem { class FSP_SRV final : public ServiceFramework<FSP_SRV> { public: @@ -22,8 +21,10 @@ public: private: void TryLoadRomFS(); - void Initalize(Kernel::HLERequestContext& ctx); + void Initialize(Kernel::HLERequestContext& ctx); void MountSdCard(Kernel::HLERequestContext& ctx); + void CreateSaveData(Kernel::HLERequestContext& ctx); + void MountSaveData(Kernel::HLERequestContext& ctx); void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenRomStorage(Kernel::HLERequestContext& ctx); @@ -31,5 +32,4 @@ private: std::unique_ptr<FileSys::FileSystemBackend> romfs; }; -} // namespace FileSystem -} // namespace Service +} // namespace Service::FileSystem diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 26593bb0c..94d9fbf25 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -6,14 +6,14 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/service/friend/friend.h" #include "core/hle/service/friend/friend_a.h" +#include "core/hle/service/friend/friend_u.h" -namespace Service { -namespace Friend { +namespace Service::Friend { -void Module::Interface::Unknown(Kernel::HLERequestContext& ctx) { +void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_Friend, "(STUBBED) called"); + NGLOG_WARNING(Service_Friend, "(STUBBED) called"); } Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) @@ -22,7 +22,7 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared<Module>(); std::make_shared<Friend_A>(module)->InstallAsService(service_manager); + std::make_shared<Friend_U>(module)->InstallAsService(service_manager); } -} // namespace Friend -} // namespace Service +} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index ffa498397..4b72115c0 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h @@ -6,8 +6,7 @@ #include "core/hle/service/service.h" -namespace Service { -namespace Friend { +namespace Service::Friend { class Module final { public: @@ -15,7 +14,7 @@ public: public: Interface(std::shared_ptr<Module> module, const char* name); - void Unknown(Kernel::HLERequestContext& ctx); + void CreateFriendService(Kernel::HLERequestContext& ctx); protected: std::shared_ptr<Module> module; @@ -25,5 +24,4 @@ public: /// Registers all Friend services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace Friend -} // namespace Service +} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_a.cpp b/src/core/hle/service/friend/friend_a.cpp index e1f2397c2..a2cc81926 100644 --- a/src/core/hle/service/friend/friend_a.cpp +++ b/src/core/hle/service/friend/friend_a.cpp @@ -4,16 +4,15 @@ #include "core/hle/service/friend/friend_a.h" -namespace Service { -namespace Friend { +namespace Service::Friend { Friend_A::Friend_A(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "friend:a") { static const FunctionInfo functions[] = { - {0, &Friend_A::Unknown, "Unknown"}, + {0, &Friend_A::CreateFriendService, "CreateFriendService"}, + {1, nullptr, "CreateNotificationService"}, }; RegisterHandlers(functions); } -} // namespace Friend -} // namespace Service +} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_a.h b/src/core/hle/service/friend/friend_a.h index 68fa58297..81257583b 100644 --- a/src/core/hle/service/friend/friend_a.h +++ b/src/core/hle/service/friend/friend_a.h @@ -6,13 +6,11 @@ #include "core/hle/service/friend/friend.h" -namespace Service { -namespace Friend { +namespace Service::Friend { class Friend_A final : public Module::Interface { public: explicit Friend_A(std::shared_ptr<Module> module); }; -} // namespace Friend -} // namespace Service +} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_u.cpp b/src/core/hle/service/friend/friend_u.cpp new file mode 100644 index 000000000..90b30883f --- /dev/null +++ b/src/core/hle/service/friend/friend_u.cpp @@ -0,0 +1,18 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/friend/friend_u.h" + +namespace Service::Friend { + +Friend_U::Friend_U(std::shared_ptr<Module> module) + : Module::Interface(std::move(module), "friend:u") { + static const FunctionInfo functions[] = { + {0, &Friend_U::CreateFriendService, "CreateFriendService"}, + {1, nullptr, "CreateNotificationService"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_u.h b/src/core/hle/service/friend/friend_u.h new file mode 100644 index 000000000..0d953d807 --- /dev/null +++ b/src/core/hle/service/friend/friend_u.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/friend/friend.h" + +namespace Service::Friend { + +class Friend_U final : public Module::Interface { +public: + explicit Friend_U(std::shared_ptr<Module> module); +}; + +} // namespace Service::Friend diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index dacd1862d..85ca4bf06 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -14,14 +14,13 @@ #include "core/hle/service/hid/hid.h" #include "core/hle/service/service.h" -namespace Service { -namespace HID { +namespace Service::HID { // Updating period for each HID device. // TODO(shinyquagsire23): These need better values. -constexpr u64 pad_update_ticks = BASE_CLOCK_RATE / 10000; -constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE / 10000; -constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE / 10000; +constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000; +constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000; +constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000; class IAppletResource final : public ServiceFramework<IAppletResource> { public: @@ -45,29 +44,37 @@ public: CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); } + ~IAppletResource() { + CoreTiming::UnscheduleEvent(pad_update_event, 0); + } + private: void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(shared_mem); - LOG_DEBUG(Service_HID, "called"); + NGLOG_DEBUG(Service_HID, "called"); } void LoadInputDevices() { std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); - // TODO(shinyquagsire23): sticks, gyro, touch, mouse, keyboard + std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, + Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END, + sticks.begin(), Input::CreateDevice<Input::AnalogDevice>); + // TODO(shinyquagsire23): gyro, touch, mouse, keyboard } void UpdatePadCallback(u64 userdata, int cycles_late) { - SharedMemory* mem = reinterpret_cast<SharedMemory*>(shared_mem->GetPointer()); + SharedMemory mem{}; + std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory)); if (is_device_reload_pending.exchange(false)) LoadInputDevices(); // Set up controllers as neon red+blue Joy-Con attached to console - ControllerHeader& controller_header = mem->controllers[Controller_Handheld].header; + ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header; controller_header.type = ControllerType_Handheld | ControllerType_JoyconPair; controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent; controller_header.right_color_body = JOYCON_BODY_NEON_RED; @@ -75,67 +82,157 @@ private: controller_header.left_color_body = JOYCON_BODY_NEON_BLUE; controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE; - for (int layoutIdx = 0; layoutIdx < HID_NUM_LAYOUTS; layoutIdx++) { - ControllerLayout& layout = mem->controllers[Controller_Handheld].layouts[layoutIdx]; - layout.header.num_entries = HID_NUM_ENTRIES; - layout.header.max_entry_index = HID_NUM_ENTRIES - 1; - - // HID shared memory stores the state of the past 17 samples in a circlular buffer, - // each with a timestamp in number of samples since boot. - layout.header.timestamp_ticks = CoreTiming::GetTicks(); - layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES; - - ControllerInputEntry& entry = layout.entries[layout.header.latest_entry]; - entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; - entry.timestamp++; - entry.timestamp_2++; // TODO(shinyquagsire23): Is this always identical to timestamp? - - // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future? - // For now everything is just the default handheld layout, but split Joy-Con will - // rotate the face buttons and directions for certain layouts. - ControllerPadState& state = entry.buttons; - using namespace Settings::NativeButton; - state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); - state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); - state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); - state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); - state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus()); - state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus()); - state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); - state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); - state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); - state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); - state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); - state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); - - state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); - state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); - state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); - state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); - - state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); - state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); - state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); - state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); - - state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); - state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); - state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); - state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); - - state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus()); - state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus()); - - // TODO(shinyquagsire23): Analog stick vals - - // TODO(shinyquagsire23): Update pad info proper, (circular buffers, timestamps, - // layouts) + for (size_t controller = 0; controller < mem.controllers.size(); controller++) { + for (int index = 0; index < HID_NUM_LAYOUTS; index++) { + ControllerLayout& layout = mem.controllers[controller].layouts[index]; + layout.header.num_entries = HID_NUM_ENTRIES; + layout.header.max_entry_index = HID_NUM_ENTRIES - 1; + + // HID shared memory stores the state of the past 17 samples in a circlular buffer, + // each with a timestamp in number of samples since boot. + layout.header.timestamp_ticks = CoreTiming::GetTicks(); + layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES; + + ControllerInputEntry& entry = layout.entries[layout.header.latest_entry]; + entry.timestamp++; + // TODO(shinyquagsire23): Is this always identical to timestamp? + entry.timestamp_2++; + + // TODO(shinyquagsire23): More than just handheld input + if (controller != Controller_Handheld) + continue; + + entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; + + // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future? + // For now everything is just the default handheld layout, but split Joy-Con will + // rotate the face buttons and directions for certain layouts. + ControllerPadState& state = entry.buttons; + using namespace Settings::NativeButton; + state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); + state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); + state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); + state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); + state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus()); + state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus()); + state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); + state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); + state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); + state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); + state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); + state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); + + state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); + state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); + state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); + state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); + + state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); + state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); + state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); + state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); + + state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); + state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); + state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); + state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); + + state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus()); + state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus()); + + const auto [stick_l_x_f, stick_l_y_f] = sticks[Joystick_Left]->GetStatus(); + const auto [stick_r_x_f, stick_r_y_f] = sticks[Joystick_Right]->GetStatus(); + entry.joystick_left_x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); + entry.joystick_left_y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); + entry.joystick_right_x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); + entry.joystick_right_y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); + } + } + + // TODO(bunnei): Properly implement the touch screen, the below will just write empty data + + TouchScreen& touchscreen = mem.touchscreen; + const u64 last_entry = touchscreen.header.latest_entry; + const u64 curr_entry = (last_entry + 1) % touchscreen.entries.size(); + const u64 timestamp = CoreTiming::GetTicks(); + const u64 sample_counter = touchscreen.entries[last_entry].header.timestamp + 1; + touchscreen.header.timestamp_ticks = timestamp; + touchscreen.header.num_entries = touchscreen.entries.size(); + touchscreen.header.latest_entry = curr_entry; + touchscreen.header.max_entry_index = touchscreen.entries.size(); + touchscreen.header.timestamp = timestamp; + touchscreen.entries[curr_entry].header.timestamp = sample_counter; + touchscreen.entries[curr_entry].header.num_touches = 0; + + // TODO(shinyquagsire23): Properly implement mouse + Mouse& mouse = mem.mouse; + const u64 last_mouse_entry = mouse.header.latest_entry; + const u64 curr_mouse_entry = (mouse.header.latest_entry + 1) % mouse.entries.size(); + const u64 mouse_sample_counter = mouse.entries[last_mouse_entry].timestamp + 1; + mouse.header.timestamp_ticks = timestamp; + mouse.header.num_entries = mouse.entries.size(); + mouse.header.max_entry_index = mouse.entries.size(); + mouse.header.latest_entry = curr_mouse_entry; + + mouse.entries[curr_mouse_entry].timestamp = mouse_sample_counter; + mouse.entries[curr_mouse_entry].timestamp_2 = mouse_sample_counter; + + // TODO(shinyquagsire23): Properly implement keyboard + Keyboard& keyboard = mem.keyboard; + const u64 last_keyboard_entry = keyboard.header.latest_entry; + const u64 curr_keyboard_entry = + (keyboard.header.latest_entry + 1) % keyboard.entries.size(); + const u64 keyboard_sample_counter = keyboard.entries[last_keyboard_entry].timestamp + 1; + keyboard.header.timestamp_ticks = timestamp; + keyboard.header.num_entries = keyboard.entries.size(); + keyboard.header.latest_entry = last_keyboard_entry; + keyboard.header.max_entry_index = keyboard.entries.size(); + + keyboard.entries[curr_keyboard_entry].timestamp = keyboard_sample_counter; + keyboard.entries[curr_keyboard_entry].timestamp_2 = keyboard_sample_counter; + + // TODO(shinyquagsire23): Figure out what any of these are + for (size_t i = 0; i < mem.unk_input_1.size(); i++) { + UnkInput1& input = mem.unk_input_1[i]; + const u64 last_input_entry = input.header.latest_entry; + const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size(); + const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1; + + input.header.timestamp_ticks = timestamp; + input.header.num_entries = input.entries.size(); + input.header.latest_entry = last_input_entry; + input.header.max_entry_index = input.entries.size(); + + input.entries[curr_input_entry].timestamp = input_sample_counter; + input.entries[curr_input_entry].timestamp_2 = input_sample_counter; } - // TODO(shinyquagsire23): Update touch info + for (size_t i = 0; i < mem.unk_input_2.size(); i++) { + UnkInput2& input = mem.unk_input_2[i]; + + input.header.timestamp_ticks = timestamp; + input.header.num_entries = 17; + input.header.latest_entry = 0; + input.header.max_entry_index = 0; + } + + UnkInput3& input = mem.unk_input_3; + const u64 last_input_entry = input.header.latest_entry; + const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size(); + const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1; + + input.header.timestamp_ticks = timestamp; + input.header.num_entries = input.entries.size(); + input.header.latest_entry = last_input_entry; + input.header.max_entry_index = input.entries.size(); + + input.entries[curr_input_entry].timestamp = input_sample_counter; + input.entries[curr_input_entry].timestamp_2 = input_sample_counter; // TODO(shinyquagsire23): Signal events + std::memcpy(shared_mem->GetPointer(), &mem, sizeof(SharedMemory)); + // Reschedule recurrent event CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); } @@ -150,6 +247,7 @@ private: std::atomic<bool> is_device_reload_pending{true}; std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> buttons; + std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; }; class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { @@ -165,7 +263,7 @@ private: void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } }; @@ -178,24 +276,105 @@ public: {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, {21, &Hid::ActivateMouse, "ActivateMouse"}, {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, + {40, nullptr, "AcquireXpadIdEventHandle"}, + {41, nullptr, "ReleaseXpadIdEventHandle"}, + {51, nullptr, "ActivateXpad"}, + {55, nullptr, "GetXpadIds"}, + {56, nullptr, "ActivateJoyXpad"}, + {58, nullptr, "GetJoyXpadLifoHandle"}, + {59, nullptr, "GetJoyXpadIds"}, + {60, nullptr, "ActivateSixAxisSensor"}, + {61, nullptr, "DeactivateSixAxisSensor"}, + {62, nullptr, "GetSixAxisSensorLifoHandle"}, + {63, nullptr, "ActivateJoySixAxisSensor"}, + {64, nullptr, "DeactivateJoySixAxisSensor"}, + {65, nullptr, "GetJoySixAxisSensorLifoHandle"}, {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, + {67, nullptr, "StopSixAxisSensor"}, + {68, nullptr, "IsSixAxisSensorFusionEnabled"}, + {69, nullptr, "EnableSixAxisSensorFusion"}, + {70, nullptr, "SetSixAxisSensorFusionParameters"}, + {71, nullptr, "GetSixAxisSensorFusionParameters"}, + {72, nullptr, "ResetSixAxisSensorFusionParameters"}, + {73, nullptr, "SetAccelerometerParameters"}, + {74, nullptr, "GetAccelerometerParameters"}, + {75, nullptr, "ResetAccelerometerParameters"}, + {76, nullptr, "SetAccelerometerPlayMode"}, + {77, nullptr, "GetAccelerometerPlayMode"}, + {78, nullptr, "ResetAccelerometerPlayMode"}, {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, + {80, nullptr, "GetGyroscopeZeroDriftMode"}, + {81, nullptr, "ResetGyroscopeZeroDriftMode"}, + {82, nullptr, "IsSixAxisSensorAtRest"}, + {91, nullptr, "ActivateGesture"}, {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, + {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, {103, &Hid::ActivateNpad, "ActivateNpad"}, + {104, nullptr, "DeactivateNpad"}, {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, + {107, nullptr, "DisconnectNpad"}, + {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, - {124, nullptr, "SetNpadJoyAssignmentModeDual"}, + {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, + {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, + {125, nullptr, "MergeSingleJoyAsDualJoy"}, + {126, nullptr, "StartLrAssignmentMode"}, + {127, nullptr, "StopLrAssignmentMode"}, {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, + {129, nullptr, "GetNpadHandheldActivationMode"}, + {130, nullptr, "SwapNpadAssignment"}, + {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, + {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, + {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, {201, &Hid::SendVibrationValue, "SendVibrationValue"}, {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, + {204, nullptr, "PermitVibration"}, + {205, nullptr, "IsVibrationPermitted"}, {206, &Hid::SendVibrationValues, "SendVibrationValues"}, + {207, nullptr, "SendVibrationGcErmCommand"}, + {208, nullptr, "GetActualVibrationGcErmCommand"}, + {209, nullptr, "BeginPermitVibrationSession"}, + {210, nullptr, "EndPermitVibrationSession"}, + {300, nullptr, "ActivateConsoleSixAxisSensor"}, + {301, nullptr, "StartConsoleSixAxisSensor"}, + {302, nullptr, "StopConsoleSixAxisSensor"}, + {303, nullptr, "ActivateSevenSixAxisSensor"}, + {304, nullptr, "StartSevenSixAxisSensor"}, + {305, nullptr, "StopSevenSixAxisSensor"}, + {306, nullptr, "InitializeSevenSixAxisSensor"}, + {307, nullptr, "FinalizeSevenSixAxisSensor"}, + {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, + {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, + {400, nullptr, "IsUsbFullKeyControllerEnabled"}, + {401, nullptr, "EnableUsbFullKeyController"}, + {402, nullptr, "IsUsbFullKeyControllerConnected"}, + {403, nullptr, "HasBattery"}, + {404, nullptr, "HasLeftRightBattery"}, + {405, nullptr, "GetNpadInterfaceType"}, + {406, nullptr, "GetNpadLeftRightInterfaceType"}, + {500, nullptr, "GetPalmaConnectionHandle"}, + {501, nullptr, "InitializePalma"}, + {502, nullptr, "AcquirePalmaOperationCompleteEvent"}, + {503, nullptr, "GetPalmaOperationInfo"}, + {504, nullptr, "PlayPalmaActivity"}, + {505, nullptr, "SetPalmaFrModeType"}, + {506, nullptr, "ReadPalmaStep"}, + {507, nullptr, "EnablePalmaStep"}, + {508, nullptr, "SuspendPalmaStep"}, + {509, nullptr, "ResetPalmaStep"}, + {510, nullptr, "ReadPalmaApplicationSection"}, + {511, nullptr, "WritePalmaApplicationSection"}, + {512, nullptr, "ReadPalmaUniqueCode"}, + {513, nullptr, "SetPalmaUniqueCodeInvalid"}, + {1000, nullptr, "SetNpadCommunicationMode"}, + {1001, nullptr, "GetNpadCommunicationMode"}, }; RegisterHandlers(functions); @@ -216,125 +395,144 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IAppletResource>(applet_resource); - LOG_DEBUG(Service_HID, "called"); + NGLOG_DEBUG(Service_HID, "called"); } void ActivateDebugPad(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void ActivateMouse(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void ActivateKeyboard(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); + } + + void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void ActivateNpad(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(event); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); + } + + void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push(joy_hold_type); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void SendVibrationValue(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); + } + + void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(0); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IActiveVibrationDeviceList>(); - LOG_DEBUG(Service_HID, "called"); + NGLOG_DEBUG(Service_HID, "called"); } void SendVibrationValues(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_HID, "(STUBBED) called"); + NGLOG_WARNING(Service_HID, "(STUBBED) called"); } }; @@ -344,5 +542,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<Hid>()->InstallAsService(service_manager); } -} // namespace HID -} // namespace Service +} // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 3de9adb4b..b499308d6 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -7,8 +7,7 @@ #include "core/hle/service/service.h" #include "core/settings.h" -namespace Service { -namespace HID { +namespace Service::HID { // Begin enums and output structs @@ -49,6 +48,11 @@ enum ControllerConnectionState { ConnectionState_Wired = 1 << 1, }; +enum ControllerJoystick { + Joystick_Left = 0, + Joystick_Right = 1, +}; + enum ControllerID { Controller_Player1 = 0, Controller_Player2 = 1, @@ -64,6 +68,34 @@ enum ControllerID { // End enums and output structs +// Begin UnkInput3 + +struct UnkInput3Header { + u64 timestamp_ticks; + u64 num_entries; + u64 latest_entry; + u64 max_entry_index; +}; +static_assert(sizeof(UnkInput3Header) == 0x20, "HID UnkInput3 header structure has incorrect size"); + +struct UnkInput3Entry { + u64 timestamp; + u64 timestamp_2; + u64 unk_8; + u64 unk_10; + u64 unk_18; +}; +static_assert(sizeof(UnkInput3Entry) == 0x28, "HID UnkInput3 entry structure has incorrect size"); + +struct UnkInput3 { + UnkInput3Header header; + std::array<UnkInput3Entry, 17> entries; + std::array<u8, 0x138> padding; +}; +static_assert(sizeof(UnkInput3) == 0x400, "HID UnkInput3 structure has incorrect size"); + +// End UnkInput3 + // Begin TouchScreen struct TouchScreenHeader { @@ -205,6 +237,52 @@ static_assert(sizeof(Keyboard) == 0x400, "HID keyboard structure has incorrect s // End Keyboard +// Begin UnkInput1 + +struct UnkInput1Header { + u64 timestamp_ticks; + u64 num_entries; + u64 latest_entry; + u64 max_entry_index; +}; +static_assert(sizeof(UnkInput1Header) == 0x20, "HID UnkInput1 header structure has incorrect size"); + +struct UnkInput1Entry { + u64 timestamp; + u64 timestamp_2; + u64 unk_8; + u64 unk_10; + u64 unk_18; +}; +static_assert(sizeof(UnkInput1Entry) == 0x28, "HID UnkInput1 entry structure has incorrect size"); + +struct UnkInput1 { + UnkInput1Header header; + std::array<UnkInput1Entry, 17> entries; + std::array<u8, 0x138> padding; +}; +static_assert(sizeof(UnkInput1) == 0x400, "HID UnkInput1 structure has incorrect size"); + +// End UnkInput1 + +// Begin UnkInput2 + +struct UnkInput2Header { + u64 timestamp_ticks; + u64 num_entries; + u64 latest_entry; + u64 max_entry_index; +}; +static_assert(sizeof(UnkInput2Header) == 0x20, "HID UnkInput2 header structure has incorrect size"); + +struct UnkInput2 { + UnkInput2Header header; + std::array<u8, 0x1E0> padding; +}; +static_assert(sizeof(UnkInput2) == 0x200, "HID UnkInput2 structure has incorrect size"); + +// End UnkInput2 + // Begin Controller struct ControllerMAC { @@ -284,10 +362,10 @@ struct ControllerInputEntry { u64 timestamp; u64 timestamp_2; ControllerPadState buttons; - u32 joystick_left_x; - u32 joystick_left_y; - u32 joystick_right_x; - u32 joystick_right_y; + s32 joystick_left_x; + s32 joystick_left_y; + s32 joystick_right_x; + s32 joystick_right_y; u64 connection_state; }; static_assert(sizeof(ControllerInputEntry) == 0x30, @@ -313,17 +391,12 @@ static_assert(sizeof(Controller) == 0x5000, "HID controller structure has incorr // End Controller struct SharedMemory { - std::array<u8, 0x400> header; + UnkInput3 unk_input_3; TouchScreen touchscreen; Mouse mouse; Keyboard keyboard; - std::array<u8, 0x400> unk_section_1; - std::array<u8, 0x400> unk_section_2; - std::array<u8, 0x400> unk_section_3; - std::array<u8, 0x400> unk_section_4; - std::array<u8, 0x200> unk_section_5; - std::array<u8, 0x200> unk_section_6; - std::array<u8, 0x200> unk_section_7; + std::array<UnkInput1, 4> unk_input_1; + std::array<UnkInput2, 3> unk_input_2; std::array<u8, 0x800> unk_section_8; std::array<u8, 0x4000> controller_serials; std::array<Controller, 10> controllers; @@ -337,5 +410,4 @@ void ReloadInputDevices(); /// Registers all HID services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace HID -} // namespace Service +} // namespace Service::HID diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index b8e53d2c7..46194643e 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -9,8 +9,7 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/service/lm/lm.h" -namespace Service { -namespace LM { +namespace Service::LM { class Logger final : public ServiceFramework<Logger> { public: @@ -142,19 +141,19 @@ private: if (header.IsTailLog()) { switch (header.severity) { case MessageHeader::Severity::Trace: - LOG_TRACE(Debug_Emulated, "%s", log_stream.str().c_str()); + NGLOG_TRACE(Debug_Emulated, "{}", log_stream.str()); break; case MessageHeader::Severity::Info: - LOG_INFO(Debug_Emulated, "%s", log_stream.str().c_str()); + NGLOG_INFO(Debug_Emulated, "{}", log_stream.str()); break; case MessageHeader::Severity::Warning: - LOG_WARNING(Debug_Emulated, "%s", log_stream.str().c_str()); + NGLOG_WARNING(Debug_Emulated, "{}", log_stream.str()); break; case MessageHeader::Severity::Error: - LOG_ERROR(Debug_Emulated, "%s", log_stream.str().c_str()); + NGLOG_ERROR(Debug_Emulated, "{}", log_stream.str()); break; case MessageHeader::Severity::Critical: - LOG_CRITICAL(Debug_Emulated, "%s", log_stream.str().c_str()); + NGLOG_CRITICAL(Debug_Emulated, "{}", log_stream.str()); break; } } @@ -179,7 +178,7 @@ void LM::Initialize(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<Logger>(); - LOG_DEBUG(Service_LM, "called"); + NGLOG_DEBUG(Service_LM, "called"); } LM::LM() : ServiceFramework("lm") { @@ -189,5 +188,4 @@ LM::LM() : ServiceFramework("lm") { RegisterHandlers(functions); } -} // namespace LM -} // namespace Service +} // namespace Service::LM diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h index 371135057..63d6506fe 100644 --- a/src/core/hle/service/lm/lm.h +++ b/src/core/hle/service/lm/lm.h @@ -8,8 +8,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/service.h" -namespace Service { -namespace LM { +namespace Service::LM { class LM final : public ServiceFramework<LM> { public: @@ -23,5 +22,4 @@ private: /// Registers all LM services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace LM -} // namespace Service +} // namespace Service::LM diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp new file mode 100644 index 000000000..b3a85b818 --- /dev/null +++ b/src/core/hle/service/mm/mm_u.cpp @@ -0,0 +1,50 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/service/mm/mm_u.h" + +namespace Service::MM { + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared<MM_U>()->InstallAsService(service_manager); +} + +void MM_U::Initialize(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + min = rp.Pop<u32>(); + max = rp.Pop<u32>(); + current = min; + + NGLOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void MM_U::Get(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(current); +} + +MM_U::MM_U() : ServiceFramework("mm:u") { + static const FunctionInfo functions[] = { + {0, nullptr, "InitializeOld"}, {1, nullptr, "FinalizeOld"}, + {2, nullptr, "SetAndWaitOld"}, {3, nullptr, "GetOld"}, + {4, &MM_U::Initialize, "Initialize"}, {5, nullptr, "Finalize"}, + {6, &MM_U::SetAndWait, "SetAndWait"}, {7, &MM_U::Get, "Get"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::MM diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h new file mode 100644 index 000000000..79eeedf9c --- /dev/null +++ b/src/core/hle/service/mm/mm_u.h @@ -0,0 +1,29 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::MM { + +class MM_U final : public ServiceFramework<MM_U> { +public: + MM_U(); + ~MM_U() = default; + +private: + void Initialize(Kernel::HLERequestContext& ctx); + void SetAndWait(Kernel::HLERequestContext& ctx); + void Get(Kernel::HLERequestContext& ctx); + + u32 min{0}; + u32 max{0}; + u32 current{0}; +}; + +/// Registers all MM services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::MM diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp new file mode 100644 index 000000000..2a9f84037 --- /dev/null +++ b/src/core/hle/service/nfp/nfp.cpp @@ -0,0 +1,162 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" +#include "core/hle/service/hid/hid.h" +#include "core/hle/service/nfp/nfp.h" +#include "core/hle/service/nfp/nfp_user.h" + +namespace Service::NFP { + +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) + : ServiceFramework(name), module(std::move(module)) {} + +class IUser final : public ServiceFramework<IUser> { +public: + IUser() : ServiceFramework("IUser") { + static const FunctionInfo functions[] = { + {0, &IUser::Initialize, "Initialize"}, + {1, nullptr, "Finalize"}, + {2, &IUser::ListDevices, "ListDevices"}, + {3, nullptr, "StartDetection"}, + {4, nullptr, "StopDetection"}, + {5, nullptr, "Mount"}, + {6, nullptr, "Unmount"}, + {7, nullptr, "OpenApplicationArea"}, + {8, nullptr, "GetApplicationArea"}, + {9, nullptr, "SetApplicationArea"}, + {10, nullptr, "Flush"}, + {11, nullptr, "Restore"}, + {12, nullptr, "CreateApplicationArea"}, + {13, nullptr, "GetTagInfo"}, + {14, nullptr, "GetRegisterInfo"}, + {15, nullptr, "GetCommonInfo"}, + {16, nullptr, "GetModelInfo"}, + {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, + {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, + {19, &IUser::GetState, "GetState"}, + {20, &IUser::GetDeviceState, "GetDeviceState"}, + {21, &IUser::GetNpadId, "GetNpadId"}, + {22, nullptr, "GetApplicationArea2"}, + {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, + {24, nullptr, "RecreateApplicationArea"}, + }; + RegisterHandlers(functions); + + activate_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:ActivateEvent"); + deactivate_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); + availability_change_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent"); + } + +private: + enum class State : u32 { + NonInitialized = 0, + Initialized = 1, + }; + + enum class DeviceState : u32 { + Initialized = 0, + }; + + void Initialize(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NFP, "(STUBBED) called"); + + state = State::Initialized; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void ListDevices(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u32 array_size = rp.Pop<u32>(); + + ctx.WriteBuffer(&device_handle, sizeof(device_handle)); + + NGLOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); + } + + void AttachActivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(activate_event); + } + + void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(deactivate_event); + } + + void GetState(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NFP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(state)); + } + + void GetDeviceState(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NFP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(device_state)); + } + + void GetNpadId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(npad_id); + } + + void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(availability_change_event); + } + + const u64 device_handle{0xDEAD}; + const HID::ControllerID npad_id{HID::Controller_Player1}; + State state{State::NonInitialized}; + DeviceState device_state{DeviceState::Initialized}; + Kernel::SharedPtr<Kernel::Event> activate_event; + Kernel::SharedPtr<Kernel::Event> deactivate_event; + Kernel::SharedPtr<Kernel::Event> availability_change_event; +}; + +void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { + NGLOG_DEBUG(Service_NFP, "called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IUser>(); +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + auto module = std::make_shared<Module>(); + std::make_shared<NFP_User>(module)->InstallAsService(service_manager); +} + +} // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h new file mode 100644 index 000000000..262a666cb --- /dev/null +++ b/src/core/hle/service/nfp/nfp.h @@ -0,0 +1,26 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::NFP { + +class Module final { +public: + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name); + + void CreateUserInterface(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + }; +}; + +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp new file mode 100644 index 000000000..b608fe693 --- /dev/null +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -0,0 +1,17 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nfp/nfp_user.h" + +namespace Service::NFP { + +NFP_User::NFP_User(std::shared_ptr<Module> module) + : Module::Interface(std::move(module), "nfp:user") { + static const FunctionInfo functions[] = { + {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h new file mode 100644 index 000000000..700043114 --- /dev/null +++ b/src/core/hle/service/nfp/nfp_user.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/nfp/nfp.h" + +namespace Service::NFP { + +class NFP_User final : public Module::Interface { +public: + explicit NFP_User(std::shared_ptr<Module> module); +}; + +} // namespace Service::NFP diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index e6f05eae5..62489c7fe 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -9,8 +9,7 @@ #include "core/hle/service/nifm/nifm_s.h" #include "core/hle/service/nifm/nifm_u.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { class IScanRequest final : public ServiceFramework<IScanRequest> { public: @@ -32,14 +31,14 @@ public: {0, &IRequest::GetRequestState, "GetRequestState"}, {1, &IRequest::GetResult, "GetResult"}, {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"}, - {3, nullptr, "Cancel"}, + {3, &IRequest::Cancel, "Cancel"}, {4, nullptr, "Submit"}, {5, nullptr, "SetRequirement"}, {6, nullptr, "SetRequirementPreset"}, {8, nullptr, "SetPriority"}, {9, nullptr, "SetNetworkProfileId"}, {10, nullptr, "SetRejectable"}, - {11, nullptr, "SetConnectionConfirmationOption"}, + {11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"}, {12, nullptr, "SetPersistent"}, {13, nullptr, "SetInstant"}, {14, nullptr, "SetSustainable"}, @@ -63,24 +62,37 @@ public: private: void GetRequestState(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); } + void GetResult(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0); } + void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2, 2}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(event1, event2); } + void Cancel(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + Kernel::SharedPtr<Kernel::Event> event1, event2; }; @@ -96,13 +108,56 @@ public: } }; +class IGeneralService final : public ServiceFramework<IGeneralService> { +public: + IGeneralService(); + +private: + void GetClientId(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(0); + } + void CreateScanRequest(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IScanRequest>(); + + NGLOG_DEBUG(Service_NIFM, "called"); + } + void CreateRequest(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IRequest>(); + + NGLOG_DEBUG(Service_NIFM, "called"); + } + void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<INetworkProfile>(); + + NGLOG_DEBUG(Service_NIFM, "called"); + } +}; + IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { static const FunctionInfo functions[] = { {1, &IGeneralService::GetClientId, "GetClientId"}, {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, {4, &IGeneralService::CreateRequest, "CreateRequest"}, - {6, nullptr, "GetCurrentNetworkProfile"}, - {7, nullptr, "EnumerateNetworkInterfaces"}, + {5, nullptr, "GetCurrentNetworkProfile"}, + {6, nullptr, "EnumerateNetworkInterfaces"}, + {7, nullptr, "EnumerateNetworkProfiles"}, {8, nullptr, "GetNetworkProfile"}, {9, nullptr, "SetNetworkProfile"}, {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, @@ -137,51 +192,28 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { RegisterHandlers(functions); } -void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.Push<u64>(0); -} - -void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) { +void Module::Interface::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IScanRequest>(); - - LOG_DEBUG(Service_NIFM, "called"); + rb.PushIpcInterface<IGeneralService>(); + NGLOG_DEBUG(Service_NIFM, "called"); } -void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) { +void Module::Interface::CreateGeneralService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IRequest>(); - - LOG_DEBUG(Service_NIFM, "called"); -} - -void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IGeneralService>(); + NGLOG_DEBUG(Service_NIFM, "called"); } -void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<INetworkProfile>(); - - LOG_DEBUG(Service_NIFM, "called"); -} +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) + : ServiceFramework(name), module(std::move(module)) {} void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<NIFM_A>()->InstallAsService(service_manager); - std::make_shared<NIFM_S>()->InstallAsService(service_manager); - std::make_shared<NIFM_U>()->InstallAsService(service_manager); + auto module = std::make_shared<Module>(); + std::make_shared<NIFM_A>(module)->InstallAsService(service_manager); + std::make_shared<NIFM_S>(module)->InstallAsService(service_manager); + std::make_shared<NIFM_U>(module)->InstallAsService(service_manager); } -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h index 6edbfe4a4..4ad3f3bcf 100644 --- a/src/core/hle/service/nifm/nifm.h +++ b/src/core/hle/service/nifm/nifm.h @@ -6,22 +6,22 @@ #include "core/hle/service/service.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { -class IGeneralService final : public ServiceFramework<IGeneralService> { +class Module final { public: - IGeneralService(); - -private: - void GetClientId(Kernel::HLERequestContext& ctx); - void CreateScanRequest(Kernel::HLERequestContext& ctx); - void CreateRequest(Kernel::HLERequestContext& ctx); - void RemoveNetworkProfile(Kernel::HLERequestContext& ctx); - void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx); + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name); + + void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); + void CreateGeneralService(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + }; }; void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm_a.cpp b/src/core/hle/service/nifm/nifm_a.cpp index ee61d8ff4..b7f296a20 100644 --- a/src/core/hle/service/nifm/nifm_a.cpp +++ b/src/core/hle/service/nifm/nifm_a.cpp @@ -2,29 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/nifm/nifm.h" #include "core/hle/service/nifm/nifm_a.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { -void NIFM_A::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); - LOG_DEBUG(Service_NIFM, "called"); -} - -void NIFM_A::CreateGeneralService(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); - LOG_DEBUG(Service_NIFM, "called"); -} - -NIFM_A::NIFM_A() : ServiceFramework("nifm:a") { +NIFM_A::NIFM_A(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:a") { static const FunctionInfo functions[] = { {4, &NIFM_A::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, {5, &NIFM_A::CreateGeneralService, "CreateGeneralService"}, @@ -32,5 +14,4 @@ NIFM_A::NIFM_A() : ServiceFramework("nifm:a") { RegisterHandlers(functions); } -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm_a.h b/src/core/hle/service/nifm/nifm_a.h index 06a92a93c..c3ba33110 100644 --- a/src/core/hle/service/nifm/nifm_a.h +++ b/src/core/hle/service/nifm/nifm_a.h @@ -4,21 +4,13 @@ #pragma once -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/service/service.h" +#include "core/hle/service/nifm/nifm.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { -class NIFM_A final : public ServiceFramework<NIFM_A> { +class NIFM_A final : public Module::Interface { public: - NIFM_A(); - ~NIFM_A() = default; - -private: - void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); - void CreateGeneralService(Kernel::HLERequestContext& ctx); + explicit NIFM_A(std::shared_ptr<Module> module); }; -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm_s.cpp b/src/core/hle/service/nifm/nifm_s.cpp index c38b2a4c7..96e3c0cee 100644 --- a/src/core/hle/service/nifm/nifm_s.cpp +++ b/src/core/hle/service/nifm/nifm_s.cpp @@ -2,29 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/nifm/nifm.h" #include "core/hle/service/nifm/nifm_s.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { -void NIFM_S::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); - LOG_DEBUG(Service_NIFM, "called"); -} - -void NIFM_S::CreateGeneralService(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); - LOG_DEBUG(Service_NIFM, "called"); -} - -NIFM_S::NIFM_S() : ServiceFramework("nifm:s") { +NIFM_S::NIFM_S(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:s") { static const FunctionInfo functions[] = { {4, &NIFM_S::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, {5, &NIFM_S::CreateGeneralService, "CreateGeneralService"}, @@ -32,5 +14,4 @@ NIFM_S::NIFM_S() : ServiceFramework("nifm:s") { RegisterHandlers(functions); } -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm_s.h b/src/core/hle/service/nifm/nifm_s.h index d11a1ec29..8d1635a5d 100644 --- a/src/core/hle/service/nifm/nifm_s.h +++ b/src/core/hle/service/nifm/nifm_s.h @@ -4,21 +4,13 @@ #pragma once -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/service/service.h" +#include "core/hle/service/nifm/nifm.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { -class NIFM_S final : public ServiceFramework<NIFM_S> { +class NIFM_S final : public Module::Interface { public: - NIFM_S(); - ~NIFM_S() = default; - -private: - void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); - void CreateGeneralService(Kernel::HLERequestContext& ctx); + explicit NIFM_S(std::shared_ptr<Module> module); }; -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm_u.cpp b/src/core/hle/service/nifm/nifm_u.cpp index a5895c13c..8cb75b903 100644 --- a/src/core/hle/service/nifm/nifm_u.cpp +++ b/src/core/hle/service/nifm/nifm_u.cpp @@ -2,29 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/nifm/nifm.h" #include "core/hle/service/nifm/nifm_u.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { -void NIFM_U::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); - LOG_DEBUG(Service_NIFM, "called"); -} - -void NIFM_U::CreateGeneralService(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); - LOG_DEBUG(Service_NIFM, "called"); -} - -NIFM_U::NIFM_U() : ServiceFramework("nifm:u") { +NIFM_U::NIFM_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:u") { static const FunctionInfo functions[] = { {4, &NIFM_U::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, {5, &NIFM_U::CreateGeneralService, "CreateGeneralService"}, @@ -32,5 +14,4 @@ NIFM_U::NIFM_U() : ServiceFramework("nifm:u") { RegisterHandlers(functions); } -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm_u.h b/src/core/hle/service/nifm/nifm_u.h index da40b604f..def9726b1 100644 --- a/src/core/hle/service/nifm/nifm_u.h +++ b/src/core/hle/service/nifm/nifm_u.h @@ -4,21 +4,13 @@ #pragma once -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/service/service.h" +#include "core/hle/service/nifm/nifm.h" -namespace Service { -namespace NIFM { +namespace Service::NIFM { -class NIFM_U final : public ServiceFramework<NIFM_U> { +class NIFM_U final : public Module::Interface { public: - NIFM_U(); - ~NIFM_U() = default; - -private: - void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); - void CreateGeneralService(Kernel::HLERequestContext& ctx); + explicit NIFM_U(std::shared_ptr<Module> module); }; -} // namespace NIFM -} // namespace Service +} // namespace Service::NIFM diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 45681c50f..89c703310 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -5,12 +5,10 @@ #include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/pl_u.h" -namespace Service { -namespace NS { +namespace Service::NS { void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<PL_U>()->InstallAsService(service_manager); } -} // namespace NS -} // namespace Service +} // namespace Service::NS diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index a4b7e3ded..b81ca8f1e 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -6,11 +6,9 @@ #include "core/hle/service/service.h" -namespace Service { -namespace NS { +namespace Service::NS { /// Registers all NS services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace NS -} // namespace Service +} // namespace Service::NS diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index cc9d03a7c..636af9a1e 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -4,11 +4,11 @@ #include "common/common_paths.h" #include "common/file_util.h" +#include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/ns/pl_u.h" -namespace Service { -namespace NS { +namespace Service::NS { struct FontRegion { u32 offset; @@ -32,10 +32,13 @@ enum class LoadState : u32 { PL_U::PL_U() : ServiceFramework("pl:u") { static const FunctionInfo functions[] = { + {0, &PL_U::RequestLoad, "RequestLoad"}, {1, &PL_U::GetLoadState, "GetLoadState"}, {2, &PL_U::GetSize, "GetSize"}, {3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, - {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}}; + {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, + {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, + }; RegisterHandlers(functions); // Attempt to load shared font data from disk @@ -43,21 +46,30 @@ PL_U::PL_U() : ServiceFramework("pl:u") { FileUtil::CreateFullPath(filepath); // Create path if not already created FileUtil::IOFile file(filepath, "rb"); + shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); if (file.IsOpen()) { // Read shared font data ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); - shared_font = std::make_shared<std::vector<u8>>(static_cast<size_t>(file.GetSize())); file.ReadBytes(shared_font->data(), shared_font->size()); } else { - LOG_WARNING(Service_NS, "Unable to load shared font: %s", filepath.c_str()); + NGLOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath); } } +void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u32 shared_font_type{rp.Pop<u32>()}; + + NGLOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 font_id{rp.Pop<u32>()}; - LOG_DEBUG(Service_NS, "called, font_id=%d", font_id); + NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(static_cast<u32>(LoadState::Done)); @@ -67,7 +79,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 font_id{rp.Pop<u32>()}; - LOG_DEBUG(Service_NS, "called, font_id=%d", font_id); + NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(SHARED_FONT_REGIONS[font_id].size); @@ -77,35 +89,56 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 font_id{rp.Pop<u32>()}; - LOG_DEBUG(Service_NS, "called, font_id=%d", font_id); + NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(SHARED_FONT_REGIONS[font_id].offset); } void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { - if (shared_font != nullptr) { - // TODO(bunnei): This is a less-than-ideal solution to load a RAM dump of the Switch shared - // font data. This (likely) relies on exact address, size, and offsets from the original - // dump. In the future, we need to replace this with a more robust solution. - - // Map backing memory for the font data - Kernel::g_current_process->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, shared_font, 0, - SHARED_FONT_MEM_SIZE, - Kernel::MemoryState::Shared); - - // Create shared font memory object - shared_font_mem = Kernel::SharedMemory::Create( - Kernel::g_current_process, SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, - Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, - "PL_U:shared_font_mem"); - } + // TODO(bunnei): This is a less-than-ideal solution to load a RAM dump of the Switch shared + // font data. This (likely) relies on exact address, size, and offsets from the original + // dump. In the future, we need to replace this with a more robust solution. + + // Map backing memory for the font data + Core::CurrentProcess()->vm_manager.MapMemoryBlock( + SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared); + + // Create shared font memory object + shared_font_mem = Kernel::SharedMemory::Create( + Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, + Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, + "PL_U:shared_font_mem"); - LOG_DEBUG(Service_NS, "called"); + NGLOG_DEBUG(Service_NS, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(shared_font_mem); } -} // namespace NS -} // namespace Service +void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for + NGLOG_DEBUG(Service_NS, "called, language_code=%lx", language_code); + IPC::ResponseBuilder rb{ctx, 4}; + std::vector<u32> font_codes; + std::vector<u32> font_offsets; + std::vector<u32> font_sizes; + + // TODO(ogniK): Have actual priority order + for (size_t i = 0; i < SHARED_FONT_REGIONS.size(); i++) { + font_codes.push_back(static_cast<u32>(i)); + font_offsets.push_back(SHARED_FONT_REGIONS[i].offset); + font_sizes.push_back(SHARED_FONT_REGIONS[i].size); + } + + ctx.WriteBuffer(font_codes.data(), font_codes.size(), 0); + ctx.WriteBuffer(font_offsets.data(), font_offsets.size(), 1); + ctx.WriteBuffer(font_sizes.data(), font_sizes.size(), 2); + + rb.Push(RESULT_SUCCESS); + rb.Push<u8>(static_cast<u8>(LoadState::Done)); // Fonts Loaded + rb.Push<u32>(static_cast<u32>(font_codes.size())); +} + +} // namespace Service::NS diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index 7a4766338..fcc2acab7 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h @@ -8,8 +8,7 @@ #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/service.h" -namespace Service { -namespace NS { +namespace Service::NS { class PL_U final : public ServiceFramework<PL_U> { public: @@ -17,10 +16,12 @@ public: ~PL_U() = default; private: + void RequestLoad(Kernel::HLERequestContext& ctx); void GetLoadState(Kernel::HLERequestContext& ctx); void GetSize(Kernel::HLERequestContext& ctx); void GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx); void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); + void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx); /// Handle to shared memory region designated for a shared font Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; @@ -29,5 +30,4 @@ private: std::shared_ptr<std::vector<u8>> shared_font; }; -} // namespace NS -} // namespace Service +} // namespace Service::NS diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index cdc25b059..0f02a1a18 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -9,9 +9,7 @@ #include "common/common_types.h" #include "common/swap.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { /// Represents an abstract nvidia device node. It is to be subclassed by concrete device nodes to /// implement the ioctl interface. @@ -38,6 +36,4 @@ public: virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) = 0; }; -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 7674d332d..103e66d0c 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -10,32 +10,27 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; } void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) { VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); - LOG_WARNING(Service, - "Drawing from address %llx offset %08X Width %u Height %u Stride %u Format %u", - addr, offset, width, height, stride, format); + NGLOG_WARNING(Service, + "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", + addr, offset, width, height, stride, format); - using PixelFormat = RendererBase::FramebufferInfo::PixelFormat; - using Flags = NVFlinger::BufferQueue::BufferTransformFlags; - const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV); - const RendererBase::FramebufferInfo framebuffer_info{ - addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical}; + using PixelFormat = Tegra::FramebufferConfig::PixelFormat; + const Tegra::FramebufferConfig framebuffer{ + addr, offset, width, height, stride, static_cast<PixelFormat>(format), transform}; Core::System::GetInstance().perf_stats.EndGameFrame(); - VideoCore::g_renderer->SwapBuffers(framebuffer_info); + + VideoCore::g_renderer->SwapBuffers(framebuffer); } -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 66f56f23d..3d3979723 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -10,9 +10,7 @@ #include "core/hle/service/nvdrv/devices/nvdevice.h" #include "core/hle/service/nvflinger/buffer_queue.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { class nvmap; @@ -31,6 +29,4 @@ private: std::shared_ptr<nvmap> nvmap_dev; }; -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 9892402fa..c1eea861d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -9,13 +9,11 @@ #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" #include "core/hle/service/nvdrv/devices/nvmap.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx", - command.raw, input.size(), output.size()); + NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", + command.raw, input.size(), output.size()); switch (static_cast<IoctlCommand>(command.raw)) { case IoctlCommand::IocInitalizeExCommand: @@ -28,23 +26,29 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vecto return BindChannel(input, output); case IoctlCommand::IocGetVaRegionsCommand: return GetVARegions(input, output); + case IoctlCommand::IocUnmapBufferCommand: + return UnmapBuffer(input, output); } + + if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) + return Remap(input, output); + + UNIMPLEMENTED_MSG("Unimplemented ioctl command"); return 0; } u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { IoctlInitalizeEx params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x%x", params.big_page_size); - std::memcpy(output.data(), ¶ms, output.size()); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); return 0; } u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { IoctlAllocSpace params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_DEBUG(Service_NVDRV, "called, pages=%x, page_size=%x, flags=%x", params.pages, - params.page_size, params.flags); + NGLOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, + params.page_size, params.flags); auto& gpu = Core::System::GetInstance().GPU(); const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)}; @@ -58,15 +62,45 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& return 0; } +u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { + size_t num_entries = input.size() / sizeof(IoctlRemapEntry); + + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries); + + std::vector<IoctlRemapEntry> entries(num_entries); + std::memcpy(entries.data(), input.data(), input.size()); + + auto& gpu = Core::System::GetInstance().GPU(); + + for (const auto& entry : entries) { + NGLOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", + entry.offset, entry.nvmap_handle, entry.pages); + Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10; + + auto object = nvmap_dev->GetObject(entry.nvmap_handle); + ASSERT(object); + + ASSERT(object->status == nvmap::Object::Status::Allocated); + + u64 size = static_cast<u64>(entry.pages) << 0x10; + ASSERT(size <= object->size); + + Tegra::GPUVAddr returned = gpu.memory_manager->MapBufferEx(object->addr, offset, size); + ASSERT(returned == offset); + } + std::memcpy(output.data(), entries.data(), output.size()); + return 0; +} + u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { IoctlMapBufferEx params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_DEBUG(Service_NVDRV, - "called, flags=%x, nvmap_handle=%x, buffer_offset=%" PRIu64 ", mapping_size=%" PRIu64 - ", offset=%" PRIu64, - params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size, - params.offset); + NGLOG_DEBUG(Service_NVDRV, + "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" + ", offset={}", + params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size, + params.offset); if (!params.nvmap_handle) { return 0; @@ -75,6 +109,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou auto object = nvmap_dev->GetObject(params.nvmap_handle); ASSERT(object); + // We can only map objects that have already been assigned a CPU address. + ASSERT(object->status == nvmap::Object::Status::Allocated); + + ASSERT(params.buffer_offset == 0); + + // The real nvservices doesn't make a distinction between handles and ids, and + // object can only have one handle and it will be the same as its id. Assert that this is the + // case to prevent unexpected behavior. + ASSERT(object->id == params.nvmap_handle); + auto& gpu = Core::System::GetInstance().GPU(); if (params.flags & 1) { @@ -83,6 +127,37 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou params.offset = gpu.memory_manager->MapBufferEx(object->addr, object->size); } + // Create a new mapping entry for this operation. + ASSERT_MSG(buffer_mappings.find(params.offset) == buffer_mappings.end(), + "Offset is already mapped"); + + BufferMapping mapping{}; + mapping.nvmap_handle = params.nvmap_handle; + mapping.offset = params.offset; + mapping.size = object->size; + + buffer_mappings[params.offset] = mapping; + + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + +u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlUnmapBuffer params{}; + std::memcpy(¶ms, input.data(), input.size()); + + NGLOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); + + auto& gpu = Core::System::GetInstance().GPU(); + + auto itr = buffer_mappings.find(params.offset); + + ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping"); + + params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size); + + buffer_mappings.erase(itr->second.offset); + std::memcpy(output.data(), ¶ms, output.size()); return 0; } @@ -90,17 +165,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { IoctlBindChannel params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_DEBUG(Service_NVDRV, "called, fd=%x", params.fd); + NGLOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); channel = params.fd; - std::memcpy(output.data(), ¶ms, output.size()); return 0; } u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { IoctlGetVaRegions params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr=%" PRIu64 ", buf_size=%x", - params.buf_addr, params.buf_size); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, + params.buf_size); params.buf_size = 0x30; params.regions[0].offset = 0x04000000; @@ -115,6 +189,4 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o return 0; } -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index f8a60cce7..d4c4b4db3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -5,15 +5,14 @@ #pragma once #include <memory> +#include <unordered_map> #include <utility> #include <vector> #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { class nvmap; @@ -28,9 +27,11 @@ private: enum class IoctlCommand : u32_le { IocInitalizeExCommand = 0x40284109, IocAllocateSpaceCommand = 0xC0184102, + IocRemapCommand = 0x00000014, IocMapBufferExCommand = 0xC0284106, IocBindChannelCommand = 0x40044101, IocGetVaRegionsCommand = 0xC0404108, + IocUnmapBufferCommand = 0xC0084105, }; struct IoctlInitalizeEx { @@ -56,6 +57,16 @@ private: }; static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); + struct IoctlRemapEntry { + u16_le flags; + u16_le kind; + u32_le nvmap_handle; + INSERT_PADDING_WORDS(1); + u32_le offset; + u32_le pages; + }; + static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); + struct IoctlMapBufferEx { u32_le flags; // bit0: fixed_offset, bit2: cacheable u32_le kind; // -1 is default @@ -67,6 +78,11 @@ private: }; static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); + struct IoctlUnmapBuffer { + u64_le offset; + }; + static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); + struct IoctlBindChannel { u32_le fd; }; @@ -89,17 +105,26 @@ private: static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, "IoctlGetVaRegions is incorrect size"); + struct BufferMapping { + u64 offset; + u64 size; + u32 nvmap_handle; + }; + + /// Map containing the nvmap object mappings in GPU memory. + std::unordered_map<u64, BufferMapping> buffer_mappings; + u32 channel{}; u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); + u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); + u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); std::shared_ptr<nvmap> nvmap_dev; }; -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 45711d686..7872d1e09 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -6,29 +6,31 @@ #include "common/logging/log.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx", - command.raw, input.size(), output.size()); + NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", + command.raw, input.size(), output.size()); switch (static_cast<IoctlCommand>(command.raw)) { case IoctlCommand::IocGetConfigCommand: return NvOsGetConfigU32(input, output); case IoctlCommand::IocCtrlEventWaitCommand: - return IocCtrlEventWait(input, output); + return IocCtrlEventWait(input, output, false); + case IoctlCommand::IocCtrlEventWaitAsyncCommand: + return IocCtrlEventWait(input, output, true); + case IoctlCommand::IocCtrlEventRegisterCommand: + return IocCtrlEventRegister(input, output); } - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; } u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { IocGetConfigParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "called, setting=%s!%s", params.domain_str.data(), - params.param_str.data()); + NGLOG_DEBUG(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), + params.param_str.data()); if (!strcmp(params.domain_str.data(), "nv")) { if (!strcmp(params.param_str.data(), "NV_MEMORY_PROFILER")) { @@ -38,7 +40,7 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& } else if (!strcmp(params.param_str.data(), "NVRM_GPU_PREVENT_USE")) { params.config_str[0] = '0'; } else { - params.config_str[0] = '0'; + params.config_str[0] = '\0'; } } else { UNIMPLEMENTED(); // unknown domain? Only nv has been seen so far on hardware @@ -47,11 +49,13 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& return 0; } -u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output) { +u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, + bool is_async) { IocCtrlEventWaitParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, syncpt_id=%u threshold=%u timeout=%d", - params.syncpt_id, params.threshold, params.timeout); + NGLOG_WARNING(Service_NVDRV, + "(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}", + params.syncpt_id, params.threshold, params.timeout, is_async); // TODO(Subv): Implement actual syncpt waiting. params.value = 0; @@ -59,6 +63,10 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& return 0; } -} // namespace Devices -} // namespace Nvidia -} // namespace Service +u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + // TODO(bunnei): Implement this. + return 0; +} + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 0ca01aa6d..090261a60 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -11,9 +11,7 @@ #include "common/common_types.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { class nvhost_ctrl final : public nvdevice { public: @@ -28,12 +26,64 @@ private: IocSyncptIncrCommand = 0x40040015, IocSyncptWaitCommand = 0xC00C0016, IocModuleMutexCommand = 0x40080017, - IocModuleRegRDWRCommand = 0xC008010E, + IocModuleRegRDWRCommand = 0xC0180018, IocSyncptWaitexCommand = 0xC0100019, IocSyncptReadMaxCommand = 0xC008001A, - IocCtrlEventWaitCommand = 0xC010001D, IocGetConfigCommand = 0xC183001B, + IocCtrlEventSignalCommand = 0xC004001C, + IocCtrlEventWaitCommand = 0xC010001D, + IocCtrlEventWaitAsyncCommand = 0xC010001E, + IocCtrlEventRegisterCommand = 0xC004001F, + IocCtrlEventUnregisterCommand = 0xC0040020, + IocCtrlEventKillCommand = 0x40080021, + }; + struct IocSyncptReadParams { + u32_le id; + u32_le value; + }; + static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); + + struct IocSyncptIncrParams { + u32_le id; + }; + static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); + + struct IocSyncptWaitParams { + u32_le id; + u32_le thresh; + s32_le timeout; + }; + static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); + + struct IocModuleMutexParams { + u32_le id; + u32_le lock; // (0 = unlock and 1 = lock) + }; + static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); + + struct IocModuleRegRDWRParams { + u32_le id; + u32_le num_offsets; + u32_le block_size; + u32_le offsets; + u32_le values; + u32_le write; + }; + static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); + + struct IocSyncptWaitexParams { + u32_le id; + u32_le thresh; + s32_le timeout; + u32_le value; }; + static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); + + struct IocSyncptReadMaxParams { + u32_le id; + u32_le value; + }; + static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); struct IocGetConfigParams { std::array<char, 0x41> domain_str; @@ -42,6 +92,12 @@ private: }; static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); + struct IocCtrlEventSignalParams { + u32_le user_event_id; + }; + static_assert(sizeof(IocCtrlEventSignalParams) == 4, + "IocCtrlEventSignalParams is incorrect size"); + struct IocCtrlEventWaitParams { u32_le syncpt_id; u32_le threshold; @@ -50,11 +106,37 @@ private: }; static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); + struct IocCtrlEventWaitAsyncParams { + u32_le syncpt_id; + u32_le threshold; + u32_le timeout; + u32_le value; + }; + static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, + "IocCtrlEventWaitAsyncParams is incorrect size"); + + struct IocCtrlEventRegisterParams { + u32_le user_event_id; + }; + static_assert(sizeof(IocCtrlEventRegisterParams) == 4, + "IocCtrlEventRegisterParams is incorrect size"); + + struct IocCtrlEventUnregisterParams { + u32_le user_event_id; + }; + static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, + "IocCtrlEventUnregisterParams is incorrect size"); + + struct IocCtrlEventKill { + u64_le user_events; + }; + static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); + u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); - u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output); + u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); + + u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); }; -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 3b353d742..0abc0de83 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -7,13 +7,11 @@ #include "common/logging/log.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx", - command.raw, input.size(), output.size()); + NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", + command.raw, input.size(), output.size()); switch (static_cast<IoctlCommand>(command.raw)) { case IoctlCommand::IocGetCharacteristicsCommand: @@ -26,13 +24,19 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec return ZCullGetCtxSize(input, output); case IoctlCommand::IocZcullGetInfo: return ZCullGetInfo(input, output); + case IoctlCommand::IocZbcSetTable: + return ZBCSetTable(input, output); + case IoctlCommand::IocZbcQueryTable: + return ZBCQueryTable(input, output); + case IoctlCommand::IocFlushL2: + return FlushL2(input, output); } - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; } u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IoctlCharacteristics params{}; std::memcpy(¶ms, input.data(), input.size()); params.gc.arch = 0x120; @@ -79,14 +83,19 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { IoctlGpuGetTpcMasksArgs params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, mask=0x%x, mask_buf_addr=0x%" PRIx64, - params.mask_buf_size, params.mask_buf_addr); + NGLOG_INFO(Service_NVDRV, "called, mask=0x{:X}, mask_buf_addr=0x{:X}", params.mask_buf_size, + params.mask_buf_addr); + // TODO(ogniK): Confirm value on hardware + if (params.mask_buf_size) + params.tpc_mask_size = 4 * 1; // 4 * num_gpc + else + params.tpc_mask_size = 0; std::memcpy(output.data(), ¶ms, sizeof(params)); return 0; } u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IoctlActiveSlotMask params{}; std::memcpy(¶ms, input.data(), input.size()); params.slot = 0x07; @@ -96,7 +105,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector } u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IoctlZcullGetCtxSize params{}; std::memcpy(¶ms, input.data(), input.size()); params.size = 0x1; @@ -105,7 +114,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u } u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IoctlNvgpuGpuZcullGetInfoArgs params{}; std::memcpy(¶ms, input.data(), input.size()); params.width_align_pixels = 0x20; @@ -122,6 +131,31 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& return 0; } -} // namespace Devices -} // namespace Nvidia -} // namespace Service +u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + IoctlZbcSetTable params{}; + std::memcpy(¶ms, input.data(), input.size()); + // TODO(ogniK): What does this even actually do? + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + +u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + IoctlZbcQueryTable params{}; + std::memcpy(¶ms, input.data(), input.size()); + // TODO : To implement properly + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + +u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + IoctlFlushL2 params{}; + std::memcpy(¶ms, input.data(), input.size()); + // TODO : To implement properly + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index dc0476993..f09113e67 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -9,9 +9,7 @@ #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { class nvhost_ctrl_gpu final : public nvdevice { public: @@ -27,6 +25,19 @@ private: IocGetActiveSlotMaskCommand = 0x80084714, IocZcullGetCtxSizeCommand = 0x80044701, IocZcullGetInfo = 0x80284702, + IocZbcSetTable = 0x402C4703, + IocZbcQueryTable = 0xC0344704, + IocFlushL2 = 0x40084707, + IocInvalICache = 0x4008470D, + IocSetMmudebugMode = 0x4008470E, + IocSetSmDebugMode = 0x4010470F, + IocWaitForPause = 0xC0084710, + IocGetTcpExceptionEnStatus = 0x80084711, + IocNumVsms = 0x80084712, + IocVsmsMapping = 0xC0044713, + IocGetErrorChannelUserData = 0xC008471B, + IocGetGpuTime = 0xC010471C, + IocGetCpuTimeCorrelationInfo = 0xC108471D, }; struct IoctlGpuCharacteristics { @@ -88,7 +99,7 @@ private: /// [in] pointer to TPC mask buffer. It will receive one 32-bit TPC mask per GPC or 0 if /// GPC is not enabled or not present. This parameter is ignored if mask_buf_size is 0. u64_le mask_buf_addr; - u64_le unk; // Nintendo add this? + u64_le tpc_mask_size; // Nintendo add this? }; static_assert(sizeof(IoctlGpuGetTpcMasksArgs) == 24, "IoctlGpuGetTpcMasksArgs is incorrect size"); @@ -119,12 +130,40 @@ private: static_assert(sizeof(IoctlNvgpuGpuZcullGetInfoArgs) == 40, "IoctlNvgpuGpuZcullGetInfoArgs is incorrect size"); + struct IoctlZbcSetTable { + u32_le color_ds[4]; + u32_le color_l2[4]; + u32_le depth; + u32_le format; + u32_le type; + }; + static_assert(sizeof(IoctlZbcSetTable) == 44, "IoctlZbcSetTable is incorrect size"); + + struct IoctlZbcQueryTable { + u32_le color_ds[4]; + u32_le color_l2[4]; + u32_le depth; + u32_le ref_cnt; + u32_le format; + u32_le type; + u32_le index_size; + }; + static_assert(sizeof(IoctlZbcQueryTable) == 52, "IoctlZbcQueryTable is incorrect size"); + + struct IoctlFlushL2 { + u32_le flush; // l2_flush | l2_invalidate << 1 | fb_flush << 2 + u32_le reserved; + }; + static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); + u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); + u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); + u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); + u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); }; -} // namespace Devices -} // namespace Nvidia -} // namespace Service + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index da44c65f3..79aab87f9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -9,13 +9,11 @@ #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx", - command.raw, input.size(), output.size()); + NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", + command.raw, input.size(), output.size()); switch (static_cast<IoctlCommand>(command.raw)) { case IoctlCommand::IocSetNVMAPfdCommand: @@ -34,6 +32,10 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u return AllocGPFIFOEx2(input, output); case IoctlCommand::IocAllocObjCtxCommand: return AllocateObjectContext(input, output); + case IoctlCommand::IocChannelGetWaitbaseCommand: + return GetWaitbase(input, output); + case IoctlCommand::IocChannelSetTimeoutCommand: + return ChannelSetTimeout(input, output); } if (command.group == NVGPU_IOCTL_MAGIC) { @@ -42,30 +44,28 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u } } - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; }; u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { IoctlSetNvmapFD params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_DEBUG(Service_NVDRV, "called, fd=%x", params.nvmap_fd); + NGLOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); nvmap_fd = params.nvmap_fd; - std::memcpy(output.data(), ¶ms, output.size()); return 0; } u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IoctlClientData params{}; std::memcpy(¶ms, input.data(), input.size()); user_data = params.data; - std::memcpy(output.data(), ¶ms, output.size()); return 0; } u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IoctlClientData params{}; std::memcpy(¶ms, input.data(), input.size()); params.data = user_data; @@ -75,8 +75,8 @@ u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& out u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { std::memcpy(&zcull_params, input.data(), input.size()); - LOG_DEBUG(Service_NVDRV, "called, gpu_va=%" PRIx64 ", mode=%x", zcull_params.gpu_va, - zcull_params.mode); + NGLOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, + zcull_params.mode); std::memcpy(output.data(), &zcull_params, output.size()); return 0; } @@ -84,26 +84,26 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { IoctlSetErrorNotifier params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset=%" PRIx64 ", size=%" PRIx64 ", mem=%x", - params.offset, params.size, params.mem); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", + params.offset, params.size, params.mem); std::memcpy(output.data(), ¶ms, output.size()); return 0; } u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { std::memcpy(&channel_priority, input.data(), input.size()); - LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority=%x", channel_priority); - std::memcpy(output.data(), &channel_priority, output.size()); + NGLOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); return 0; } u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { IoctlAllocGpfifoEx2 params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, - "(STUBBED) called, num_entries=%x, flags=%x, unk0=%x, unk1=%x, unk2=%x, unk3=%x", - params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, - params.unk3); + NGLOG_WARNING(Service_NVDRV, + "(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, " + "unk1={:X}, unk2={:X}, unk3={:X}", + params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, + params.unk3); params.fence_out.id = 0; params.fence_out.value = 0; std::memcpy(output.data(), ¶ms, output.size()); @@ -113,8 +113,8 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { IoctlAllocObjCtx params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num=%x, flags=%x", params.class_num, - params.flags); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, + params.flags); params.obj_id = 0x0; std::memcpy(output.data(), ¶ms, output.size()); return 0; @@ -125,8 +125,8 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp UNIMPLEMENTED(); IoctlSubmitGpfifo params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo=%" PRIx64 ", num_entries=%x, flags=%x", - params.gpfifo, params.num_entries, params.flags); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", + params.gpfifo, params.num_entries, params.flags); auto entries = std::vector<IoctlGpfifoEntry>(); entries.resize(params.num_entries); @@ -142,6 +142,20 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp return 0; } -} // namespace Devices -} // namespace Nvidia -} // namespace Service +u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlGetWaitbase params{}; + std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); + NGLOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); + params.value = 0; // Seems to be hard coded at 0 + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + +u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlChannelSetTimeout params{}; + std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); + NGLOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); + 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 e7e9a0088..56b5ed60d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -10,9 +10,7 @@ #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { class nvmap; constexpr u32 NVGPU_IOCTL_MAGIC('H'); @@ -28,13 +26,23 @@ public: private: enum class IoctlCommand : u32_le { IocSetNVMAPfdCommand = 0x40044801, + IocAllocGPFIFOCommand = 0x40084805, IocSetClientDataCommand = 0x40084714, IocGetClientDataCommand = 0x80084715, IocZCullBind = 0xc010480b, IocSetErrorNotifierCommand = 0xC018480C, IocChannelSetPriorityCommand = 0x4004480D, + IocEnableCommand = 0x0000480E, + IocDisableCommand = 0x0000480F, + IocPreemptCommand = 0x00004810, + IocForceResetCommand = 0x00004811, + IocEventIdControlCommand = 0x40084812, + IocGetErrorNotificationCommand = 0xC0104817, + IocAllocGPFIFOExCommand = 0x40204818, IocAllocGPFIFOEx2Command = 0xC020481A, IocAllocObjCtxCommand = 0xC0104809, + IocChannelGetWaitbaseCommand = 0xC0080003, + IocChannelSetTimeoutCommand = 0x40044803, }; enum class CtxObjects : u32_le { @@ -51,6 +59,17 @@ private: }; static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); + struct IoctlChannelSetTimeout { + u32_le timeout; + }; + static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); + + struct IoctlAllocGPFIFO { + u32_le num_entries; + u32_le flags; + }; + static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); + struct IoctlClientData { u64_le data; }; @@ -71,12 +90,45 @@ private: }; static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); + struct IoctlChannelSetPriority { + u32_le priority; + }; + static_assert(sizeof(IoctlChannelSetPriority) == 4, + "IoctlChannelSetPriority is incorrect size"); + + struct IoctlEventIdControl { + u32_le cmd; // 0=disable, 1=enable, 2=clear + u32_le id; + }; + static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); + + struct IoctlGetErrorNotification { + u64_le timestamp; + u32_le info32; + u16_le info16; + u16_le status; // always 0xFFFF + }; + static_assert(sizeof(IoctlGetErrorNotification) == 16, + "IoctlGetErrorNotification is incorrect size"); + struct IoctlFence { u32_le id; u32_le value; }; static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size"); + struct IoctlAllocGpfifoEx { + u32_le num_entries; + u32_le flags; + u32_le unk0; + u32_le unk1; + u32_le unk2; + u32_le unk3; + u32_le unk4; + u32_le unk5; + }; + static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); + struct IoctlAllocGpfifoEx2 { u32_le num_entries; // in u32_le flags; // in @@ -119,7 +171,13 @@ private: IoctlFence fence_out; // returned new fence object for others to wait on }; static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(IoctlFence), - "submit_gpfifo is incorrect size"); + "IoctlSubmitGpfifo is incorrect size"); + + struct IoctlGetWaitbase { + u32 unknown; // seems to be ignored? Nintendo added this + u32 value; + }; + static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); u32_le nvmap_fd{}; u64_le user_data{}; @@ -135,10 +193,10 @@ private: u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); + u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); + u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); std::shared_ptr<nvmap> nvmap_dev; }; -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp new file mode 100644 index 000000000..0b6c22898 --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" + +namespace Service::Nvidia::Devices { + +u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { + NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", + command.raw, input.size(), output.size()); + + switch (static_cast<IoctlCommand>(command.raw)) { + case IoctlCommand::IocSetNVMAPfdCommand: + return SetNVMAPfd(input, output); + } + + UNIMPLEMENTED_MSG("Unimplemented ioctl"); + return 0; +} + +u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlSetNvmapFD params{}; + std::memcpy(¶ms, input.data(), input.size()); + NGLOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); + nvmap_fd = params.nvmap_fd; + return 0; +} + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h new file mode 100644 index 000000000..0192aecdd --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -0,0 +1,38 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <cstdlib> +#include <cstring> +#include <vector> +#include "common/common_types.h" +#include "core/hle/service/nvdrv/devices/nvdevice.h" + +namespace Service::Nvidia::Devices { + +class nvhost_nvdec final : public nvdevice { +public: + nvhost_nvdec() = default; + ~nvhost_nvdec() override = default; + + u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; + +private: + enum class IoctlCommand : u32_le { + IocSetNVMAPfdCommand = 0x40044801, + }; + + struct IoctlSetNvmapFD { + u32_le nvmap_fd; + }; + static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); + + u32_le nvmap_fd{}; + + u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); +}; + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index b3842eb4c..23fe98190 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -9,9 +9,7 @@ #include "common/logging/log.h" #include "core/hle/service/nvdrv/devices/nvmap.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { VAddr nvmap::GetObjectAddress(u32 handle) const { auto object = GetObject(handle); @@ -32,9 +30,11 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& o return IocFromId(input, output); case IoctlCommand::Param: return IocParam(input, output); + case IoctlCommand::Free: + return IocFree(input, output); } - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; } @@ -47,11 +47,12 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { object->id = next_id++; object->size = params.size; object->status = Object::Status::Created; + object->refcount = 1; u32 handle = next_handle++; handles[handle] = std::move(object); - LOG_DEBUG(Service_NVDRV, "size=0x%08X", params.size); + NGLOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); params.handle = handle; @@ -72,7 +73,7 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { object->addr = params.addr; object->status = Object::Status::Allocated; - LOG_DEBUG(Service_NVDRV, "called, addr=0x%" PRIx64, params.addr); + NGLOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); std::memcpy(output.data(), ¶ms, sizeof(params)); return 0; @@ -82,7 +83,7 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { IocGetIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "called"); + NGLOG_WARNING(Service_NVDRV, "called"); auto object = GetObject(params.handle); ASSERT(object); @@ -97,12 +98,14 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { IocFromIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); auto itr = std::find_if(handles.begin(), handles.end(), [&](const auto& entry) { return entry.second->id == params.id; }); ASSERT(itr != handles.end()); + itr->second->refcount++; + // Return the existing handle instead of creating a new one. params.handle = itr->first; @@ -116,25 +119,25 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { IocParamParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "(STUBBED) called type=%u", params.type); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); auto object = GetObject(params.handle); ASSERT(object); ASSERT(object->status == Object::Status::Allocated); - switch (static_cast<ParamTypes>(params.type)) { + switch (static_cast<ParamTypes>(params.param)) { case ParamTypes::Size: - params.value = object->size; + params.result = object->size; break; case ParamTypes::Alignment: - params.value = object->align; + params.result = object->align; break; case ParamTypes::Heap: // TODO(Subv): Seems to be a hardcoded value? - params.value = 0x40000000; + params.result = 0x40000000; break; case ParamTypes::Kind: - params.value = object->kind; + params.result = object->kind; break; default: UNIMPLEMENTED(); @@ -144,6 +147,34 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { return 0; } -} // namespace Devices -} // namespace Nvidia -} // namespace Service +u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { + enum FreeFlags { + Freed = 0, + NotFreedYet = 1, + }; + + IocFreeParams params; + std::memcpy(¶ms, input.data(), sizeof(params)); + + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + + auto itr = handles.find(params.handle); + ASSERT(itr != handles.end()); + + itr->second->refcount--; + + params.refcount = itr->second->refcount; + params.size = itr->second->size; + + if (itr->second->refcount == 0) + params.flags = Freed; + else + params.flags = NotFreedYet; + + handles.erase(params.handle); + + std::memcpy(output.data(), ¶ms, sizeof(params)); + return 0; +} + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 4681e438b..39fafaa7c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -12,9 +12,7 @@ #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -namespace Service { -namespace Nvidia { -namespace Devices { +namespace Service::Nvidia::Devices { class nvmap final : public nvdevice { public: @@ -36,6 +34,7 @@ public: u8 kind; VAddr addr; Status status; + u32 refcount; }; std::shared_ptr<Object> GetObject(u32 handle) const { @@ -60,16 +59,25 @@ private: Create = 0xC0080101, FromId = 0xC0080103, Alloc = 0xC0200104, + Free = 0xC0180105, Param = 0xC00C0109, - GetId = 0xC008010E + GetId = 0xC008010E, }; - struct IocCreateParams { // Input u32_le size; // Output u32_le handle; }; + static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); + + struct IocFromIdParams { + // Input + u32_le id; + // Output + u32_le handle; + }; + static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); struct IocAllocParams { // Input @@ -81,36 +89,40 @@ private: INSERT_PADDING_BYTES(7); u64_le addr; }; + static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); - struct IocGetIdParams { - // Output - u32_le id; - // Input + struct IocFreeParams { u32_le handle; + INSERT_PADDING_BYTES(4); + u64_le refcount; + u32_le size; + u32_le flags; }; + static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); - struct IocFromIdParams { + struct IocParamParams { // Input - u32_le id; - // Output u32_le handle; + u32_le param; + // Output + u32_le result; }; + static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); - struct IocParamParams { + struct IocGetIdParams { + // Output + u32_le id; // Input u32_le handle; - u32_le type; - // Output - u32_le value; }; + static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); + u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); }; -} // namespace Devices -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index c70370f1f..45d2862ef 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -9,11 +9,10 @@ #include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" -namespace Service { -namespace Nvidia { +namespace Service::Nvidia { void NVDRV::Open(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); const auto& buffer = ctx.ReadBuffer(); std::string device_name(buffer.begin(), buffer.end()); @@ -26,7 +25,7 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) { } void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IPC::RequestParser rp{ctx}; u32 fd = rp.Pop<u32>(); @@ -42,7 +41,7 @@ void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { } void NVDRV::Close(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NVDRV, "called"); + NGLOG_DEBUG(Service_NVDRV, "called"); IPC::RequestParser rp{ctx}; u32 fd = rp.Pop<u32>(); @@ -54,7 +53,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) { } void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); @@ -64,7 +63,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; u32 fd = rp.Pop<u32>(); u32 event_id = rp.Pop<u32>(); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd=%x, event_id=%x", fd, event_id); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); IPC::ResponseBuilder rb{ctx, 3, 1}; rb.Push(RESULT_SUCCESS); @@ -76,14 +75,14 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; pid = rp.Pop<u64>(); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x%" PRIx64, pid); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); } void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -96,7 +95,14 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) {2, &NVDRV::Close, "Close"}, {3, &NVDRV::Initialize, "Initialize"}, {4, &NVDRV::QueryEvent, "QueryEvent"}, + {5, nullptr, "MapSharedMem"}, + {6, nullptr, "GetStatus"}, + {7, nullptr, "ForceSetClientPID"}, {8, &NVDRV::SetClientPID, "SetClientPID"}, + {9, nullptr, "DumpGraphicsMemoryInfo"}, + {10, nullptr, "InitializeDevtools"}, + {11, nullptr, "Ioctl2"}, + {12, nullptr, "Ioctl3"}, {13, &NVDRV::FinishInitialize, "FinishInitialize"}, }; RegisterHandlers(functions); @@ -104,5 +110,4 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) query_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NVDRV::query_event"); } -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index daf2302af..959b5ba29 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -10,8 +10,7 @@ #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/service.h" -namespace Service { -namespace Nvidia { +namespace Service::Nvidia { class NVDRV final : public ServiceFramework<NVDRV> { public: @@ -34,5 +33,4 @@ private: Kernel::SharedPtr<Kernel::Event> query_event; }; -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index ea00240e6..cc5cfe34e 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -9,13 +9,13 @@ #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" +#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" #include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvmemp.h" -namespace Service { -namespace Nvidia { +namespace Service::Nvidia { std::weak_ptr<Module> nvdrv; @@ -37,11 +37,12 @@ Module::Module() { devices["/dev/nvmap"] = nvmap_dev; devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(); + devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(); } u32 Module::Open(std::string device_name) { - ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device %s", - device_name.c_str()); + ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", + device_name); auto device = devices[device_name]; u32 fd = next_fd++; @@ -69,5 +70,4 @@ ResultCode Module::Close(u32 fd) { return RESULT_SUCCESS; } -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 6a55ff96d..579940817 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -10,8 +10,7 @@ #include "common/common_types.h" #include "core/hle/service/service.h" -namespace Service { -namespace Nvidia { +namespace Service::Nvidia { namespace Devices { class nvdevice; @@ -61,5 +60,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager); extern std::weak_ptr<Module> nvdrv; -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp index 5a13732c7..9ca6e5512 100644 --- a/src/core/hle/service/nvdrv/nvmemp.cpp +++ b/src/core/hle/service/nvdrv/nvmemp.cpp @@ -8,24 +8,22 @@ #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvmemp.h" -namespace Service { -namespace Nvidia { +namespace Service::Nvidia { NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { static const FunctionInfo functions[] = { - {0, &NVMEMP::Unknown0, "Unknown0"}, - {1, &NVMEMP::Unknown1, "Unknown1"}, + {0, &NVMEMP::Cmd0, "Cmd0"}, + {1, &NVMEMP::Cmd1, "Cmd1"}, }; RegisterHandlers(functions); } -void NVMEMP::Unknown0(Kernel::HLERequestContext& ctx) { +void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } -void NVMEMP::Unknown1(Kernel::HLERequestContext& ctx) { +void NVMEMP::Cmd1(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h index a6b5fbb82..dfdcabf4a 100644 --- a/src/core/hle/service/nvdrv/nvmemp.h +++ b/src/core/hle/service/nvdrv/nvmemp.h @@ -6,8 +6,7 @@ #include "core/hle/service/service.h" -namespace Service { -namespace Nvidia { +namespace Service::Nvidia { class NVMEMP final : public ServiceFramework<NVMEMP> { public: @@ -15,9 +14,8 @@ public: ~NVMEMP() = default; private: - void Unknown0(Kernel::HLERequestContext& ctx); - void Unknown1(Kernel::HLERequestContext& ctx); + void Cmd0(Kernel::HLERequestContext& ctx); + void Cmd1(Kernel::HLERequestContext& ctx); }; -} // namespace Nvidia -} // namespace Service +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index ff7b6b039..49e88b394 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -23,29 +23,33 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { buffer.igbp_buffer = igbp_buffer; buffer.status = Buffer::Status::Free; - LOG_WARNING(Service, "Adding graphics buffer %u", slot); + NGLOG_WARNING(Service, "Adding graphics buffer {}", slot); queue.emplace_back(buffer); + + if (buffer_wait_event) { + buffer_wait_event->Signal(); + } } -u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { +boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { // Only consider free buffers. Buffers become free once again after they've been Acquired // and Released by the compositor, see the NVFlinger::Compose method. - if (buffer.status != Buffer::Status::Free) + if (buffer.status != Buffer::Status::Free) { return false; + } // Make sure that the parameters match. - auto& igbp_buffer = buffer.igbp_buffer; - return igbp_buffer.format == pixel_format && igbp_buffer.width == width && - igbp_buffer.height == height; + return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height; }); + if (itr == queue.end()) { - LOG_CRITICAL(Service_NVDRV, "no free buffers for pixel_format=%d, width=%d, height=%d", - pixel_format, width, height); - itr = queue.begin(); + return boost::none; } + buffer_wait_event = nullptr; + itr->status = Buffer::Status::Dequeued; return itr->slot; } @@ -83,10 +87,14 @@ void BufferQueue::ReleaseBuffer(u32 slot) { ASSERT(itr != queue.end()); ASSERT(itr->status == Buffer::Status::Acquired); itr->status = Buffer::Status::Free; + + if (buffer_wait_event) { + buffer_wait_event->Signal(); + } } u32 BufferQueue::Query(QueryType type) { - LOG_WARNING(Service, "(STUBBED) called type=%u", static_cast<u32>(type)); + NGLOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); switch (type) { case QueryType::NativeWindowFormat: // TODO(Subv): Use an enum for this @@ -98,5 +106,10 @@ u32 BufferQueue::Query(QueryType type) { return 0; } +void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event) { + ASSERT_MSG(!buffer_wait_event, "buffer_wait_event only supports a single waiting thread!"); + buffer_wait_event = std::move(wait_event); +} + } // namespace NVFlinger } // namespace Service diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index ef9732769..1de5767cb 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -47,6 +47,8 @@ public: ~BufferQueue() = default; enum class BufferTransformFlags : u32 { + /// No transform flags are set + Unset = 0x00, /// Flip source image horizontally (around the vertical axis) FlipH = 0x01, /// Flip source image vertically (around the horizontal axis) @@ -69,12 +71,13 @@ public: }; void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); - u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); + boost::optional<u32> DequeueBuffer(u32 width, u32 height); const IGBPBuffer& RequestBuffer(u32 slot) const; void QueueBuffer(u32 slot, BufferTransformFlags transform); boost::optional<const Buffer&> AcquireBuffer(); void ReleaseBuffer(u32 slot); u32 Query(QueryType type); + void SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event); u32 GetId() const { return id; @@ -90,6 +93,9 @@ private: std::vector<Buffer> queue; Kernel::SharedPtr<Kernel::Event> native_handle; + + /// Used to signal waiting thread when no buffers are available + Kernel::SharedPtr<Kernel::Event> buffer_wait_event; }; } // namespace NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index a54239b0f..5c50ed601 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -5,6 +5,7 @@ #include <algorithm> #include "common/alignment.h" +#include "common/microprofile.h" #include "common/scope_exit.h" #include "core/core.h" #include "core/core_timing.h" @@ -15,11 +16,10 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" -namespace Service { -namespace NVFlinger { +namespace Service::NVFlinger { constexpr size_t SCREEN_REFRESH_RATE = 60; -constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); +constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); NVFlinger::NVFlinger() { // Add the different displays to the list of displays. @@ -48,7 +48,7 @@ NVFlinger::~NVFlinger() { } u64 NVFlinger::OpenDisplay(const std::string& name) { - LOG_WARNING(Service, "Opening display %s", name.c_str()); + NGLOG_WARNING(Service, "Opening display {}", name); // TODO(Subv): Currently we only support the Default display. ASSERT(name == "Default"); @@ -128,6 +128,8 @@ void NVFlinger::Compose() { // Search for a queued buffer and acquire it auto buffer = buffer_queue->AcquireBuffer(); + MicroProfileFlip(); + if (buffer == boost::none) { // There was no queued buffer to draw, render previous frame Core::System::GetInstance().perf_stats.EndGameFrame(); @@ -150,6 +152,9 @@ void NVFlinger::Compose() { igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform); buffer_queue->ReleaseBuffer(buffer->slot); + + // TODO(Subv): Figure out when we should actually signal this event. + buffer_queue->GetNativeHandle()->Signal(); } } @@ -159,5 +164,4 @@ Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event"); } -} // namespace NVFlinger -} // namespace Service +} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 3126018ad..2c908297b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -12,8 +12,7 @@ namespace CoreTiming { struct EventType; } -namespace Service { -namespace NVFlinger { +namespace Service::NVFlinger { class BufferQueue; @@ -80,5 +79,4 @@ private: CoreTiming::EventType* composition_event; }; -} // namespace NVFlinger -} // namespace Service +} // namespace Service::NVFlinger diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp new file mode 100644 index 000000000..dd20d5ae7 --- /dev/null +++ b/src/core/hle/service/pctl/module.cpp @@ -0,0 +1,146 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/pctl/module.h" +#include "core/hle/service/pctl/pctl.h" + +namespace Service::PCTL { + +class IParentalControlService final : public ServiceFramework<IParentalControlService> { +public: + IParentalControlService() : ServiceFramework("IParentalControlService") { + static const FunctionInfo functions[] = { + {1, &IParentalControlService::Initialize, "Initialize"}, + {1001, nullptr, "CheckFreeCommunicationPermission"}, + {1002, nullptr, "ConfirmLaunchApplicationPermission"}, + {1003, nullptr, "ConfirmResumeApplicationPermission"}, + {1004, nullptr, "ConfirmSnsPostPermission"}, + {1005, nullptr, "ConfirmSystemSettingsPermission"}, + {1006, nullptr, "IsRestrictionTemporaryUnlocked"}, + {1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, + {1008, nullptr, "EnterRestrictedSystemSettings"}, + {1009, nullptr, "LeaveRestrictedSystemSettings"}, + {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, + {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, + {1012, nullptr, "GetRestrictedFeatures"}, + {1013, nullptr, "ConfirmStereoVisionPermission"}, + {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, + {1015, nullptr, "ConfirmPlayableApplicationVideo"}, + {1031, nullptr, "IsRestrictionEnabled"}, + {1032, nullptr, "GetSafetyLevel"}, + {1033, nullptr, "SetSafetyLevel"}, + {1034, nullptr, "GetSafetyLevelSettings"}, + {1035, nullptr, "GetCurrentSettings"}, + {1036, nullptr, "SetCustomSafetyLevelSettings"}, + {1037, nullptr, "GetDefaultRatingOrganization"}, + {1038, nullptr, "SetDefaultRatingOrganization"}, + {1039, nullptr, "GetFreeCommunicationApplicationListCount"}, + {1042, nullptr, "AddToFreeCommunicationApplicationList"}, + {1043, nullptr, "DeleteSettings"}, + {1044, nullptr, "GetFreeCommunicationApplicationList"}, + {1045, nullptr, "UpdateFreeCommunicationApplicationList"}, + {1046, nullptr, "DisableFeaturesForReset"}, + {1047, nullptr, "NotifyApplicationDownloadStarted"}, + {1061, nullptr, "ConfirmStereoVisionRestrictionConfigurable"}, + {1062, nullptr, "GetStereoVisionRestriction"}, + {1063, nullptr, "SetStereoVisionRestriction"}, + {1064, nullptr, "ResetConfirmedStereoVisionPermission"}, + {1065, nullptr, "IsStereoVisionPermitted"}, + {1201, nullptr, "UnlockRestrictionTemporarily"}, + {1202, nullptr, "UnlockSystemSettingsRestriction"}, + {1203, nullptr, "SetPinCode"}, + {1204, nullptr, "GenerateInquiryCode"}, + {1205, nullptr, "CheckMasterKey"}, + {1206, nullptr, "GetPinCodeLength"}, + {1207, nullptr, "GetPinCodeChangedEvent"}, + {1208, nullptr, "GetPinCode"}, + {1403, nullptr, "IsPairingActive"}, + {1406, nullptr, "GetSettingsLastUpdated"}, + {1411, nullptr, "GetPairingAccountInfo"}, + {1421, nullptr, "GetAccountNickname"}, + {1424, nullptr, "GetAccountState"}, + {1432, nullptr, "GetSynchronizationEvent"}, + {1451, nullptr, "StartPlayTimer"}, + {1452, nullptr, "StopPlayTimer"}, + {1453, nullptr, "IsPlayTimerEnabled"}, + {1454, nullptr, "GetPlayTimerRemainingTime"}, + {1455, nullptr, "IsRestrictedByPlayTimer"}, + {1456, nullptr, "GetPlayTimerSettings"}, + {1457, nullptr, "GetPlayTimerEventToRequestSuspension"}, + {1458, nullptr, "IsPlayTimerAlarmDisabled"}, + {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"}, + {1472, nullptr, "CancelNetworkRequest"}, + {1473, nullptr, "GetUnlinkedEvent"}, + {1474, nullptr, "ClearUnlinkedEvent"}, + {1601, nullptr, "DisableAllFeatures"}, + {1602, nullptr, "PostEnableAllFeatures"}, + {1603, nullptr, "IsAllFeaturesDisabled"}, + {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"}, + {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"}, + {1903, nullptr, "GetExemptApplicationListCountForDebug"}, + {1904, nullptr, "GetExemptApplicationListForDebug"}, + {1905, nullptr, "UpdateExemptApplicationListForDebug"}, + {1906, nullptr, "AddToExemptApplicationListForDebug"}, + {1907, nullptr, "DeleteFromExemptApplicationListForDebug"}, + {1908, nullptr, "ClearExemptApplicationListForDebug"}, + {1941, nullptr, "DeletePairing"}, + {1951, nullptr, "SetPlayTimerSettingsForDebug"}, + {1952, nullptr, "GetPlayTimerSpentTimeForTest"}, + {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"}, + {2001, nullptr, "RequestPairingAsync"}, + {2002, nullptr, "FinishRequestPairing"}, + {2003, nullptr, "AuthorizePairingAsync"}, + {2004, nullptr, "FinishAuthorizePairing"}, + {2005, nullptr, "RetrievePairingInfoAsync"}, + {2006, nullptr, "FinishRetrievePairingInfo"}, + {2007, nullptr, "UnlinkPairingAsync"}, + {2008, nullptr, "FinishUnlinkPairing"}, + {2009, nullptr, "GetAccountMiiImageAsync"}, + {2010, nullptr, "FinishGetAccountMiiImage"}, + {2011, nullptr, "GetAccountMiiImageContentTypeAsync"}, + {2012, nullptr, "FinishGetAccountMiiImageContentType"}, + {2013, nullptr, "SynchronizeParentalControlSettingsAsync"}, + {2014, nullptr, "FinishSynchronizeParentalControlSettings"}, + {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"}, + {2016, nullptr, "RequestUpdateExemptionListAsync"}, + }; + RegisterHandlers(functions); + } + +private: + void Initialize(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_PCTL, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 0}; + rb.Push(RESULT_SUCCESS); + } +}; + +void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IParentalControlService>(); + NGLOG_DEBUG(Service_PCTL, "called"); +} + +void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IParentalControlService>(); + NGLOG_DEBUG(Service_PCTL, "called"); +} + +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) + : ServiceFramework(name), module(std::move(module)) {} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + auto module = std::make_shared<Module>(); + std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager); + std::make_shared<PCTL>(module, "pctl:a")->InstallAsService(service_manager); + std::make_shared<PCTL>(module, "pctl:r")->InstallAsService(service_manager); + std::make_shared<PCTL>(module, "pctl:s")->InstallAsService(service_manager); +} + +} // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h new file mode 100644 index 000000000..68da628a8 --- /dev/null +++ b/src/core/hle/service/pctl/module.h @@ -0,0 +1,28 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::PCTL { + +class Module final { +public: + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name); + + void CreateService(Kernel::HLERequestContext& ctx); + void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + }; +}; + +/// Registers all PCTL services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp index 692b27a71..de2741d66 100644 --- a/src/core/hle/service/pctl/pctl.cpp +++ b/src/core/hle/service/pctl/pctl.cpp @@ -3,14 +3,15 @@ // Refer to the license.txt file included. #include "core/hle/service/pctl/pctl.h" -#include "core/hle/service/pctl/pctl_a.h" -namespace Service { -namespace PCTL { +namespace Service::PCTL { -void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<PCTL_A>()->InstallAsService(service_manager); +PCTL::PCTL(std::shared_ptr<Module> module, const char* name) + : Module::Interface(std::move(module), name) { + static const FunctionInfo functions[] = { + {0, &PCTL::CreateService, "CreateService"}, + {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, + }; + RegisterHandlers(functions); } - -} // namespace PCTL -} // namespace Service +} // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h index 5fa67dd1b..8ddf69128 100644 --- a/src/core/hle/service/pctl/pctl.h +++ b/src/core/hle/service/pctl/pctl.h @@ -4,13 +4,13 @@ #pragma once -#include "core/hle/service/service.h" +#include "core/hle/service/pctl/module.h" -namespace Service { -namespace PCTL { +namespace Service::PCTL { -/// Registers all PCTL services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +class PCTL final : public Module::Interface { +public: + explicit PCTL(std::shared_ptr<Module> module, const char* name); +}; -} // namespace PCTL -} // namespace Service +} // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/pctl_a.cpp b/src/core/hle/service/pctl/pctl_a.cpp deleted file mode 100644 index c65fffa07..000000000 --- a/src/core/hle/service/pctl/pctl_a.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/pctl/pctl_a.h" - -namespace Service { -namespace PCTL { - -class IParentalControlService final : public ServiceFramework<IParentalControlService> { -public: - IParentalControlService() : ServiceFramework("IParentalControlService") {} -}; - -void PCTL_A::GetService(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IParentalControlService>(); - LOG_DEBUG(Service_PCTL, "called"); -} - -PCTL_A::PCTL_A() : ServiceFramework("pctl:a") { - static const FunctionInfo functions[] = { - {0, &PCTL_A::GetService, "GetService"}, - }; - RegisterHandlers(functions); -} - -} // namespace PCTL -} // namespace Service diff --git a/src/core/hle/service/pctl/pctl_a.h b/src/core/hle/service/pctl/pctl_a.h deleted file mode 100644 index a89c8d07d..000000000 --- a/src/core/hle/service/pctl/pctl_a.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -namespace Service { -namespace PCTL { - -class PCTL_A final : public ServiceFramework<PCTL_A> { -public: - PCTL_A(); - ~PCTL_A() = default; - -private: - void GetService(Kernel::HLERequestContext& ctx); -}; - -} // namespace PCTL -} // namespace Service diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp new file mode 100644 index 000000000..eaf30ee6b --- /dev/null +++ b/src/core/hle/service/prepo/prepo.cpp @@ -0,0 +1,43 @@ +#include <cinttypes> +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" +#include "core/hle/service/prepo/prepo.h" + +namespace Service::PlayReport { +PlayReport::PlayReport(const char* name) : ServiceFramework(name) { + static const FunctionInfo functions[] = { + {10100, nullptr, "SaveReport"}, + {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, + {10200, nullptr, "RequestImmediateTransmission"}, + {10300, nullptr, "GetTransmissionStatus"}, + {20100, nullptr, "SaveSystemReport"}, + {20200, nullptr, "SetOperationMode"}, + {20101, nullptr, "SaveSystemReportWithUser"}, + {30100, nullptr, "ClearStorage"}, + {40100, nullptr, "IsUserAgreementCheckEnabled"}, + {40101, nullptr, "SetUserAgreementCheckEnabled"}, + {90100, nullptr, "GetStorageUsage"}, + {90200, nullptr, "GetStatistics"}, + {90201, nullptr, "GetThroughputHistory"}, + {90300, nullptr, "GetLastUploadError"}, + }; + RegisterHandlers(functions); +}; + +void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { + // TODO(ogniK): Do we want to add play report? + NGLOG_WARNING(Service_PREPO, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +}; + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared<PlayReport>("prepo:a")->InstallAsService(service_manager); + std::make_shared<PlayReport>("prepo:m")->InstallAsService(service_manager); + std::make_shared<PlayReport>("prepo:s")->InstallAsService(service_manager); + std::make_shared<PlayReport>("prepo:u")->InstallAsService(service_manager); +} + +} // namespace Service::PlayReport diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h new file mode 100644 index 000000000..3708e0dcb --- /dev/null +++ b/src/core/hle/service/prepo/prepo.h @@ -0,0 +1,23 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> +#include <string> +#include "core/hle/kernel/event.h" +#include "core/hle/service/service.h" + +namespace Service::PlayReport { + +class PlayReport final : public ServiceFramework<PlayReport> { +public: + explicit PlayReport(const char* name); + ~PlayReport() = default; + +private: + void SaveReportWithUser(Kernel::HLERequestContext& ctx); +}; + +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::PlayReport diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 6a2d6a4ef..bdd9eb5a5 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -7,6 +7,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/core.h" #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" @@ -19,19 +20,26 @@ #include "core/hle/service/aoc/aoc_u.h" #include "core/hle/service/apm/apm.h" #include "core/hle/service/audio/audio.h" +#include "core/hle/service/bcat/bcat.h" +#include "core/hle/service/fatal/fatal.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/friend/friend.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/lm/lm.h" +#include "core/hle/service/mm/mm_u.h" +#include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nifm/nifm.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/pctl/pctl.h" +#include "core/hle/service/prepo/prepo.h" #include "core/hle/service/service.h" -#include "core/hle/service/set/set.h" +#include "core/hle/service/set/settings.h" #include "core/hle/service/sm/controller.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/sockets/sockets.h" +#include "core/hle/service/spl/module.h" +#include "core/hle/service/ssl/ssl.h" #include "core/hle/service/time/time.h" #include "core/hle/service/vi/vi.h" @@ -52,10 +60,9 @@ static std::string MakeFunctionString(const char* name, const char* port_name, // Number of params == bits 0-5 + bits 6-11 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); - std::string function_string = - Common::StringFromFormat("function '%s': port=%s", name, port_name); + std::string function_string = fmt::format("function '{}': port={}", name, port_name); for (int i = 1; i <= num_params; ++i) { - function_string += Common::StringFromFormat(", cmd_buff[%i]=0x%X", i, cmd_buff[i]); + function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]); } return function_string; } @@ -107,15 +114,15 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext auto cmd_buf = ctx.CommandBuffer(); std::string function_name = info == nullptr ? fmt::format("{}", ctx.GetCommand()) : info->name; - fmt::MemoryWriter w; - w.write("function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name, - cmd_buf[0]); + fmt::memory_buffer buf; + fmt::format_to(buf, "function '{}': port='{}' cmd_buf={{[0]=0x{:X}", function_name, + service_name, cmd_buf[0]); for (int i = 1; i <= 8; ++i) { - w.write(", [{}]={:#x}", i, cmd_buf[i]); + fmt::format_to(buf, ", [{}]=0x{:X}", i, cmd_buf[i]); } - w << '}'; + buf.push_back('}'); - LOG_ERROR(Service, "unknown / unimplemented %s", w.c_str()); + NGLOG_ERROR(Service, "unknown / unimplemented {}", fmt::to_string(buf)); UNIMPLEMENTED(); } @@ -126,8 +133,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { return ReportUnimplementedFunction(ctx, info); } - LOG_TRACE( - Service, "%s", + NGLOG_TRACE( + Service, "{}", MakeFunctionString(info->name, GetServiceName().c_str(), ctx.CommandBuffer()).c_str()); handler_invoker(this, info->handler_callback, ctx); } @@ -139,21 +146,21 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co rb.Push(RESULT_SUCCESS); return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead); } + case IPC::CommandType::ControlWithContext: case IPC::CommandType::Control: { - SM::g_service_manager->InvokeControlRequest(context); + Core::System::GetInstance().ServiceManager().InvokeControlRequest(context); break; } + case IPC::CommandType::RequestWithContext: case IPC::CommandType::Request: { InvokeRequest(context); break; } default: - UNIMPLEMENTED_MSG("command_type=%d", context.GetCommandType()); + UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType())); } - u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress()); - context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process, - Kernel::g_handle_table); + context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread()); return RESULT_SUCCESS; } @@ -167,39 +174,44 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) { } /// Initialize ServiceManager -void Init() { +void Init(std::shared_ptr<SM::ServiceManager>& sm) { // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it // here and pass it into the respective InstallInterfaces functions. auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); - SM::g_service_manager = std::make_shared<SM::ServiceManager>(); - SM::ServiceManager::InstallInterfaces(SM::g_service_manager); - - Account::InstallInterfaces(*SM::g_service_manager); - AM::InstallInterfaces(*SM::g_service_manager, nv_flinger); - AOC::InstallInterfaces(*SM::g_service_manager); - APM::InstallInterfaces(*SM::g_service_manager); - Audio::InstallInterfaces(*SM::g_service_manager); - FileSystem::InstallInterfaces(*SM::g_service_manager); - Friend::InstallInterfaces(*SM::g_service_manager); - HID::InstallInterfaces(*SM::g_service_manager); - LM::InstallInterfaces(*SM::g_service_manager); - NIFM::InstallInterfaces(*SM::g_service_manager); - NS::InstallInterfaces(*SM::g_service_manager); - Nvidia::InstallInterfaces(*SM::g_service_manager); - PCTL::InstallInterfaces(*SM::g_service_manager); - Sockets::InstallInterfaces(*SM::g_service_manager); - Time::InstallInterfaces(*SM::g_service_manager); - VI::InstallInterfaces(*SM::g_service_manager, nv_flinger); - Set::InstallInterfaces(*SM::g_service_manager); - - LOG_DEBUG(Service, "initialized OK"); + SM::ServiceManager::InstallInterfaces(sm); + + Account::InstallInterfaces(*sm); + AM::InstallInterfaces(*sm, nv_flinger); + AOC::InstallInterfaces(*sm); + APM::InstallInterfaces(*sm); + BCAT::InstallInterfaces(*sm); + Audio::InstallInterfaces(*sm); + Fatal::InstallInterfaces(*sm); + FileSystem::InstallInterfaces(*sm); + Friend::InstallInterfaces(*sm); + HID::InstallInterfaces(*sm); + LM::InstallInterfaces(*sm); + MM::InstallInterfaces(*sm); + NFP::InstallInterfaces(*sm); + NIFM::InstallInterfaces(*sm); + NS::InstallInterfaces(*sm); + Nvidia::InstallInterfaces(*sm); + PCTL::InstallInterfaces(*sm); + PlayReport::InstallInterfaces(*sm); + Sockets::InstallInterfaces(*sm); + SPL::InstallInterfaces(*sm); + SSL::InstallInterfaces(*sm); + Time::InstallInterfaces(*sm); + VI::InstallInterfaces(*sm, nv_flinger); + Set::InstallInterfaces(*sm); + + NGLOG_DEBUG(Service, "initialized OK"); } /// Shutdown ServiceManager void Shutdown() { - SM::g_service_manager = nullptr; g_kernel_named_ports.clear(); - LOG_DEBUG(Service, "shutdown OK"); + NGLOG_DEBUG(Service, "shutdown OK"); } } // namespace Service diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 9c2e826da..fee841d46 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -178,7 +178,7 @@ private: }; /// Initialize ServiceManager -void Init(); +void Init(std::shared_ptr<SM::ServiceManager>& sm); /// Shutdown ServiceManager void Shutdown(); diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 3001ee411..f0572bed6 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -9,33 +9,53 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/service/set/set.h" -namespace Service { -namespace Set { +namespace Service::Set { void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; u32 id = rp.Pop<u32>(); - constexpr std::array<u8, 13> lang_codes{}; - - ctx.WriteBuffer(lang_codes.data(), lang_codes.size()); - - IPC::ResponseBuilder rb{ctx, 2}; + static constexpr std::array<LanguageCode, 17> available_language_codes = {{ + LanguageCode::JA, + LanguageCode::EN_US, + LanguageCode::FR, + LanguageCode::DE, + LanguageCode::IT, + LanguageCode::ES, + LanguageCode::ZH_CN, + LanguageCode::KO, + LanguageCode::NL, + LanguageCode::PT, + LanguageCode::RU, + LanguageCode::ZH_TW, + LanguageCode::EN_GB, + LanguageCode::FR_CA, + LanguageCode::ES_419, + LanguageCode::ZH_HANS, + LanguageCode::ZH_HANT, + }}; + ctx.WriteBuffer(available_language_codes.data(), available_language_codes.size()); + + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u64>(available_language_codes.size())); - LOG_WARNING(Service_SET, "(STUBBED) called"); + NGLOG_DEBUG(Service_SET, "called"); } -SET::SET(const char* name) : ServiceFramework(name) { +SET::SET() : ServiceFramework("set") { static const FunctionInfo functions[] = { + {0, nullptr, "GetLanguageCode"}, {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, + {2, nullptr, "MakeLanguageCode"}, + {3, nullptr, "GetAvailableLanguageCodeCount"}, + {4, nullptr, "GetRegionCode"}, + {5, nullptr, "GetAvailableLanguageCodes2"}, + {6, nullptr, "GetAvailableLanguageCodeCount2"}, + {7, nullptr, "GetKeyCodeMap"}, + {8, nullptr, "GetQuestFlag"}, }; RegisterHandlers(functions); } -void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<SET>("set")->InstallAsService(service_manager); -} - -} // namespace Set -} // namespace Service +} // namespace Service::Set diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 61e957946..ec0df0152 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -6,20 +6,36 @@ #include "core/hle/service/service.h" -namespace Service { -namespace Set { +namespace Service::Set { + +/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. +enum class LanguageCode : u64 { + JA = 0x000000000000616A, + EN_US = 0x00000053552D6E65, + FR = 0x0000000000007266, + DE = 0x0000000000006564, + IT = 0x0000000000007469, + ES = 0x0000000000007365, + ZH_CN = 0x0000004E432D687A, + KO = 0x0000000000006F6B, + NL = 0x0000000000006C6E, + PT = 0x0000000000007470, + RU = 0x0000000000007572, + ZH_TW = 0x00000057542D687A, + EN_GB = 0x00000042472D6E65, + FR_CA = 0x00000041432D7266, + ES_419 = 0x00003931342D7365, + ZH_HANS = 0x00736E61482D687A, + ZH_HANT = 0x00746E61482D687A, +}; class SET final : public ServiceFramework<SET> { public: - explicit SET(const char* name); + explicit SET(); ~SET() = default; private: void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); }; -/// Registers all Set services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); - -} // namespace Set -} // namespace Service +} // namespace Service::Set diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp new file mode 100644 index 000000000..7066ef725 --- /dev/null +++ b/src/core/hle/service/set/set_cal.cpp @@ -0,0 +1,47 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/set/set_cal.h" + +namespace Service::Set { + +SET_CAL::SET_CAL() : ServiceFramework("set:cal") { + static const FunctionInfo functions[] = { + {0, nullptr, "GetBluetoothBdAddress"}, + {1, nullptr, "GetConfigurationId1"}, + {2, nullptr, "GetAccelerometerOffset"}, + {3, nullptr, "GetAccelerometerScale"}, + {4, nullptr, "GetGyroscopeOffset"}, + {5, nullptr, "GetGyroscopeScale"}, + {6, nullptr, "GetWirelessLanMacAddress"}, + {7, nullptr, "GetWirelessLanCountryCodeCount"}, + {8, nullptr, "GetWirelessLanCountryCodes"}, + {9, nullptr, "GetSerialNumber"}, + {10, nullptr, "SetInitialSystemAppletProgramId"}, + {11, nullptr, "SetOverlayDispProgramId"}, + {12, nullptr, "GetBatteryLot"}, + {14, nullptr, "GetEciDeviceCertificate"}, + {15, nullptr, "GetEticketDeviceCertificate"}, + {16, nullptr, "GetSslKey"}, + {17, nullptr, "GetSslCertificate"}, + {18, nullptr, "GetGameCardKey"}, + {19, nullptr, "GetGameCardCertificate"}, + {20, nullptr, "GetEciDeviceKey"}, + {21, nullptr, "GetEticketDeviceKey"}, + {22, nullptr, "GetSpeakerParameter"}, + {23, nullptr, "GetLcdVendorId"}, + {24, nullptr, "GetEciDeviceCertificate2"}, + {25, nullptr, "GetEciDeviceKey2"}, + {26, nullptr, "GetAmiiboKey"}, + {27, nullptr, "GetAmiiboEcqvCertificate"}, + {28, nullptr, "GetAmiiboEcdsaCertificate"}, + {29, nullptr, "GetAmiiboEcqvBlsKey"}, + {30, nullptr, "GetAmiiboEcqvBlsCertificate"}, + {31, nullptr, "GetAmiiboEcqvBlsRootCertificate"}, + {32, nullptr, "GetUnknownId"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h new file mode 100644 index 000000000..bb50336aa --- /dev/null +++ b/src/core/hle/service/set/set_cal.h @@ -0,0 +1,17 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::Set { + +class SET_CAL final : public ServiceFramework<SET_CAL> { +public: + explicit SET_CAL(); + ~SET_CAL() = default; +}; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp new file mode 100644 index 000000000..c9f938716 --- /dev/null +++ b/src/core/hle/service/set/set_fd.cpp @@ -0,0 +1,23 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/set/set_fd.h" + +namespace Service::Set { + +SET_FD::SET_FD() : ServiceFramework("set:fd") { + static const FunctionInfo functions[] = { + {2, nullptr, "SetSettingsItemValue"}, + {3, nullptr, "ResetSettingsItemValue"}, + {4, nullptr, "CreateSettingsItemKeyIterator"}, + {10, nullptr, "ReadSettings"}, + {11, nullptr, "ResetSettings"}, + {20, nullptr, "SetWebInspectorFlag"}, + {21, nullptr, "SetAllowedSslHosts"}, + {22, nullptr, "SetHostFsMountPoint"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h new file mode 100644 index 000000000..dbd850bc7 --- /dev/null +++ b/src/core/hle/service/set/set_fd.h @@ -0,0 +1,17 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::Set { + +class SET_FD final : public ServiceFramework<SET_FD> { +public: + explicit SET_FD(); + ~SET_FD() = default; +}; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp new file mode 100644 index 000000000..762a664c5 --- /dev/null +++ b/src/core/hle/service/set/set_sys.cpp @@ -0,0 +1,175 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/service/set/set_sys.h" + +namespace Service::Set { + +void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { + + IPC::ResponseBuilder rb{ctx, 3}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); + + NGLOG_WARNING(Service_SET, "(STUBBED) called"); +} + +SET_SYS::SET_SYS() : ServiceFramework("set:sys") { + static const FunctionInfo functions[] = { + {0, nullptr, "SetLanguageCode"}, + {1, nullptr, "SetNetworkSettings"}, + {2, nullptr, "GetNetworkSettings"}, + {3, nullptr, "GetFirmwareVersion"}, + {4, nullptr, "GetFirmwareVersion2"}, + {5, nullptr, "GetFirmwareVersionDigest"}, + {7, nullptr, "GetLockScreenFlag"}, + {8, nullptr, "SetLockScreenFlag"}, + {9, nullptr, "GetBacklightSettings"}, + {10, nullptr, "SetBacklightSettings"}, + {11, nullptr, "SetBluetoothDevicesSettings"}, + {12, nullptr, "GetBluetoothDevicesSettings"}, + {13, nullptr, "GetExternalSteadyClockSourceId"}, + {14, nullptr, "SetExternalSteadyClockSourceId"}, + {15, nullptr, "GetUserSystemClockContext"}, + {16, nullptr, "SetUserSystemClockContext"}, + {17, nullptr, "GetAccountSettings"}, + {18, nullptr, "SetAccountSettings"}, + {19, nullptr, "GetAudioVolume"}, + {20, nullptr, "SetAudioVolume"}, + {21, nullptr, "GetEulaVersions"}, + {22, nullptr, "SetEulaVersions"}, + {23, &SET_SYS::GetColorSetId, "GetColorSetId"}, + {24, nullptr, "SetColorSetId"}, + {25, nullptr, "GetConsoleInformationUploadFlag"}, + {26, nullptr, "SetConsoleInformationUploadFlag"}, + {27, nullptr, "GetAutomaticApplicationDownloadFlag"}, + {28, nullptr, "SetAutomaticApplicationDownloadFlag"}, + {29, nullptr, "GetNotificationSettings"}, + {30, nullptr, "SetNotificationSettings"}, + {31, nullptr, "GetAccountNotificationSettings"}, + {32, nullptr, "SetAccountNotificationSettings"}, + {35, nullptr, "GetVibrationMasterVolume"}, + {36, nullptr, "SetVibrationMasterVolume"}, + {37, nullptr, "GetSettingsItemValueSize"}, + {38, nullptr, "GetSettingsItemValue"}, + {39, nullptr, "GetTvSettings"}, + {40, nullptr, "SetTvSettings"}, + {41, nullptr, "GetEdid"}, + {42, nullptr, "SetEdid"}, + {43, nullptr, "GetAudioOutputMode"}, + {44, nullptr, "SetAudioOutputMode"}, + {45, nullptr, "IsForceMuteOnHeadphoneRemoved"}, + {46, nullptr, "SetForceMuteOnHeadphoneRemoved"}, + {47, nullptr, "GetQuestFlag"}, + {48, nullptr, "SetQuestFlag"}, + {49, nullptr, "GetDataDeletionSettings"}, + {50, nullptr, "SetDataDeletionSettings"}, + {51, nullptr, "GetInitialSystemAppletProgramId"}, + {52, nullptr, "GetOverlayDispProgramId"}, + {53, nullptr, "GetDeviceTimeZoneLocationName"}, + {54, nullptr, "SetDeviceTimeZoneLocationName"}, + {55, nullptr, "GetWirelessCertificationFileSize"}, + {56, nullptr, "GetWirelessCertificationFile"}, + {57, nullptr, "SetRegionCode"}, + {58, nullptr, "GetNetworkSystemClockContext"}, + {59, nullptr, "SetNetworkSystemClockContext"}, + {60, nullptr, "IsUserSystemClockAutomaticCorrectionEnabled"}, + {61, nullptr, "SetUserSystemClockAutomaticCorrectionEnabled"}, + {62, nullptr, "GetDebugModeFlag"}, + {63, nullptr, "GetPrimaryAlbumStorage"}, + {64, nullptr, "SetPrimaryAlbumStorage"}, + {65, nullptr, "GetUsb30EnableFlag"}, + {66, nullptr, "SetUsb30EnableFlag"}, + {67, nullptr, "GetBatteryLot"}, + {68, nullptr, "GetSerialNumber"}, + {69, nullptr, "GetNfcEnableFlag"}, + {70, nullptr, "SetNfcEnableFlag"}, + {71, nullptr, "GetSleepSettings"}, + {72, nullptr, "SetSleepSettings"}, + {73, nullptr, "GetWirelessLanEnableFlag"}, + {74, nullptr, "SetWirelessLanEnableFlag"}, + {75, nullptr, "GetInitialLaunchSettings"}, + {76, nullptr, "SetInitialLaunchSettings"}, + {77, nullptr, "GetDeviceNickName"}, + {78, nullptr, "SetDeviceNickName"}, + {79, nullptr, "GetProductModel"}, + {80, nullptr, "GetLdnChannel"}, + {81, nullptr, "SetLdnChannel"}, + {82, nullptr, "AcquireTelemetryDirtyFlagEventHandle"}, + {83, nullptr, "GetTelemetryDirtyFlags"}, + {84, nullptr, "GetPtmBatteryLot"}, + {85, nullptr, "SetPtmBatteryLot"}, + {86, nullptr, "GetPtmFuelGaugeParameter"}, + {87, nullptr, "SetPtmFuelGaugeParameter"}, + {88, nullptr, "GetBluetoothEnableFlag"}, + {89, nullptr, "SetBluetoothEnableFlag"}, + {90, nullptr, "GetMiiAuthorId"}, + {91, nullptr, "SetShutdownRtcValue"}, + {92, nullptr, "GetShutdownRtcValue"}, + {93, nullptr, "AcquireFatalDirtyFlagEventHandle"}, + {94, nullptr, "GetFatalDirtyFlags"}, + {95, nullptr, "GetAutoUpdateEnableFlag"}, + {96, nullptr, "SetAutoUpdateEnableFlag"}, + {97, nullptr, "GetNxControllerSettings"}, + {98, nullptr, "SetNxControllerSettings"}, + {99, nullptr, "GetBatteryPercentageFlag"}, + {100, nullptr, "SetBatteryPercentageFlag"}, + {101, nullptr, "GetExternalRtcResetFlag"}, + {102, nullptr, "SetExternalRtcResetFlag"}, + {103, nullptr, "GetUsbFullKeyEnableFlag"}, + {104, nullptr, "SetUsbFullKeyEnableFlag"}, + {105, nullptr, "SetExternalSteadyClockInternalOffset"}, + {106, nullptr, "GetExternalSteadyClockInternalOffset"}, + {107, nullptr, "GetBacklightSettingsEx"}, + {108, nullptr, "SetBacklightSettingsEx"}, + {109, nullptr, "GetHeadphoneVolumeWarningCount"}, + {110, nullptr, "SetHeadphoneVolumeWarningCount"}, + {111, nullptr, "GetBluetoothAfhEnableFlag"}, + {112, nullptr, "SetBluetoothAfhEnableFlag"}, + {113, nullptr, "GetBluetoothBoostEnableFlag"}, + {114, nullptr, "SetBluetoothBoostEnableFlag"}, + {115, nullptr, "GetInRepairProcessEnableFlag"}, + {116, nullptr, "SetInRepairProcessEnableFlag"}, + {117, nullptr, "GetHeadphoneVolumeUpdateFlag"}, + {118, nullptr, "SetHeadphoneVolumeUpdateFlag"}, + {119, nullptr, "NeedsToUpdateHeadphoneVolume"}, + {120, nullptr, "GetPushNotificationActivityModeOnSleep"}, + {121, nullptr, "SetPushNotificationActivityModeOnSleep"}, + {122, nullptr, "GetServiceDiscoveryControlSettings"}, + {123, nullptr, "SetServiceDiscoveryControlSettings"}, + {124, nullptr, "GetErrorReportSharePermission"}, + {125, nullptr, "SetErrorReportSharePermission"}, + {126, nullptr, "GetAppletLaunchFlags"}, + {127, nullptr, "SetAppletLaunchFlags"}, + {128, nullptr, "GetConsoleSixAxisSensorAccelerationBias"}, + {129, nullptr, "SetConsoleSixAxisSensorAccelerationBias"}, + {130, nullptr, "GetConsoleSixAxisSensorAngularVelocityBias"}, + {131, nullptr, "SetConsoleSixAxisSensorAngularVelocityBias"}, + {132, nullptr, "GetConsoleSixAxisSensorAccelerationGain"}, + {133, nullptr, "SetConsoleSixAxisSensorAccelerationGain"}, + {134, nullptr, "GetConsoleSixAxisSensorAngularVelocityGain"}, + {135, nullptr, "SetConsoleSixAxisSensorAngularVelocityGain"}, + {136, nullptr, "GetKeyboardLayout"}, + {137, nullptr, "SetKeyboardLayout"}, + {138, nullptr, "GetWebInspectorFlag"}, + {139, nullptr, "GetAllowedSslHosts"}, + {140, nullptr, "GetHostFsMountPoint"}, + {141, nullptr, "GetRequiresRunRepairTimeReviser"}, + {142, nullptr, "SetRequiresRunRepairTimeReviser"}, + {143, nullptr, "SetBlePairingSettings"}, + {144, nullptr, "GetBlePairingSettings"}, + {145, nullptr, "GetConsoleSixAxisSensorAngularVelocityTimeBias"}, + {146, nullptr, "SetConsoleSixAxisSensorAngularVelocityTimeBias"}, + {147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"}, + {148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"}, + {149, nullptr, "GetRebootlessSystemUpdateVersion"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h new file mode 100644 index 000000000..b77a97cde --- /dev/null +++ b/src/core/hle/service/set/set_sys.h @@ -0,0 +1,20 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::Set { + +class SET_SYS final : public ServiceFramework<SET_SYS> { +public: + explicit SET_SYS(); + ~SET_SYS() = default; + +private: + void GetColorSetId(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/settings.cpp b/src/core/hle/service/set/settings.cpp new file mode 100644 index 000000000..cf5541ca8 --- /dev/null +++ b/src/core/hle/service/set/settings.cpp @@ -0,0 +1,20 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/set/set.h" +#include "core/hle/service/set/set_cal.h" +#include "core/hle/service/set/set_fd.h" +#include "core/hle/service/set/set_sys.h" +#include "core/hle/service/set/settings.h" + +namespace Service::Set { + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared<SET>()->InstallAsService(service_manager); + std::make_shared<SET_CAL>()->InstallAsService(service_manager); + std::make_shared<SET_FD>()->InstallAsService(service_manager); + std::make_shared<SET_SYS>()->InstallAsService(service_manager); +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/settings.h b/src/core/hle/service/set/settings.h new file mode 100644 index 000000000..6606ce776 --- /dev/null +++ b/src/core/hle/service/set/settings.h @@ -0,0 +1,14 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::Set { + +/// Registers all Settings services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::Set diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index e12c53442..fe5097cdc 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -7,8 +7,7 @@ #include "core/hle/kernel/session.h" #include "core/hle/service/sm/controller.h" -namespace Service { -namespace SM { +namespace Service::SM { void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain"); @@ -18,7 +17,7 @@ void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push<u32>(1); // Converted sessions start with 1 request handler - LOG_DEBUG(Service, "called, server_session=%d", ctx.Session()->GetObjectId()); + NGLOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); } void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { @@ -30,11 +29,11 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; rb.PushMoveObjects(session); - LOG_DEBUG(Service, "called, session=%u", session->GetObjectId()); + NGLOG_DEBUG(Service, "called, session={}", session->GetObjectId()); } void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called, using DuplicateSession"); + NGLOG_WARNING(Service, "(STUBBED) called, using DuplicateSession"); DuplicateSession(ctx); } @@ -44,7 +43,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push<u32>(0x500); - LOG_WARNING(Service, "(STUBBED) called"); + NGLOG_WARNING(Service, "(STUBBED) called"); } Controller::Controller() : ServiceFramework("IpcController") { @@ -58,5 +57,4 @@ Controller::Controller() : ServiceFramework("IpcController") { RegisterHandlers(functions); } -} // namespace SM -} // namespace Service +} // namespace Service::SM diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h index 7b4bc4b75..a4de52cd2 100644 --- a/src/core/hle/service/sm/controller.h +++ b/src/core/hle/service/sm/controller.h @@ -6,8 +6,7 @@ #include "core/hle/service/service.h" -namespace Service { -namespace SM { +namespace Service::SM { class Controller final : public ServiceFramework<Controller> { public: @@ -21,5 +20,4 @@ private: void QueryPointerBufferSize(Kernel::HLERequestContext& ctx); }; -} // namespace SM -} // namespace Service +} // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index bc72512a0..bded8421f 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -12,8 +12,9 @@ #include "core/hle/service/sm/controller.h" #include "core/hle/service/sm/sm.h" -namespace Service { -namespace SM { +namespace Service::SM { + +ServiceManager::~ServiceManager() = default; void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { controller_interface->InvokeRequest(context); @@ -73,7 +74,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToSer return client_port->Connect(); } -std::shared_ptr<ServiceManager> g_service_manager; +SM::~SM() = default; /** * SM::Initialize service function @@ -85,7 +86,7 @@ std::shared_ptr<ServiceManager> g_service_manager; void SM::Initialize(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_DEBUG(Service_SM, "called"); + NGLOG_DEBUG(Service_SM, "called"); } void SM::GetService(Kernel::HLERequestContext& ctx) { @@ -101,8 +102,8 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { if (client_port.Failed()) { IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); rb.Push(client_port.Code()); - LOG_ERROR(Service_SM, "called service=%s -> error 0x%08X", name.c_str(), - client_port.Code().raw); + NGLOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, + client_port.Code().raw); if (name.length() == 0) return; // LibNX Fix UNIMPLEMENTED(); @@ -112,8 +113,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { auto session = client_port.Unwrap()->Connect(); ASSERT(session.Succeeded()); if (session.Succeeded()) { - LOG_DEBUG(Service_SM, "called service=%s -> session=%u", name.c_str(), - (*session)->GetObjectId()); + NGLOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles); rb.Push(session.Code()); @@ -132,5 +132,4 @@ SM::SM(std::shared_ptr<ServiceManager> service_manager) RegisterHandlers(functions); } -} // namespace SM -} // namespace Service +} // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 11fa788ca..13f5c4c28 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -17,14 +17,13 @@ class ServerPort; class SessionRequestHandler; } // namespace Kernel -namespace Service { -namespace SM { +namespace Service::SM { /// Interface to "sm:" service class SM final : public ServiceFramework<SM> { public: SM(std::shared_ptr<ServiceManager> service_manager); - ~SM() = default; + ~SM() override; private: void Initialize(Kernel::HLERequestContext& ctx); @@ -45,6 +44,8 @@ class ServiceManager { public: static void InstallInterfaces(std::shared_ptr<ServiceManager> self); + ~ServiceManager(); + ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, unsigned int max_sessions); ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); @@ -60,7 +61,4 @@ private: std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services; }; -extern std::shared_ptr<ServiceManager> g_service_manager; - -} // namespace SM -} // namespace Service +} // namespace Service::SM diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp new file mode 100644 index 000000000..ab909fdaa --- /dev/null +++ b/src/core/hle/service/sockets/bsd.cpp @@ -0,0 +1,114 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/sockets/bsd.h" + +namespace Service::Sockets { + +void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // bsd errno +} + +void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // bsd errno +} + +void BSD::Socket(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + u32 domain = rp.Pop<u32>(); + u32 type = rp.Pop<u32>(); + u32 protocol = rp.Pop<u32>(); + + NGLOG_WARNING(Service, "(STUBBED) called domain={} type={} protocol={}", domain, type, + protocol); + + u32 fd = next_fd++; + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(fd); + rb.Push<u32>(0); // bsd errno +} + +void BSD::Connect(Kernel::HLERequestContext& ctx) { + NGLOG_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) { + NGLOG_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::Close(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // ret + rb.Push<u32>(0); // bsd errno +} + +BSD::BSD(const char* name) : ServiceFramework(name) { + static const FunctionInfo functions[] = { + {0, &BSD::RegisterClient, "RegisterClient"}, + {1, &BSD::StartMonitoring, "StartMonitoring"}, + {2, &BSD::Socket, "Socket"}, + {3, nullptr, "SocketExempt"}, + {4, nullptr, "Open"}, + {5, nullptr, "Select"}, + {6, nullptr, "Poll"}, + {7, nullptr, "Sysctl"}, + {8, nullptr, "Recv"}, + {9, nullptr, "RecvFrom"}, + {10, nullptr, "Send"}, + {11, &BSD::SendTo, "SendTo"}, + {12, nullptr, "Accept"}, + {13, nullptr, "Bind"}, + {14, &BSD::Connect, "Connect"}, + {15, nullptr, "GetPeerName"}, + {16, nullptr, "GetSockName"}, + {17, nullptr, "GetSockOpt"}, + {18, nullptr, "Listen"}, + {19, nullptr, "Ioctl"}, + {20, nullptr, "Fcntl"}, + {21, nullptr, "SetSockOpt"}, + {22, nullptr, "Shutdown"}, + {23, nullptr, "ShutdownAllSockets"}, + {24, nullptr, "Write"}, + {25, nullptr, "Read"}, + {26, &BSD::Close, "Close"}, + {27, nullptr, "DuplicateSocket"}, + {28, nullptr, "GetResourceStatistics"}, + {29, nullptr, "RecvMMsg"}, + {30, nullptr, "SendMMsg"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/bsd_u.h b/src/core/hle/service/sockets/bsd.h index 4e1252e9d..a6b1ca7d0 100644 --- a/src/core/hle/service/sockets/bsd_u.h +++ b/src/core/hle/service/sockets/bsd.h @@ -7,13 +7,12 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/service.h" -namespace Service { -namespace Sockets { +namespace Service::Sockets { -class BSD_U final : public ServiceFramework<BSD_U> { +class BSD final : public ServiceFramework<BSD> { public: - BSD_U(); - ~BSD_U() = default; + explicit BSD(const char* name); + ~BSD() = default; private: void RegisterClient(Kernel::HLERequestContext& ctx); @@ -27,5 +26,4 @@ private: u32 next_fd = 1; }; -} // namespace Sockets -} // namespace Service +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/bsd_u.cpp b/src/core/hle/service/sockets/bsd_u.cpp deleted file mode 100644 index 2ca1000ca..000000000 --- a/src/core/hle/service/sockets/bsd_u.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/sockets/bsd_u.h" - -namespace Service { -namespace Sockets { - -void BSD_U::RegisterClient(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0); // bsd errno -} - -void BSD_U::StartMonitoring(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0); // bsd errno -} - -void BSD_U::Socket(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - u32 domain = rp.Pop<u32>(); - u32 type = rp.Pop<u32>(); - u32 protocol = rp.Pop<u32>(); - - LOG_WARNING(Service, "(STUBBED) called domain=%u type=%u protocol=%u", domain, type, protocol); - - u32 fd = next_fd++; - - IPC::ResponseBuilder rb{ctx, 4}; - - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(fd); - rb.Push<u32>(0); // bsd errno -} - -void BSD_U::Connect(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_U::SendTo(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_U::Close(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 -} - -BSD_U::BSD_U() : ServiceFramework("bsd:u") { - static const FunctionInfo functions[] = {{0, &BSD_U::RegisterClient, "RegisterClient"}, - {1, &BSD_U::StartMonitoring, "StartMonitoring"}, - {2, &BSD_U::Socket, "Socket"}, - {11, &BSD_U::SendTo, "SendTo"}, - {14, &BSD_U::Connect, "Connect"}, - {26, &BSD_U::Close, "Close"}}; - RegisterHandlers(functions); -} - -} // namespace Sockets -} // namespace Service diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp new file mode 100644 index 000000000..8682dc2e0 --- /dev/null +++ b/src/core/hle/service/sockets/nsd.cpp @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/sockets/nsd.h" + +namespace Service::Sockets { + +NSD::NSD(const char* name) : ServiceFramework(name) { + static const FunctionInfo functions[] = { + {10, nullptr, "GetSettingName"}, + {11, nullptr, "GetEnvironmentIdentifier"}, + {12, nullptr, "GetDeviceId"}, + {13, nullptr, "DeleteSettings"}, + {14, nullptr, "ImportSettings"}, + {20, nullptr, "Resolve"}, + {21, nullptr, "ResolveEx"}, + {30, nullptr, "GetNasServiceSetting"}, + {31, nullptr, "GetNasServiceSettingEx"}, + {40, nullptr, "GetNasRequestFqdn"}, + {41, nullptr, "GetNasRequestFqdnEx"}, + {42, nullptr, "GetNasApiFqdn"}, + {43, nullptr, "GetNasApiFqdnEx"}, + {50, nullptr, "GetCurrentSetting"}, + {60, nullptr, "ReadSaveDataFromFsForTest"}, + {61, nullptr, "WriteSaveDataToFsForTest"}, + {62, nullptr, "DeleteSaveDataOfFsForTest"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h new file mode 100644 index 000000000..3b7edfc43 --- /dev/null +++ b/src/core/hle/service/sockets/nsd.h @@ -0,0 +1,18 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/service.h" + +namespace Service::Sockets { + +class NSD final : public ServiceFramework<NSD> { +public: + explicit NSD(const char* name); + ~NSD() = default; +}; + +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 4d7bc7c3e..f377e59f2 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -5,13 +5,12 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/service/sockets/sfdnsres.h" -namespace Service { -namespace Sockets { +namespace Service::Sockets { void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - LOG_WARNING(Service, "(STUBBED) called"); + NGLOG_WARNING(Service, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; @@ -19,18 +18,20 @@ void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { } SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") { - static const FunctionInfo functions[] = {{0, nullptr, "SetDnsAddressesPrivate"}, - {1, nullptr, "GetDnsAddressPrivate"}, - {2, nullptr, "GetHostByName"}, - {3, nullptr, "GetHostByAddr"}, - {4, nullptr, "GetHostStringError"}, - {5, nullptr, "GetGaiStringError"}, - {6, &SFDNSRES::GetAddrInfo, "GetAddrInfo"}, - {7, nullptr, "GetNameInfo"}, - {8, nullptr, "RequestCancelHandle"}, - {9, nullptr, "CancelSocketCall"}}; + static const FunctionInfo functions[] = { + {0, nullptr, "SetDnsAddressesPrivate"}, + {1, nullptr, "GetDnsAddressPrivate"}, + {2, nullptr, "GetHostByName"}, + {3, nullptr, "GetHostByAddr"}, + {4, nullptr, "GetHostStringError"}, + {5, nullptr, "GetGaiStringError"}, + {6, &SFDNSRES::GetAddrInfo, "GetAddrInfo"}, + {7, nullptr, "GetNameInfo"}, + {8, nullptr, "RequestCancelHandle"}, + {9, nullptr, "CancelSocketCall"}, + {11, nullptr, "ClearDnsIpServerAddressArray"}, + }; RegisterHandlers(functions); } -} // namespace Sockets -} // namespace Service +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h index b726a30fd..62c7e35bf 100644 --- a/src/core/hle/service/sockets/sfdnsres.h +++ b/src/core/hle/service/sockets/sfdnsres.h @@ -7,17 +7,15 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/service.h" -namespace Service { -namespace Sockets { +namespace Service::Sockets { class SFDNSRES final : public ServiceFramework<SFDNSRES> { public: - SFDNSRES(); + explicit SFDNSRES(); ~SFDNSRES() = default; private: void GetAddrInfo(Kernel::HLERequestContext& ctx); }; -} // namespace Sockets -} // namespace Service +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp index f1396eaa1..05bd10d35 100644 --- a/src/core/hle/service/sockets/sockets.cpp +++ b/src/core/hle/service/sockets/sockets.cpp @@ -2,17 +2,19 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/service/sockets/bsd_u.h" +#include "core/hle/service/sockets/bsd.h" +#include "core/hle/service/sockets/nsd.h" #include "core/hle/service/sockets/sfdnsres.h" #include "core/hle/service/sockets/sockets.h" -namespace Service { -namespace Sockets { +namespace Service::Sockets { void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<BSD_U>()->InstallAsService(service_manager); + std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager); + std::make_shared<BSD>("bsd:u")->InstallAsService(service_manager); + std::make_shared<NSD>("nsd:a")->InstallAsService(service_manager); + std::make_shared<NSD>("nsd:u")->InstallAsService(service_manager); std::make_shared<SFDNSRES>()->InstallAsService(service_manager); } -} // namespace Sockets -} // namespace Service +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h index 7e89c8d2c..ca8a6a7e0 100644 --- a/src/core/hle/service/sockets/sockets.h +++ b/src/core/hle/service/sockets/sockets.h @@ -6,11 +6,9 @@ #include "core/hle/service/service.h" -namespace Service { -namespace Sockets { +namespace Service::Sockets { /// Registers all Sockets services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace Sockets -} // namespace Service +} // namespace Service::Sockets diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp new file mode 100644 index 000000000..b9e6b799d --- /dev/null +++ b/src/core/hle/service/spl/csrng.cpp @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/spl/csrng.h" + +namespace Service::SPL { + +CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "csrng") { + static const FunctionInfo functions[] = { + {0, &CSRNG::GetRandomBytes, "GetRandomBytes"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::SPL diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h new file mode 100644 index 000000000..3f849b5a7 --- /dev/null +++ b/src/core/hle/service/spl/csrng.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/spl/module.h" + +namespace Service::SPL { + +class CSRNG final : public Module::Interface { +public: + explicit CSRNG(std::shared_ptr<Module> module); +}; + +} // namespace Service::SPL diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp new file mode 100644 index 000000000..76ba97156 --- /dev/null +++ b/src/core/hle/service/spl/module.cpp @@ -0,0 +1,40 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstdlib> +#include <vector> +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/spl/csrng.h" +#include "core/hle/service/spl/module.h" +#include "core/hle/service/spl/spl.h" + +namespace Service::SPL { + +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) + : ServiceFramework(name), module(std::move(module)) {} + +void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + size_t size = ctx.GetWriteBufferSize(); + + std::vector<u8> data(size); + std::generate(data.begin(), data.end(), std::rand); + + ctx.WriteBuffer(data); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + NGLOG_DEBUG(Service_SPL, "called"); +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + auto module = std::make_shared<Module>(); + std::make_shared<CSRNG>(module)->InstallAsService(service_manager); + std::make_shared<SPL>(module)->InstallAsService(service_manager); +} + +} // namespace Service::SPL diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h new file mode 100644 index 000000000..6ab91b400 --- /dev/null +++ b/src/core/hle/service/spl/module.h @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::SPL { + +class Module final { +public: + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name); + + void GetRandomBytes(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + }; +}; + +/// Registers all SPL services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::SPL diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp new file mode 100644 index 000000000..bb1e03342 --- /dev/null +++ b/src/core/hle/service/spl/spl.cpp @@ -0,0 +1,45 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/spl/spl.h" + +namespace Service::SPL { + +SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") { + static const FunctionInfo functions[] = { + {0, nullptr, "GetConfig"}, + {1, nullptr, "UserExpMod"}, + {2, nullptr, "GenerateAesKek"}, + {3, nullptr, "LoadAesKey"}, + {4, nullptr, "GenerateAesKey"}, + {5, nullptr, "SetConfig"}, + {7, &SPL::GetRandomBytes, "GetRandomBytes"}, + {9, nullptr, "LoadSecureExpModKey"}, + {10, nullptr, "SecureExpMod"}, + {11, nullptr, "IsDevelopment"}, + {12, nullptr, "GenerateSpecificAesKey"}, + {13, nullptr, "DecryptPrivk"}, + {14, nullptr, "DecryptAesKey"}, + {15, nullptr, "DecryptAesCtr"}, + {16, nullptr, "ComputeCmac"}, + {17, nullptr, "LoadRsaOaepKey"}, + {18, nullptr, "UnwrapRsaOaepWrappedTitleKey"}, + {19, nullptr, "LoadTitleKey"}, + {20, nullptr, "UnwrapAesWrappedTitleKey"}, + {21, nullptr, "LockAesEngine"}, + {22, nullptr, "UnlockAesEngine"}, + {23, nullptr, "GetSplWaitEvent"}, + {24, nullptr, "SetSharedData"}, + {25, nullptr, "GetSharedData"}, + {26, nullptr, "ImportSslRsaKey"}, + {27, nullptr, "SecureExpModWithSslKey"}, + {28, nullptr, "ImportEsRsaKey"}, + {29, nullptr, "SecureExpModWithEsKey"}, + {30, nullptr, "EncryptManuRsaKeyForImport"}, + {31, nullptr, "GetPackage2Hash"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::SPL diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h new file mode 100644 index 000000000..69c4c1747 --- /dev/null +++ b/src/core/hle/service/spl/spl.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/spl/module.h" + +namespace Service::SPL { + +class SPL final : public Module::Interface { +public: + explicit SPL(std::shared_ptr<Module> module); +}; + +} // namespace Service::SPL diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp new file mode 100644 index 000000000..b3dad8b06 --- /dev/null +++ b/src/core/hle/service/ssl/ssl.cpp @@ -0,0 +1,119 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/ssl/ssl.h" + +namespace Service::SSL { + +class ISslConnection final : public ServiceFramework<ISslConnection> { +public: + ISslConnection() : ServiceFramework("ISslConnection") { + static const FunctionInfo functions[] = { + {0, nullptr, "SetSocketDescriptor"}, + {1, nullptr, "SetHostName"}, + {2, nullptr, "SetVerifyOption"}, + {3, nullptr, "SetIoMode"}, + {4, nullptr, "GetSocketDescriptor"}, + {5, nullptr, "GetHostName"}, + {6, nullptr, "GetVerifyOption"}, + {7, nullptr, "GetIoMode"}, + {8, nullptr, "DoHandshake"}, + {9, nullptr, "DoHandshakeGetServerCert"}, + {10, nullptr, "Read"}, + {11, nullptr, "Write"}, + {12, nullptr, "Pending"}, + {13, nullptr, "Peek"}, + {14, nullptr, "Poll"}, + {15, nullptr, "GetVerifyCertError"}, + {16, nullptr, "GetNeededServerCertBufferSize"}, + {17, nullptr, "SetSessionCacheMode"}, + {18, nullptr, "GetSessionCacheMode"}, + {19, nullptr, "FlushSessionCache"}, + {20, nullptr, "SetRenegotiationMode"}, + {21, nullptr, "GetRenegotiationMode"}, + {22, nullptr, "SetOption"}, + {23, nullptr, "GetOption"}, + {24, nullptr, "GetVerifyCertErrors"}, + {25, nullptr, "GetCipherInfo"}, + }; + RegisterHandlers(functions); + } +}; + +class ISslContext final : public ServiceFramework<ISslContext> { +public: + ISslContext() : ServiceFramework("ISslContext") { + static const FunctionInfo functions[] = { + {0, &ISslContext::SetOption, "SetOption"}, + {1, nullptr, "GetOption"}, + {2, &ISslContext::CreateConnection, "CreateConnection"}, + {3, nullptr, "GetConnectionCount"}, + {4, nullptr, "ImportServerPki"}, + {5, nullptr, "ImportClientPki"}, + {6, nullptr, "RemoveServerPki"}, + {7, nullptr, "RemoveClientPki"}, + {8, nullptr, "RegisterInternalPki"}, + {9, nullptr, "AddPolicyOid"}, + {10, nullptr, "ImportCrl"}, + {11, nullptr, "RemoveCrl"}, + }; + RegisterHandlers(functions); + } + ~ISslContext() = default; + +private: + void SetOption(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_SSL, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + rb.Push(RESULT_SUCCESS); + } + + void CreateConnection(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_SSL, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISslConnection>(); + } +}; + +void SSL::CreateContext(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_SSL, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISslContext>(); +} + +SSL::SSL() : ServiceFramework("ssl") { + static const FunctionInfo functions[] = { + {0, &SSL::CreateContext, "CreateContext"}, + {1, nullptr, "GetContextCount"}, + {2, nullptr, "GetCertificates"}, + {3, nullptr, "GetCertificateBufSize"}, + {4, nullptr, "DebugIoctl"}, + {5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"}, + {6, nullptr, "FlushSessionCache"}, + }; + RegisterHandlers(functions); +} + +void SSL::SetInterfaceVersion(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_SSL, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u32 unk1 = rp.Pop<u32>(); // Probably minor/major? + u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared<SSL>()->InstallAsService(service_manager); +} + +} // namespace Service::SSL diff --git a/src/core/hle/service/ssl/ssl.h b/src/core/hle/service/ssl/ssl.h new file mode 100644 index 000000000..8fef13022 --- /dev/null +++ b/src/core/hle/service/ssl/ssl.h @@ -0,0 +1,24 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::SSL { + +class SSL final : public ServiceFramework<SSL> { +public: + explicit SSL(); + ~SSL() = default; + +private: + void CreateContext(Kernel::HLERequestContext& ctx); + void SetInterfaceVersion(Kernel::HLERequestContext& ctx); +}; + +/// Registers all SSL services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::SSL diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index ad49f4265..654012189 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <chrono> +#include <ctime> #include "common/logging/log.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" @@ -12,15 +13,18 @@ #include "core/hle/service/time/time_s.h" #include "core/hle/service/time/time_u.h" -namespace Service { -namespace Time { +namespace Service::Time { class ISystemClock final : public ServiceFramework<ISystemClock> { public: ISystemClock() : ServiceFramework("ISystemClock") { static const FunctionInfo functions[] = { {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, - {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}}; + {1, nullptr, "SetCurrentTime"}, + {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}, + {3, nullptr, "SetSystemClockContext"}, + + }; RegisterHandlers(functions); } @@ -29,14 +33,14 @@ private: const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch()) .count()}; - LOG_DEBUG(Service_Time, "called"); + NGLOG_DEBUG(Service_Time, "called"); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(time_since_epoch); } void GetSystemClockContext(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Time, "(STUBBED) called"); + NGLOG_WARNING(Service_Time, "(STUBBED) called"); SystemClockContext system_clock_ontext{}; IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; rb.Push(RESULT_SUCCESS); @@ -55,8 +59,9 @@ public: private: void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - SteadyClockTimePoint steady_clock_time_point{cyclesToMs(CoreTiming::GetTicks()) / 1000}; + NGLOG_DEBUG(Service_Time, "called"); + SteadyClockTimePoint steady_clock_time_point{ + CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; rb.Push(RESULT_SUCCESS); rb.PushRaw(steady_clock_time_point); @@ -73,7 +78,7 @@ public: {3, nullptr, "LoadLocationNameList"}, {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, {5, nullptr, "GetTimeZoneRuleVersion"}, - {100, nullptr, "ToCalendarTime"}, + {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, {200, nullptr, "ToPosixTime"}, {201, nullptr, "ToPosixTimeWithMyRule"}, @@ -82,75 +87,124 @@ public: } private: + LocationName location_name{"UTC"}; + TimeZoneRule my_time_zone_rule{}; + void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Time, "(STUBBED) called"); - LocationName location_name{}; + NGLOG_DEBUG(Service_Time, "called"); IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; rb.Push(RESULT_SUCCESS); rb.PushRaw(location_name); } void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Time, "(STUBBED) called"); + NGLOG_WARNING(Service_Time, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); } void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Time, "(STUBBED) called"); + NGLOG_WARNING(Service_Time, "(STUBBED) called"); + + ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule)); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + void ToCalendarTime(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 posix_time = rp.Pop<u64>(); + + NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); + + TimeZoneRule time_zone_rule{}; + auto buffer = ctx.ReadBuffer(); + std::memcpy(&time_zone_rule, buffer.data(), buffer.size()); + + CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; + CalendarAdditionalInfo additional_info{}; + + PosixToCalendar(posix_time, calendar_time, additional_info, time_zone_rule); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw(calendar_time); + rb.PushRaw(additional_info); + } + void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 posix_time = rp.Pop<u64>(); + const u64 posix_time = rp.Pop<u64>(); - LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x%016llX", posix_time); + NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; CalendarAdditionalInfo additional_info{}; + + PosixToCalendar(posix_time, calendar_time, additional_info, my_time_zone_rule); + IPC::ResponseBuilder rb{ctx, 10}; rb.Push(RESULT_SUCCESS); rb.PushRaw(calendar_time); rb.PushRaw(additional_info); } + + void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, + CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) { + std::time_t t(posix_time); + std::tm* tm = std::localtime(&t); + if (!tm) { + return; + } + calendar_time.year = tm->tm_year + 1900; + calendar_time.month = tm->tm_mon + 1; + calendar_time.day = tm->tm_mday; + calendar_time.hour = tm->tm_hour; + calendar_time.minute = tm->tm_min; + calendar_time.second = tm->tm_sec; + + additional_info.day_of_week = tm->tm_wday; + additional_info.day_of_year = tm->tm_yday; + std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); + additional_info.utc_offset = 0; + } }; void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISystemClock>(); - LOG_DEBUG(Service_Time, "called"); + NGLOG_DEBUG(Service_Time, "called"); } void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISystemClock>(); - LOG_DEBUG(Service_Time, "called"); + NGLOG_DEBUG(Service_Time, "called"); } void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISteadyClock>(); - LOG_DEBUG(Service_Time, "called"); + NGLOG_DEBUG(Service_Time, "called"); } void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ITimeZoneService>(); - LOG_DEBUG(Service_Time, "called"); + NGLOG_DEBUG(Service_Time, "called"); } void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISystemClock>(); - LOG_DEBUG(Service_Time, "called"); + NGLOG_DEBUG(Service_Time, "called"); } Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) @@ -162,5 +216,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<TIME_U>(time)->InstallAsService(service_manager); } -} // namespace Time -} // namespace Service +} // namespace Service::Time diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 197029e7a..49af38589 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -4,14 +4,13 @@ #pragma once +#include <array> #include "core/hle/service/service.h" -namespace Service { -namespace Time { +namespace Service::Time { -// TODO(Rozelette) RE this structure struct LocationName { - INSERT_PADDING_BYTES(0x24); + std::array<u8, 0x24> name; }; static_assert(sizeof(LocationName) == 0x24, "LocationName is incorrect size"); @@ -26,26 +25,34 @@ struct CalendarTime { }; static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size"); -// TODO(Rozelette) RE this structure struct CalendarAdditionalInfo { - INSERT_PADDING_BYTES(0x18); + u32_le day_of_week; + u32_le day_of_year; + std::array<u8, 8> name; + INSERT_PADDING_BYTES(1); + s32_le utc_offset; }; static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo structure has incorrect size"); -// TODO(bunnei) RE this structure -struct SystemClockContext { - INSERT_PADDING_BYTES(0x20); +// TODO(mailwl) RE this structure +struct TimeZoneRule { + INSERT_PADDING_BYTES(0x4000); }; -static_assert(sizeof(SystemClockContext) == 0x20, - "SystemClockContext structure has incorrect size"); struct SteadyClockTimePoint { - u64 value; + u64_le value; INSERT_PADDING_WORDS(4); }; static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); +struct SystemClockContext { + u64_le offset; + SteadyClockTimePoint time_point; +}; +static_assert(sizeof(SystemClockContext) == 0x20, + "SystemClockContext structure has incorrect size"); + class Module final { public: class Interface : public ServiceFramework<Interface> { @@ -66,5 +73,4 @@ public: /// Registers all Time services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace Time -} // namespace Service +} // namespace Service::Time diff --git a/src/core/hle/service/time/time_s.cpp b/src/core/hle/service/time/time_s.cpp index b172b2bd6..0b599ea00 100644 --- a/src/core/hle/service/time/time_s.cpp +++ b/src/core/hle/service/time/time_s.cpp @@ -4,8 +4,7 @@ #include "core/hle/service/time/time_s.h" -namespace Service { -namespace Time { +namespace Service::Time { TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:s") { static const FunctionInfo functions[] = { @@ -14,9 +13,19 @@ TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time) {2, &TIME_S::GetStandardSteadyClock, "GetStandardSteadyClock"}, {3, &TIME_S::GetTimeZoneService, "GetTimeZoneService"}, {4, &TIME_S::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, + {5, nullptr, "GetEphemeralNetworkSystemClock"}, + {50, nullptr, "SetStandardSteadyClockInternalOffset"}, + {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, + {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, + {102, nullptr, "GetStandardUserSystemClockInitialYear"}, + {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, + {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, + {400, nullptr, "GetClockSnapshot"}, + {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, + {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, + {501, nullptr, "CalculateSpanBetween"}, }; RegisterHandlers(functions); } -} // namespace Time -} // namespace Service +} // namespace Service::Time diff --git a/src/core/hle/service/time/time_s.h b/src/core/hle/service/time/time_s.h index abc2a8c5a..4a2daa513 100644 --- a/src/core/hle/service/time/time_s.h +++ b/src/core/hle/service/time/time_s.h @@ -6,13 +6,11 @@ #include "core/hle/service/time/time.h" -namespace Service { -namespace Time { +namespace Service::Time { class TIME_S final : public Module::Interface { public: explicit TIME_S(std::shared_ptr<Module> time); }; -} // namespace Time -} // namespace Service +} // namespace Service::Time diff --git a/src/core/hle/service/time/time_u.cpp b/src/core/hle/service/time/time_u.cpp index fc1ace325..1ed42c419 100644 --- a/src/core/hle/service/time/time_u.cpp +++ b/src/core/hle/service/time/time_u.cpp @@ -4,8 +4,7 @@ #include "core/hle/service/time/time_u.h" -namespace Service { -namespace Time { +namespace Service::Time { TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:u") { static const FunctionInfo functions[] = { @@ -14,9 +13,19 @@ TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time) {2, &TIME_U::GetStandardSteadyClock, "GetStandardSteadyClock"}, {3, &TIME_U::GetTimeZoneService, "GetTimeZoneService"}, {4, &TIME_U::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, + {5, nullptr, "GetEphemeralNetworkSystemClock"}, + {50, nullptr, "SetStandardSteadyClockInternalOffset"}, + {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, + {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, + {102, nullptr, "GetStandardUserSystemClockInitialYear"}, + {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, + {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, + {400, nullptr, "GetClockSnapshot"}, + {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, + {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, + {501, nullptr, "CalculateSpanBetween"}, }; RegisterHandlers(functions); } -} // namespace Time -} // namespace Service +} // namespace Service::Time diff --git a/src/core/hle/service/time/time_u.h b/src/core/hle/service/time/time_u.h index f99d25057..3724bcdc7 100644 --- a/src/core/hle/service/time/time_u.h +++ b/src/core/hle/service/time/time_u.h @@ -6,13 +6,11 @@ #include "core/hle/service/time/time.h" -namespace Service { -namespace Time { +namespace Service::Time { class TIME_U final : public Module::Interface { public: explicit TIME_U(std::shared_ptr<Module> time); }; -} // namespace Time -} // namespace Service +} // namespace Service::Time diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 0aa621dfe..e86556671 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -4,21 +4,24 @@ #include <algorithm> #include <array> +#include <memory> +#include <boost/optional.hpp> #include "common/alignment.h" #include "common/scope_exit.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" #include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_m.h" #include "core/hle/service/vi/vi_s.h" #include "core/hle/service/vi/vi_u.h" +#include "core/settings.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" -namespace Service { -namespace VI { +namespace Service::VI { struct DisplayInfo { char display_name[0x40]{"Default"}; @@ -146,7 +149,7 @@ private: class NativeWindow : public Parcel { public: - explicit NativeWindow(u32 id) : Parcel() { + explicit NativeWindow(u32 id) { data.id = id; } ~NativeWindow() override = default; @@ -193,7 +196,7 @@ public: class IGBPConnectResponseParcel : public Parcel { public: - explicit IGBPConnectResponseParcel(u32 width, u32 height) : Parcel() { + explicit IGBPConnectResponseParcel(u32 width, u32 height) { data.width = width; data.height = height; } @@ -243,10 +246,6 @@ public: }; class IGBPSetPreallocatedBufferResponseParcel : public Parcel { -public: - IGBPSetPreallocatedBufferResponseParcel() : Parcel() {} - ~IGBPSetPreallocatedBufferResponseParcel() override = default; - protected: void SerializeData() override { // TODO(Subv): Find out what this means @@ -285,7 +284,7 @@ static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong class IGBPDequeueBufferResponseParcel : public Parcel { public: - explicit IGBPDequeueBufferResponseParcel(u32 slot) : Parcel(), slot(slot) {} + explicit IGBPDequeueBufferResponseParcel(u32 slot) : slot(slot) {} ~IGBPDequeueBufferResponseParcel() override = default; protected: @@ -379,7 +378,7 @@ public: class IGBPQueueBufferResponseParcel : public Parcel { public: - explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) : Parcel() { + explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) { data.width = width; data.height = height; } @@ -420,7 +419,7 @@ public: class IGBPQueryResponseParcel : public Parcel { public: - explicit IGBPQueryResponseParcel(u32 value) : Parcel(), value(value) {} + explicit IGBPQueryResponseParcel(u32 value) : value(value) {} ~IGBPQueryResponseParcel() override = default; protected: @@ -471,7 +470,7 @@ private: u32 flags = rp.Pop<u32>(); auto buffer_queue = nv_flinger->GetBufferQueue(id); - LOG_DEBUG(Service_VI, "called, transaction=%x", transaction); + NGLOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); if (transaction == TransactionId::Connect) { IGBPConnectRequestParcel request{ctx.ReadBuffer()}; @@ -486,12 +485,30 @@ private: ctx.WriteBuffer(response.Serialize()); } else if (transaction == TransactionId::DequeueBuffer) { IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; - - u32 slot = buffer_queue->DequeueBuffer(request.data.pixel_format, request.data.width, - request.data.height); - - IGBPDequeueBufferResponseParcel response{slot}; - ctx.WriteBuffer(response.Serialize()); + const u32 width{request.data.width}; + const u32 height{request.data.height}; + boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); + + if (slot != boost::none) { + // Buffer is available + IGBPDequeueBufferResponseParcel response{*slot}; + ctx.WriteBuffer(response.Serialize()); + } else { + // Wait the current thread until a buffer becomes available + auto wait_event = ctx.SleepClientThread( + Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1, + [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, + ThreadWakeupReason reason) { + // Repeat TransactParcel DequeueBuffer when a buffer is available + auto buffer_queue = nv_flinger->GetBufferQueue(id); + boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); + IGBPDequeueBufferResponseParcel response{*slot}; + ctx.WriteBuffer(response.Serialize()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + }); + buffer_queue->SetBufferWaitEvent(std::move(wait_event)); + } } else if (transaction == TransactionId::RequestBuffer) { IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; @@ -515,7 +532,7 @@ private: IGBPQueryResponseParcel response{value}; ctx.WriteBuffer(response.Serialize()); } else if (transaction == TransactionId::CancelBuffer) { - LOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); + NGLOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); } else { ASSERT_MSG(false, "Unimplemented"); } @@ -530,7 +547,8 @@ private: s32 addval = rp.PopRaw<s32>(); u32 type = rp.Pop<u32>(); - LOG_WARNING(Service_VI, "(STUBBED) called id=%u, addval=%08X, type=%08X", id, addval, type); + NGLOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, + type); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -544,7 +562,7 @@ private: // TODO(Subv): Find out what this actually is. - LOG_WARNING(Service_VI, "(STUBBED) called id=%u, unknown=%08X", id, unknown); + NGLOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(buffer_queue->GetNativeHandle()); @@ -558,7 +576,48 @@ public: ISystemDisplayService() : ServiceFramework("ISystemDisplayService") { static const FunctionInfo functions[] = { {1200, nullptr, "GetZOrderCountMin"}, + {1202, nullptr, "GetZOrderCountMax"}, + {1203, nullptr, "GetDisplayLogicalResolution"}, + {1204, nullptr, "SetDisplayMagnification"}, + {2201, nullptr, "SetLayerPosition"}, + {2203, nullptr, "SetLayerSize"}, + {2204, nullptr, "GetLayerZ"}, {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"}, + {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"}, + {2209, nullptr, "SetLayerAlpha"}, + {2312, nullptr, "CreateStrayLayer"}, + {2400, nullptr, "OpenIndirectLayer"}, + {2401, nullptr, "CloseIndirectLayer"}, + {2402, nullptr, "FlipIndirectLayer"}, + {3000, nullptr, "ListDisplayModes"}, + {3001, nullptr, "ListDisplayRgbRanges"}, + {3002, nullptr, "ListDisplayContentTypes"}, + {3200, nullptr, "GetDisplayMode"}, + {3201, nullptr, "SetDisplayMode"}, + {3202, nullptr, "GetDisplayUnderscan"}, + {3203, nullptr, "SetDisplayUnderscan"}, + {3204, nullptr, "GetDisplayContentType"}, + {3205, nullptr, "SetDisplayContentType"}, + {3206, nullptr, "GetDisplayRgbRange"}, + {3207, nullptr, "SetDisplayRgbRange"}, + {3208, nullptr, "GetDisplayCmuMode"}, + {3209, nullptr, "SetDisplayCmuMode"}, + {3210, nullptr, "GetDisplayContrastRatio"}, + {3211, nullptr, "SetDisplayContrastRatio"}, + {3214, nullptr, "GetDisplayGamma"}, + {3215, nullptr, "SetDisplayGamma"}, + {3216, nullptr, "GetDisplayCmuLuma"}, + {3217, nullptr, "SetDisplayCmuLuma"}, + {8225, nullptr, "GetSharedBufferMemoryHandleId"}, + {8250, nullptr, "OpenSharedLayer"}, + {8251, nullptr, "CloseSharedLayer"}, + {8252, nullptr, "ConnectSharedLayer"}, + {8253, nullptr, "DisconnectSharedLayer"}, + {8254, nullptr, "AcquireSharedFrameBuffer"}, + {8255, nullptr, "PresentSharedFrameBuffer"}, + {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"}, + {8257, nullptr, "FillSharedFrameBufferColor"}, + {8258, nullptr, "CancelSharedFrameBuffer"}, }; RegisterHandlers(functions); } @@ -566,7 +625,7 @@ public: private: void SetLayerZ(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + NGLOG_WARNING(Service_VI, "(STUBBED) called"); IPC::RequestParser rp{ctx}; u64 layer_id = rp.Pop<u64>(); u64 z_value = rp.Pop<u64>(); @@ -574,6 +633,16 @@ private: IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); rb.Push(RESULT_SUCCESS); } + + void SetLayerVisibility(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + u64 layer_id = rp.Pop<u64>(); + bool visibility = rp.Pop<bool>(); + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + rb.Push(RESULT_SUCCESS); + NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, + visibility); + } }; class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { @@ -581,10 +650,72 @@ public: explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { static const FunctionInfo functions[] = { + {200, nullptr, "AllocateProcessHeapBlock"}, + {201, nullptr, "FreeProcessHeapBlock"}, {1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"}, {1102, nullptr, "GetDisplayResolution"}, {2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"}, + {2011, nullptr, "DestroyManagedLayer"}, + {2050, nullptr, "CreateIndirectLayer"}, + {2051, nullptr, "DestroyIndirectLayer"}, + {2052, nullptr, "CreateIndirectProducerEndPoint"}, + {2053, nullptr, "DestroyIndirectProducerEndPoint"}, + {2054, nullptr, "CreateIndirectConsumerEndPoint"}, + {2055, nullptr, "DestroyIndirectConsumerEndPoint"}, + {2300, nullptr, "AcquireLayerTexturePresentingEvent"}, + {2301, nullptr, "ReleaseLayerTexturePresentingEvent"}, + {2302, nullptr, "GetDisplayHotplugEvent"}, + {2402, nullptr, "GetDisplayHotplugState"}, + {2501, nullptr, "GetCompositorErrorInfo"}, + {2601, nullptr, "GetDisplayErrorEvent"}, + {4201, nullptr, "SetDisplayAlpha"}, + {4203, nullptr, "SetDisplayLayerStack"}, + {4205, nullptr, "SetDisplayPowerState"}, + {4206, nullptr, "SetDefaultDisplay"}, {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"}, + {6001, nullptr, "RemoveFromLayerStack"}, + {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"}, + {6003, nullptr, "SetLayerConfig"}, + {6004, nullptr, "AttachLayerPresentationTracer"}, + {6005, nullptr, "DetachLayerPresentationTracer"}, + {6006, nullptr, "StartLayerPresentationRecording"}, + {6007, nullptr, "StopLayerPresentationRecording"}, + {6008, nullptr, "StartLayerPresentationFenceWait"}, + {6009, nullptr, "StopLayerPresentationFenceWait"}, + {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"}, + {7000, nullptr, "SetContentVisibility"}, + {8000, nullptr, "SetConductorLayer"}, + {8100, nullptr, "SetIndirectProducerFlipOffset"}, + {8200, nullptr, "CreateSharedBufferStaticStorage"}, + {8201, nullptr, "CreateSharedBufferTransferMemory"}, + {8202, nullptr, "DestroySharedBuffer"}, + {8203, nullptr, "BindSharedLowLevelLayerToManagedLayer"}, + {8204, nullptr, "BindSharedLowLevelLayerToIndirectLayer"}, + {8207, nullptr, "UnbindSharedLowLevelLayer"}, + {8208, nullptr, "ConnectSharedLowLevelLayerToSharedBuffer"}, + {8209, nullptr, "DisconnectSharedLowLevelLayerFromSharedBuffer"}, + {8210, nullptr, "CreateSharedLayer"}, + {8211, nullptr, "DestroySharedLayer"}, + {8216, nullptr, "AttachSharedLayerToLowLevelLayer"}, + {8217, nullptr, "ForceDetachSharedLayerFromLowLevelLayer"}, + {8218, nullptr, "StartDetachSharedLayerFromLowLevelLayer"}, + {8219, nullptr, "FinishDetachSharedLayerFromLowLevelLayer"}, + {8220, nullptr, "GetSharedLayerDetachReadyEvent"}, + {8221, nullptr, "GetSharedLowLevelLayerSynchronizedEvent"}, + {8222, nullptr, "CheckSharedLowLevelLayerSynchronized"}, + {8223, nullptr, "RegisterSharedBufferImporterAruid"}, + {8224, nullptr, "UnregisterSharedBufferImporterAruid"}, + {8227, nullptr, "CreateSharedBufferProcessHeap"}, + {8228, nullptr, "GetSharedLayerLayerStacks"}, + {8229, nullptr, "SetSharedLayerLayerStacks"}, + {8291, nullptr, "PresentDetachedSharedFrameBufferToLowLevelLayer"}, + {8292, nullptr, "FillDetachedSharedFrameBufferColor"}, + {8293, nullptr, "GetDetachedSharedFrameBufferImage"}, + {8294, nullptr, "SetDetachedSharedFrameBufferImage"}, + {8295, nullptr, "CopyDetachedSharedFrameBufferImage"}, + {8296, nullptr, "SetDetachedSharedFrameBufferSubImage"}, + {8297, nullptr, "GetSharedFrameBufferContentParameter"}, + {8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"}, }; RegisterHandlers(functions); } @@ -592,7 +723,7 @@ public: private: void CloseDisplay(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + NGLOG_WARNING(Service_VI, "(STUBBED) called"); IPC::RequestParser rp{ctx}; u64 display = rp.Pop<u64>(); @@ -601,7 +732,7 @@ private: } void CreateManagedLayer(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + NGLOG_WARNING(Service_VI, "(STUBBED) called"); IPC::RequestParser rp{ctx}; u32 unknown = rp.Pop<u32>(); rp.Skip(1, false); @@ -616,7 +747,7 @@ private: } void AddToLayerStack(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + NGLOG_WARNING(Service_VI, "(STUBBED) called"); IPC::RequestParser rp{ctx}; u32 stack = rp.Pop<u32>(); u64 layer_id = rp.Pop<u64>(); @@ -625,147 +756,182 @@ private: rb.Push(RESULT_SUCCESS); } + void SetLayerVisibility(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + u64 layer_id = rp.Pop<u64>(); + bool visibility = rp.Pop<bool>(); + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + rb.Push(RESULT_SUCCESS); + NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, + visibility); + } + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; }; -void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); +class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { +public: + IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~IApplicationDisplayService() = default; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); -} +private: + void GetRelayService(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); -void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); + } - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ISystemDisplayService>(); -} + void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); -void IApplicationDisplayService::GetManagerDisplayService(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISystemDisplayService>(); + } - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IManagerDisplayService>(nv_flinger); -} + void GetManagerDisplayService(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); -void IApplicationDisplayService::GetIndirectDisplayTransactionService( - Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IManagerDisplayService>(nv_flinger); + } - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); -} + void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); -void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); + } - std::string name(name_buf.begin(), end); + void OpenDisplay(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); + auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); - ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); + std::string name(name_buf.begin(), end); - IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); - rb.Push(RESULT_SUCCESS); - rb.Push<u64>(nv_flinger->OpenDisplay(name)); -} + ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); -void IApplicationDisplayService::CloseDisplay(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(nv_flinger->OpenDisplay(name)); + } - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); - rb.Push(RESULT_SUCCESS); -} + void CloseDisplay(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u64 display_id = rp.Pop<u64>(); -void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_VI, "called"); - IPC::RequestParser rp{ctx}; - auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + rb.Push(RESULT_SUCCESS); + } - std::string display_name(name_buf.begin(), end); + void GetDisplayResolution(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u64 display_id = rp.Pop<u64>(); - u64 layer_id = rp.Pop<u64>(); - u64 aruid = rp.Pop<u64>(); + IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); + rb.Push(RESULT_SUCCESS); - u64 display_id = nv_flinger->OpenDisplay(display_name); - u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); + if (Settings::values.use_docked_mode) { + rb.Push(static_cast<u64>(DisplayResolution::DockedWidth)); + rb.Push(static_cast<u64>(DisplayResolution::DockedHeight)); + } else { + rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth)); + rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight)); + } + } - NativeWindow native_window{buffer_queue_id}; - IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); - rb.Push(RESULT_SUCCESS); - rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); -} + void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u32 scaling_mode = rp.Pop<u32>(); + u64 unknown = rp.Pop<u64>(); -void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_VI, "called"); + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + rb.Push(RESULT_SUCCESS); + } - IPC::RequestParser rp{ctx}; - u32 flags = rp.Pop<u32>(); - rp.Pop<u32>(); // padding - u64 display_id = rp.Pop<u64>(); + void ListDisplays(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + DisplayInfo display_info; + ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); + IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(1); + NGLOG_WARNING(Service_VI, "(STUBBED) called"); + } - // TODO(Subv): What's the difference between a Stray and a Managed layer? + void OpenLayer(Kernel::HLERequestContext& ctx) { + NGLOG_DEBUG(Service_VI, "called"); + IPC::RequestParser rp{ctx}; + auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); + auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); - u64 layer_id = nv_flinger->CreateLayer(display_id); - u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); + std::string display_name(name_buf.begin(), end); - NativeWindow native_window{buffer_queue_id}; - IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); - rb.Push(RESULT_SUCCESS); - rb.Push(layer_id); - rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); -} + u64 layer_id = rp.Pop<u64>(); + u64 aruid = rp.Pop<u64>(); -void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + u64 display_id = nv_flinger->OpenDisplay(display_name); + u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); - IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); + NativeWindow native_window{buffer_queue_id}; + IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); + } - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); - rb.Push(RESULT_SUCCESS); -} + void CreateStrayLayer(Kernel::HLERequestContext& ctx) { + NGLOG_DEBUG(Service_VI, "called"); -void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 scaling_mode = rp.Pop<u32>(); - u64 unknown = rp.Pop<u64>(); + IPC::RequestParser rp{ctx}; + u32 flags = rp.Pop<u32>(); + rp.Pop<u32>(); // padding + u64 display_id = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); - rb.Push(RESULT_SUCCESS); -} + // TODO(Subv): What's the difference between a Stray and a Managed layer? -void IApplicationDisplayService::ListDisplays(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - DisplayInfo display_info; - ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); - IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); - rb.Push(RESULT_SUCCESS); - rb.Push<u64>(1); - LOG_WARNING(Service_VI, "(STUBBED) called"); -} + u64 layer_id = nv_flinger->CreateLayer(display_id); + u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); -void IApplicationDisplayService::GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + NativeWindow native_window{buffer_queue_id}; + IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(layer_id); + rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); + } - auto vsync_event = nv_flinger->GetVsyncEvent(display_id); + void DestroyStrayLayer(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0); - rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(vsync_event); -} + IPC::RequestParser rp{ctx}; + u64 layer_id = rp.Pop<u64>(); + + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + rb.Push(RESULT_SUCCESS); + } + + void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u64 display_id = rp.Pop<u64>(); + + auto vsync_event = nv_flinger->GetVsyncEvent(display_id); + + IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0); + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(vsync_event); + } + + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; +}; IApplicationDisplayService::IApplicationDisplayService( std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) @@ -778,22 +944,43 @@ IApplicationDisplayService::IApplicationDisplayService( "GetIndirectDisplayTransactionService"}, {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"}, {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"}, + {1011, nullptr, "OpenDefaultDisplay"}, {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"}, - {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, + {1101, nullptr, "SetDisplayEnabled"}, + {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"}, {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"}, + {2021, nullptr, "CloseLayer"}, {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"}, {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"}, + {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, + {2102, nullptr, "ConvertScalingMode"}, + {2450, nullptr, "GetIndirectLayerImageMap"}, + {2451, nullptr, "GetIndirectLayerImageCropMap"}, + {2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"}, {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"}, + {5203, nullptr, "GetDisplayVsyncEventForDebug"}, }; RegisterHandlers(functions); } +Module::Interface::Interface(std::shared_ptr<Module> module, const char* name, + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) + : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} + +void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_VI, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); +} + void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { - std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager); - std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager); - std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); + auto module = std::make_shared<Module>(); + std::make_shared<VI_M>(module, nv_flinger)->InstallAsService(service_manager); + std::make_shared<VI_S>(module, nv_flinger)->InstallAsService(service_manager); + std::make_shared<VI_U>(module, nv_flinger)->InstallAsService(service_manager); } -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index f6be7d1e6..e8bda01d7 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -4,9 +4,6 @@ #pragma once -#include <memory> -#include <boost/optional.hpp> -#include "core/hle/kernel/event.h" #include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/service.h" @@ -14,34 +11,32 @@ namespace CoreTiming { struct EventType; } -namespace Service { -namespace VI { +namespace Service::VI { -class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { +enum class DisplayResolution : u32 { + DockedWidth = 1920, + DockedHeight = 1080, + UndockedWidth = 1280, + UndockedHeight = 720, +}; + +class Module final { public: - IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); - ~IApplicationDisplayService() = default; - -private: - void GetRelayService(Kernel::HLERequestContext& ctx); - void GetSystemDisplayService(Kernel::HLERequestContext& ctx); - void GetManagerDisplayService(Kernel::HLERequestContext& ctx); - void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx); - void OpenDisplay(Kernel::HLERequestContext& ctx); - void CloseDisplay(Kernel::HLERequestContext& ctx); - void SetLayerScalingMode(Kernel::HLERequestContext& ctx); - void ListDisplays(Kernel::HLERequestContext& ctx); - void OpenLayer(Kernel::HLERequestContext& ctx); - void CreateStrayLayer(Kernel::HLERequestContext& ctx); - void DestroyStrayLayer(Kernel::HLERequestContext& ctx); - void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); - - std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; + class Interface : public ServiceFramework<Interface> { + public: + Interface(std::shared_ptr<Module> module, const char* name, + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + + void GetDisplayService(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr<Module> module; + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; + }; }; /// Registers all VI services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 5d99647dc..d47da565b 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp @@ -2,24 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_m.h" -namespace Service { -namespace VI { +namespace Service::VI { -void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); -} - -VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) - : ServiceFramework("vi:m"), nv_flinger(std::move(nv_flinger)) { +VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) + : Module::Interface(std::move(module), "vi:m", std::move(nv_flinger)) { static const FunctionInfo functions[] = { {2, &VI_M::GetDisplayService, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -27,5 +15,4 @@ VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) RegisterHandlers(functions); } -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index e5319b1e7..6abb9b3a3 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h @@ -4,26 +4,13 @@ #pragma once -#include <memory> -#include "core/hle/service/service.h" +#include "core/hle/service/vi/vi.h" -namespace Service { -namespace NVFlinger { -class NVFlinger; -} +namespace Service::VI { -namespace VI { - -class VI_M final : public ServiceFramework<VI_M> { +class VI_M final : public Module::Interface { public: - VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); - ~VI_M() = default; - -private: - void GetDisplayService(Kernel::HLERequestContext& ctx); - - std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; + explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); }; -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 411757981..8f82e797f 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp @@ -2,24 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_s.h" -namespace Service { -namespace VI { +namespace Service::VI { -void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); -} - -VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) - : ServiceFramework("vi:s"), nv_flinger(std::move(nv_flinger)) { +VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) + : Module::Interface(std::move(module), "vi:s", std::move(nv_flinger)) { static const FunctionInfo functions[] = { {1, &VI_S::GetDisplayService, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -27,5 +15,4 @@ VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) RegisterHandlers(functions); } -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index 6978fd700..8f16f804f 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h @@ -4,26 +4,13 @@ #pragma once -#include <memory> -#include "core/hle/service/service.h" +#include "core/hle/service/vi/vi.h" -namespace Service { -namespace NVFlinger { -class NVFlinger; -} +namespace Service::VI { -namespace VI { - -class VI_S final : public ServiceFramework<VI_S> { +class VI_S final : public Module::Interface { public: - VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); - ~VI_S() = default; - -private: - void GetDisplayService(Kernel::HLERequestContext& ctx); - - std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; + explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); }; -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index f5568383b..b84aed1d5 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -2,30 +2,16 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_u.h" -namespace Service { -namespace VI { +namespace Service::VI { -void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); -} - -VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) - : ServiceFramework("vi:u"), nv_flinger(std::move(nv_flinger)) { +VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) + : Module::Interface(std::move(module), "vi:u", std::move(nv_flinger)) { static const FunctionInfo functions[] = { {0, &VI_U::GetDisplayService, "GetDisplayService"}, - {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, }; RegisterHandlers(functions); } -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index b3e9c094d..e9b4f76b2 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h @@ -4,26 +4,13 @@ #pragma once -#include <memory> -#include "core/hle/service/service.h" +#include "core/hle/service/vi/vi.h" -namespace Service { -namespace NVFlinger { -class NVFlinger; -} +namespace Service::VI { -namespace VI { - -class VI_U final : public ServiceFramework<VI_U> { +class VI_U final : public Module::Interface { public: - VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); - ~VI_U() = default; - -private: - void GetDisplayService(Kernel::HLERequestContext& ctx); - - std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; + explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); }; -} // namespace VI -} // namespace Service +} // namespace Service::VI diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index bba4a0715..9ed8ab249 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp @@ -56,13 +56,14 @@ static void UpdateTimeCallback(u64 userdata, int cycles_late) { date_time.date_time = GetSystemTime(); date_time.update_tick = CoreTiming::GetTicks(); - date_time.tick_to_second_coefficient = BASE_CLOCK_RATE; + date_time.tick_to_second_coefficient = CoreTiming::BASE_CLOCK_RATE; date_time.tick_offset = 0; ++shared_page.date_time_counter; // system time is updated hourly - CoreTiming::ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event); + CoreTiming::ScheduleEvent(CoreTiming::msToCycles(60 * 60 * 1000) - cycles_late, + update_time_event); } void Init() { |