diff options
author | Morph <39850852+Morph1984@users.noreply.github.com> | 2023-03-04 04:51:17 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-04 04:51:17 +0100 |
commit | ce8f4da63834be0179d98a7720dee47d65f3ec06 (patch) | |
tree | a9a9303a532d374db9ae8255e5f3f2487e370f84 /src/core/hle/kernel | |
parent | Merge pull request #9855 from liamwhite/kern-16-support (diff) | |
parent | nvnflinger: fix name (diff) | |
download | yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar.gz yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar.bz2 yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar.lz yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar.xz yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar.zst yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.zip |
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 531 | ||||
-rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 421 | ||||
-rw-r--r-- | src/core/hle/kernel/k_client_port.cpp | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/k_client_port.h | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/k_client_session.cpp | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/k_port.cpp | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 11 | ||||
-rw-r--r-- | src/core/hle/kernel/k_server_session.h | 12 |
8 files changed, 13 insertions, 966 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp deleted file mode 100644 index 876fbbe53..000000000 --- a/src/core/hle/kernel/hle_ipc.cpp +++ /dev/null @@ -1,531 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <algorithm> -#include <array> -#include <sstream> - -#include <boost/range/algorithm_ext/erase.hpp> - -#include "common/assert.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "common/scratch_buffer.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/k_auto_object.h" -#include "core/hle/kernel/k_handle_table.h" -#include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_server_port.h" -#include "core/hle/kernel/k_server_session.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/kernel.h" -#include "core/memory.h" - -namespace Kernel { - -SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_) - : kernel{kernel_} {} - -SessionRequestHandler::~SessionRequestHandler() = default; - -SessionRequestManager::SessionRequestManager(KernelCore& kernel_, - Service::ServerManager& server_manager_) - : kernel{kernel_}, server_manager{server_manager_} {} - -SessionRequestManager::~SessionRequestManager() = default; - -bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& context) const { - if (IsDomain() && context.HasDomainMessageHeader()) { - const auto& message_header = context.GetDomainMessageHeader(); - const auto object_id = message_header.object_id; - - if (object_id > DomainHandlerCount()) { - LOG_CRITICAL(IPC, "object_id {} is too big!", object_id); - return false; - } - return !DomainHandler(object_id - 1).expired(); - } else { - return session_handler != nullptr; - } -} - -Result SessionRequestManager::CompleteSyncRequest(KServerSession* server_session, - HLERequestContext& context) { - Result result = ResultSuccess; - - // If the session has been converted to a domain, handle the domain request - if (this->HasSessionRequestHandler(context)) { - if (IsDomain() && context.HasDomainMessageHeader()) { - result = HandleDomainSyncRequest(server_session, context); - // If there is no domain header, the regular session handler is used - } else if (this->HasSessionHandler()) { - // If this manager has an associated HLE handler, forward the request to it. - result = this->SessionHandler().HandleSyncRequest(*server_session, context); - } - } else { - ASSERT_MSG(false, "Session handler is invalid, stubbing response!"); - IPC::ResponseBuilder rb(context, 2); - rb.Push(ResultSuccess); - } - - if (convert_to_domain) { - ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); - this->ConvertToDomain(); - convert_to_domain = false; - } - - return result; -} - -Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_session, - HLERequestContext& context) { - if (!context.HasDomainMessageHeader()) { - return ResultSuccess; - } - - // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs - ASSERT(context.GetManager().get() == this); - - // If there is a DomainMessageHeader, then this is CommandType "Request" - const auto& domain_message_header = context.GetDomainMessageHeader(); - const u32 object_id{domain_message_header.object_id}; - switch (domain_message_header.command) { - case IPC::DomainMessageHeader::CommandType::SendMessage: - if (object_id > this->DomainHandlerCount()) { - LOG_CRITICAL(IPC, - "object_id {} is too big! This probably means a recent service call " - "needed to return a new interface!", - object_id); - ASSERT(false); - return ResultSuccess; // Ignore error if asserts are off - } - if (auto strong_ptr = this->DomainHandler(object_id - 1).lock()) { - return strong_ptr->HandleSyncRequest(*server_session, context); - } else { - ASSERT(false); - return ResultSuccess; - } - - case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { - LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); - - this->CloseDomainHandler(object_id - 1); - - IPC::ResponseBuilder rb{context, 2}; - rb.Push(ResultSuccess); - return ResultSuccess; - } - } - - LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value()); - ASSERT(false); - return ResultSuccess; -} - -HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, - KServerSession* server_session_, KThread* thread_) - : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { - cmd_buf[0] = 0; -} - -HLERequestContext::~HLERequestContext() = default; - -void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, - bool incoming) { - IPC::RequestParser rp(src_cmdbuf); - command_header = rp.PopRaw<IPC::CommandHeader>(); - - if (command_header->IsCloseCommand()) { - // Close does not populate the rest of the IPC header - return; - } - - // If handle descriptor is present, add size of it - if (command_header->enable_handle_descriptor) { - handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); - if (handle_descriptor_header->send_current_pid) { - pid = rp.Pop<u64>(); - } - if (incoming) { - // Populate the object lists with the data in the IPC request. - incoming_copy_handles.reserve(handle_descriptor_header->num_handles_to_copy); - incoming_move_handles.reserve(handle_descriptor_header->num_handles_to_move); - - for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { - incoming_copy_handles.push_back(rp.Pop<Handle>()); - } - for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { - incoming_move_handles.push_back(rp.Pop<Handle>()); - } - } else { - // For responses we just ignore the handles, they're empty and will be populated when - // translating the response. - rp.Skip(handle_descriptor_header->num_handles_to_copy, false); - rp.Skip(handle_descriptor_header->num_handles_to_move, false); - } - } - - buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); - buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); - buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); - buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); - - for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { - buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); - } - for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { - buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); - } - for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { - buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); - } - for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { - buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); - } - - const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; - - if (!command_header->IsTipc()) { - // Padding to align to 16 bytes - rp.AlignWithPadding(); - - if (GetManager()->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 = rp.PopRaw<IPC::DomainMessageHeader>(); - } else { - if (GetManager()->IsDomain()) { - LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); - } - } - } - - data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>(); - - data_payload_offset = rp.GetCurrentOffset(); - - if (domain_message_header && - domain_message_header->command == - IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { - // CloseVirtualHandle command does not have SFC* or any data - return; - } - - if (incoming) { - ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); - } else { - ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); - } - } - - rp.SetCurrentOffset(buffer_c_offset); - - // For Inline buffers, the response data is written directly to buffer_c_offset - // and in this case we don't have any BufferDescriptorC on the request. - if (command_header->buf_c_descriptor_flags > - IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { - if (command_header->buf_c_descriptor_flags == - IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { - buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); - } else { - u32 num_buf_c_descriptors = - static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; - - // This is used to detect possible underflows, in case something is broken - // with the two ifs above and the flags value is == 0 || == 1. - ASSERT(num_buf_c_descriptors < 14); - - for (u32 i = 0; i < num_buf_c_descriptors; ++i) { - buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); - } - } - } - - rp.SetCurrentOffset(data_payload_offset); - - command = rp.Pop<u32_le>(); - rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. -} - -Result HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, - u32_le* src_cmdbuf) { - ParseCommandBuffer(handle_table, src_cmdbuf, true); - - if (command_header->IsCloseCommand()) { - // Close does not populate the rest of the IPC header - return ResultSuccess; - } - - std::copy_n(src_cmdbuf, IPC::COMMAND_BUFFER_LENGTH, cmd_buf.begin()); - - return ResultSuccess; -} - -Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) { - auto current_offset = handles_offset; - auto& owner_process = *requesting_thread.GetOwnerProcess(); - auto& handle_table = owner_process.GetHandleTable(); - - for (auto& object : outgoing_copy_objects) { - Handle handle{}; - if (object) { - R_TRY(handle_table.Add(&handle, object)); - } - cmd_buf[current_offset++] = handle; - } - for (auto& object : outgoing_move_objects) { - Handle handle{}; - if (object) { - R_TRY(handle_table.Add(&handle, object)); - - // Close our reference to the object, as it is being moved to the caller. - object->Close(); - } - cmd_buf[current_offset++] = handle; - } - - // Write the domain objects to the command buffer, these go after the raw untranslated data. - // TODO(Subv): This completely ignores C buffers. - - if (GetManager()->IsDomain()) { - current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); - for (auto& object : outgoing_domain_objects) { - GetManager()->AppendDomainHandler(std::move(object)); - cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount()); - } - } - - // Copy the translated command buffer back into the thread's command buffer area. - memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), - write_size * sizeof(u32)); - - return ResultSuccess; -} - -std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) const { - const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && - BufferDescriptorA()[buffer_index].Size()}; - if (is_buffer_a) { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorA().size() > buffer_index, { return {}; }, - "BufferDescriptorA invalid buffer_index {}", buffer_index); - std::vector<u8> buffer(BufferDescriptorA()[buffer_index].Size()); - memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); - return buffer; - } else { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorX().size() > buffer_index, { return {}; }, - "BufferDescriptorX invalid buffer_index {}", buffer_index); - std::vector<u8> buffer(BufferDescriptorX()[buffer_index].Size()); - memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); - return buffer; - } -} - -std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { - static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a; - static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x; - - const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && - BufferDescriptorA()[buffer_index].Size()}; - if (is_buffer_a) { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorA().size() > buffer_index, { return {}; }, - "BufferDescriptorA invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_a[buffer_index]; - read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size()); - memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(), - read_buffer.size()); - return read_buffer; - } else { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorX().size() > buffer_index, { return {}; }, - "BufferDescriptorX invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_x[buffer_index]; - read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size()); - memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(), - read_buffer.size()); - return read_buffer; - } -} - -std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, - std::size_t buffer_index) const { - if (size == 0) { - LOG_WARNING(Core, "skip empty buffer write"); - return 0; - } - - const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && - BufferDescriptorB()[buffer_index].Size()}; - const std::size_t buffer_size{GetWriteBufferSize(buffer_index)}; - if (size > buffer_size) { - LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, - buffer_size); - size = buffer_size; // TODO(bunnei): This needs to be HW tested - } - - if (is_buffer_b) { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorB().size() > buffer_index && - BufferDescriptorB()[buffer_index].Size() >= size, - { return 0; }, "BufferDescriptorB is invalid, index={}, size={}", buffer_index, size); - WriteBufferB(buffer, size, buffer_index); - } else { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorC().size() > buffer_index && - BufferDescriptorC()[buffer_index].Size() >= size, - { return 0; }, "BufferDescriptorC is invalid, index={}, size={}", buffer_index, size); - WriteBufferC(buffer, size, buffer_index); - } - - return size; -} - -std::size_t HLERequestContext::WriteBufferB(const void* buffer, std::size_t size, - std::size_t buffer_index) const { - if (buffer_index >= BufferDescriptorB().size() || size == 0) { - return 0; - } - - const auto buffer_size{BufferDescriptorB()[buffer_index].Size()}; - if (size > buffer_size) { - LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, - buffer_size); - size = buffer_size; // TODO(bunnei): This needs to be HW tested - } - - memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); - return size; -} - -std::size_t HLERequestContext::WriteBufferC(const void* buffer, std::size_t size, - std::size_t buffer_index) const { - if (buffer_index >= BufferDescriptorC().size() || size == 0) { - return 0; - } - - const auto buffer_size{BufferDescriptorC()[buffer_index].Size()}; - if (size > buffer_size) { - LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, - buffer_size); - size = buffer_size; // TODO(bunnei): This needs to be HW tested - } - - memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); - return size; -} - -std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const { - const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && - BufferDescriptorA()[buffer_index].Size()}; - if (is_buffer_a) { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorA().size() > buffer_index, { return 0; }, - "BufferDescriptorA invalid buffer_index {}", buffer_index); - return BufferDescriptorA()[buffer_index].Size(); - } else { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorX().size() > buffer_index, { return 0; }, - "BufferDescriptorX invalid buffer_index {}", buffer_index); - return BufferDescriptorX()[buffer_index].Size(); - } -} - -std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) const { - const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && - BufferDescriptorB()[buffer_index].Size()}; - if (is_buffer_b) { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorB().size() > buffer_index, { return 0; }, - "BufferDescriptorB invalid buffer_index {}", buffer_index); - return BufferDescriptorB()[buffer_index].Size(); - } else { - ASSERT_OR_EXECUTE_MSG( - BufferDescriptorC().size() > buffer_index, { return 0; }, - "BufferDescriptorC invalid buffer_index {}", buffer_index); - return BufferDescriptorC()[buffer_index].Size(); - } - return 0; -} - -bool HLERequestContext::CanReadBuffer(std::size_t buffer_index) const { - const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && - BufferDescriptorA()[buffer_index].Size()}; - - if (is_buffer_a) { - return BufferDescriptorA().size() > buffer_index; - } else { - return BufferDescriptorX().size() > buffer_index; - } -} - -bool HLERequestContext::CanWriteBuffer(std::size_t buffer_index) const { - const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && - BufferDescriptorB()[buffer_index].Size()}; - - if (is_buffer_b) { - return BufferDescriptorB().size() > buffer_index; - } else { - return BufferDescriptorC().size() > buffer_index; - } -} - -std::string HLERequestContext::Description() const { - if (!command_header) { - return "No command header available"; - } - std::ostringstream s; - s << "IPC::CommandHeader: Type:" << static_cast<u32>(command_header->type.Value()); - s << ", X(Pointer):" << command_header->num_buf_x_descriptors; - if (command_header->num_buf_x_descriptors) { - s << '['; - for (u64 i = 0; i < command_header->num_buf_x_descriptors; ++i) { - s << "0x" << std::hex << BufferDescriptorX()[i].Size(); - if (i < command_header->num_buf_x_descriptors - 1) - s << ", "; - } - s << ']'; - } - s << ", A(Send):" << command_header->num_buf_a_descriptors; - if (command_header->num_buf_a_descriptors) { - s << '['; - for (u64 i = 0; i < command_header->num_buf_a_descriptors; ++i) { - s << "0x" << std::hex << BufferDescriptorA()[i].Size(); - if (i < command_header->num_buf_a_descriptors - 1) - s << ", "; - } - s << ']'; - } - s << ", B(Receive):" << command_header->num_buf_b_descriptors; - if (command_header->num_buf_b_descriptors) { - s << '['; - for (u64 i = 0; i < command_header->num_buf_b_descriptors; ++i) { - s << "0x" << std::hex << BufferDescriptorB()[i].Size(); - if (i < command_header->num_buf_b_descriptors - 1) - s << ", "; - } - s << ']'; - } - s << ", C(ReceiveList):" << BufferDescriptorC().size(); - if (!BufferDescriptorC().empty()) { - s << '['; - for (u64 i = 0; i < BufferDescriptorC().size(); ++i) { - s << "0x" << std::hex << BufferDescriptorC()[i].Size(); - if (i < BufferDescriptorC().size() - 1) - s << ", "; - } - s << ']'; - } - s << ", data_size:" << command_header->data_size.Value(); - - return s.str(); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h deleted file mode 100644 index b4364f984..000000000 --- a/src/core/hle/kernel/hle_ipc.h +++ /dev/null @@ -1,421 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <functional> -#include <memory> -#include <optional> -#include <span> -#include <string> -#include <type_traits> -#include <vector> - -#include "common/assert.h" -#include "common/common_types.h" -#include "common/concepts.h" -#include "common/swap.h" -#include "core/hle/ipc.h" -#include "core/hle/kernel/svc_common.h" - -union Result; - -namespace Core::Memory { -class Memory; -} - -namespace IPC { -class ResponseBuilder; -} - -namespace Service { -class ServiceFrameworkBase; -class ServerManager; -} // namespace Service - -namespace Kernel { - -class Domain; -class HLERequestContext; -class KAutoObject; -class KernelCore; -class KEvent; -class KHandleTable; -class KServerPort; -class KProcess; -class KServerSession; -class KThread; -class KReadableEvent; -class KSession; -class SessionRequestManager; - -/** - * Interface implemented by HLE Session handlers. - * This can be provided to a ServerSession in order to hook into several relevant events - * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. - */ -class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { -public: - SessionRequestHandler(KernelCore& kernel_, const char* service_name_); - virtual ~SessionRequestHandler(); - - /** - * Handles a sync request from the emulated application. - * @param server_session The ServerSession that was triggered for this sync request, - * it should be used to differentiate which client (As in ClientSession) we're answering to. - * TODO(Subv): Use a wrapper structure to hold all the information relevant to - * this request (ServerSession, Originator thread, Translated command buffer, etc). - * @returns Result the result code of the translate operation. - */ - virtual Result HandleSyncRequest(Kernel::KServerSession& session, - Kernel::HLERequestContext& context) = 0; - -protected: - KernelCore& kernel; -}; - -using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>; -using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; - -/** - * Manages the underlying HLE requests for a session, and whether (or not) the session should be - * treated as a domain. This is managed separately from server sessions, as this state is shared - * when objects are cloned. - */ -class SessionRequestManager final { -public: - explicit SessionRequestManager(KernelCore& kernel, Service::ServerManager& server_manager); - ~SessionRequestManager(); - - bool IsDomain() const { - return is_domain; - } - - void ConvertToDomain() { - domain_handlers = {session_handler}; - is_domain = true; - } - - void ConvertToDomainOnRequestEnd() { - convert_to_domain = true; - } - - std::size_t DomainHandlerCount() const { - return domain_handlers.size(); - } - - bool HasSessionHandler() const { - return session_handler != nullptr; - } - - SessionRequestHandler& SessionHandler() { - return *session_handler; - } - - const SessionRequestHandler& SessionHandler() const { - return *session_handler; - } - - void CloseDomainHandler(std::size_t index) { - if (index < DomainHandlerCount()) { - domain_handlers[index] = nullptr; - } else { - ASSERT_MSG(false, "Unexpected handler index {}", index); - } - } - - SessionRequestHandlerWeakPtr DomainHandler(std::size_t index) const { - ASSERT_MSG(index < DomainHandlerCount(), "Unexpected handler index {}", index); - return domain_handlers.at(index); - } - - void AppendDomainHandler(SessionRequestHandlerPtr&& handler) { - domain_handlers.emplace_back(std::move(handler)); - } - - void SetSessionHandler(SessionRequestHandlerPtr&& handler) { - session_handler = std::move(handler); - } - - bool HasSessionRequestHandler(const HLERequestContext& context) const; - - Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context); - Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context); - - Service::ServerManager& GetServerManager() { - return server_manager; - } - - // TODO: remove this when sm: is implemented with the proper IUserInterface - // abstraction, creating a new C++ handler object for each session: - - bool GetIsInitializedForSm() const { - return is_initialized_for_sm; - } - - void SetIsInitializedForSm() { - is_initialized_for_sm = true; - } - -private: - bool convert_to_domain{}; - bool is_domain{}; - bool is_initialized_for_sm{}; - SessionRequestHandlerPtr session_handler; - std::vector<SessionRequestHandlerPtr> domain_handlers; - -private: - KernelCore& kernel; - Service::ServerManager& server_manager; -}; - -/** - * Class containing information about an in-flight IPC request being handled by an HLE service - * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and - * when possible use the APIs in this class to service the request. - * - * HLE handle protocol - * =================== - * - * To avoid needing HLE services to keep a separate handle table, or having to directly modify the - * requester's table, a tweaked protocol is used to receive and send handles in requests. The kernel - * will decode the incoming handles into object pointers and insert a id in the buffer where the - * handle would normally be. The service then calls GetIncomingHandle() with that id to get the - * pointer to the object. Similarly, instead of inserting a handle into the command buffer, the - * service calls AddOutgoingHandle() and stores the returned id where the handle would normally go. - * - * The end result is similar to just giving services their own real handle tables, but since these - * ids are local to a specific context, it avoids requiring services to manage handles for objects - * across multiple calls and ensuring that unneeded handles are cleaned up. - */ -class HLERequestContext { -public: - explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, - KServerSession* session, KThread* thread); - ~HLERequestContext(); - - /// Returns a pointer to the IPC command buffer for this request. - [[nodiscard]] u32* CommandBuffer() { - return cmd_buf.data(); - } - - /** - * Returns the session through which this request was made. This can be used as a map key to - * access per-client data on services. - */ - [[nodiscard]] Kernel::KServerSession* Session() { - return server_session; - } - - /// Populates this context with data from the requesting process/thread. - Result PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf); - - /// Writes data from this context back to the requesting process/thread. - Result WriteToOutgoingCommandBuffer(KThread& requesting_thread); - - [[nodiscard]] u32_le GetHipcCommand() const { - return command; - } - - [[nodiscard]] u32_le GetTipcCommand() const { - return static_cast<u32_le>(command_header->type.Value()) - - static_cast<u32_le>(IPC::CommandType::TIPC_CommandRegion); - } - - [[nodiscard]] u32_le GetCommand() const { - return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand(); - } - - [[nodiscard]] bool IsTipc() const { - return command_header->IsTipc(); - } - - [[nodiscard]] IPC::CommandType GetCommandType() const { - return command_header->type; - } - - [[nodiscard]] u64 GetPID() const { - return pid; - } - - [[nodiscard]] u32 GetDataPayloadOffset() const { - return data_payload_offset; - } - - [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { - return buffer_x_desciptors; - } - - [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { - return buffer_a_desciptors; - } - - [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { - return buffer_b_desciptors; - } - - [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { - return buffer_c_desciptors; - } - - [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { - return domain_message_header.value(); - } - - [[nodiscard]] bool HasDomainMessageHeader() const { - return domain_message_header.has_value(); - } - - /// Helper function to get a span of a buffer using the appropriate buffer descriptor - [[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const; - - /// Helper function to read a copy of a buffer using the appropriate buffer descriptor - [[nodiscard]] std::vector<u8> ReadBufferCopy(std::size_t buffer_index = 0) const; - - /// Helper function to write a buffer using the appropriate buffer descriptor - std::size_t WriteBuffer(const void* buffer, std::size_t size, - std::size_t buffer_index = 0) const; - - /// Helper function to write buffer B - std::size_t WriteBufferB(const void* buffer, std::size_t size, - std::size_t buffer_index = 0) const; - - /// Helper function to write buffer C - std::size_t WriteBufferC(const void* buffer, std::size_t size, - std::size_t buffer_index = 0) const; - - /* Helper function to write a buffer using the appropriate buffer descriptor - * - * @tparam T an arbitrary container that satisfies the - * ContiguousContainer concept in the C++ standard library or a trivially copyable type. - * - * @param data The container/data to write into a buffer. - * @param buffer_index The buffer in particular to write to. - */ - template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>> - std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const { - if constexpr (Common::IsContiguousContainer<T>) { - using ContiguousType = typename T::value_type; - static_assert(std::is_trivially_copyable_v<ContiguousType>, - "Container to WriteBuffer must contain trivially copyable objects"); - return WriteBuffer(std::data(data), std::size(data) * sizeof(ContiguousType), - buffer_index); - } else { - static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); - return WriteBuffer(&data, sizeof(T), buffer_index); - } - } - - /// Helper function to get the size of the input buffer - [[nodiscard]] std::size_t GetReadBufferSize(std::size_t buffer_index = 0) const; - - /// Helper function to get the size of the output buffer - [[nodiscard]] std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const; - - /// Helper function to derive the number of elements able to be contained in the read buffer - template <typename T> - [[nodiscard]] std::size_t GetReadBufferNumElements(std::size_t buffer_index = 0) const { - return GetReadBufferSize(buffer_index) / sizeof(T); - } - - /// Helper function to derive the number of elements able to be contained in the write buffer - template <typename T> - [[nodiscard]] std::size_t GetWriteBufferNumElements(std::size_t buffer_index = 0) const { - return GetWriteBufferSize(buffer_index) / sizeof(T); - } - - /// Helper function to test whether the input buffer at buffer_index can be read - [[nodiscard]] bool CanReadBuffer(std::size_t buffer_index = 0) const; - - /// Helper function to test whether the output buffer at buffer_index can be written - [[nodiscard]] bool CanWriteBuffer(std::size_t buffer_index = 0) const; - - [[nodiscard]] Handle GetCopyHandle(std::size_t index) const { - return incoming_copy_handles.at(index); - } - - [[nodiscard]] Handle GetMoveHandle(std::size_t index) const { - return incoming_move_handles.at(index); - } - - void AddMoveObject(KAutoObject* object) { - outgoing_move_objects.emplace_back(object); - } - - void AddCopyObject(KAutoObject* object) { - outgoing_copy_objects.emplace_back(object); - } - - void AddDomainObject(SessionRequestHandlerPtr object) { - outgoing_domain_objects.emplace_back(std::move(object)); - } - - template <typename T> - std::shared_ptr<T> GetDomainHandler(std::size_t index) const { - return std::static_pointer_cast<T>(GetManager()->DomainHandler(index).lock()); - } - - void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) { - manager = manager_; - } - - [[nodiscard]] std::string Description() const; - - [[nodiscard]] KThread& GetThread() { - return *thread; - } - - [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { - return manager.lock(); - } - - bool GetIsDeferred() const { - return is_deferred; - } - - void SetIsDeferred(bool is_deferred_ = true) { - is_deferred = is_deferred_; - } - -private: - friend class IPC::ResponseBuilder; - - void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); - - std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; - Kernel::KServerSession* server_session{}; - KThread* thread; - - std::vector<Handle> incoming_move_handles; - std::vector<Handle> incoming_copy_handles; - - std::vector<KAutoObject*> outgoing_move_objects; - std::vector<KAutoObject*> outgoing_copy_objects; - std::vector<SessionRequestHandlerPtr> outgoing_domain_objects; - - std::optional<IPC::CommandHeader> command_header; - std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; - std::optional<IPC::DataPayloadHeader> data_payload_header; - std::optional<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; - std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; - std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; - - u32_le command{}; - u64 pid{}; - u32 write_size{}; - u32 data_payload_offset{}; - u32 handles_offset{}; - u32 domain_offset{}; - - std::weak_ptr<SessionRequestManager> manager{}; - bool is_deferred{false}; - - KernelCore& kernel; - Core::Memory::Memory& memory; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index c72a91a76..700ae71e3 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/scope_exit.h" -#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_scheduler.h" diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 81046fb86..a757cf9cd 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -15,7 +15,6 @@ namespace Kernel { class KClientSession; class KernelCore; class KPort; -class SessionRequestManager; class KClientPort final : public KSynchronizationObject { KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp index b4197a8d5..da0c9ac8c 100644 --- a/src/core/hle/kernel/k_client_session.cpp +++ b/src/core/hle/kernel/k_client_session.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/scope_exit.h" -#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index 77d00ae2c..0a45ffd57 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/svc_results.h" diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index aa1941f01..01591af5b 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -10,8 +10,6 @@ #include "common/scope_exit.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_process.h" @@ -22,6 +20,8 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/service/hle_ipc.h" +#include "core/hle/service/ipc_helpers.h" #include "core/memory.h" namespace Kernel { @@ -281,8 +281,8 @@ Result KServerSession::SendReply(bool is_hle) { return result; } -Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context, - std::weak_ptr<SessionRequestManager> manager) { +Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context, + std::weak_ptr<Service::SessionRequestManager> manager) { // Lock the session. KScopedLightLock lk{m_lock}; @@ -329,7 +329,8 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_co if (out_context != nullptr) { // HLE request. u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))}; - *out_context = std::make_shared<HLERequestContext>(kernel, memory, this, client_thread); + *out_context = + std::make_shared<Service::HLERequestContext>(kernel, memory, this, client_thread); (*out_context)->SetSessionRequestManager(manager); (*out_context) ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 6e189af8b..33f380352 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -10,18 +10,20 @@ #include <boost/intrusive/list.hpp> -#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_session_request.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/result.h" +namespace Service { +class HLERequestContext; +class SessionRequestManager; +} // namespace Service + namespace Kernel { -class HLERequestContext; class KernelCore; class KSession; -class SessionRequestManager; class KThread; class KServerSession final : public KSynchronizationObject, @@ -52,8 +54,8 @@ public: /// TODO: flesh these out to match the real kernel Result OnRequest(KSessionRequest* request); Result SendReply(bool is_hle = false); - Result ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context = nullptr, - std::weak_ptr<SessionRequestManager> manager = {}); + Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr, + std::weak_ptr<Service::SessionRequestManager> manager = {}); Result SendReplyHLE() { return SendReply(true); |