2018-01-13 16:22:39 -05:00
|
|
|
// Copyright 2018 yuzu emulator team
|
2017-06-05 00:52:19 -04:00
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2017-06-09 02:52:30 -04:00
|
|
|
#include <array>
|
2019-11-24 20:15:51 -05:00
|
|
|
#include <functional>
|
2017-06-06 01:39:26 -04:00
|
|
|
#include <memory>
|
2019-03-07 16:44:28 -05:00
|
|
|
#include <optional>
|
2018-03-18 20:22:46 -04:00
|
|
|
#include <string>
|
2018-07-19 16:10:12 -04:00
|
|
|
#include <type_traits>
|
2017-06-05 00:52:19 -04:00
|
|
|
#include <vector>
|
2017-06-11 15:51:05 -04:00
|
|
|
#include <boost/container/small_vector.hpp>
|
2017-06-09 02:52:30 -04:00
|
|
|
#include "common/common_types.h"
|
2020-08-03 07:28:54 -04:00
|
|
|
#include "common/concepts.h"
|
2017-06-09 08:23:13 -04:00
|
|
|
#include "common/swap.h"
|
2017-06-09 02:52:30 -04:00
|
|
|
#include "core/hle/ipc.h"
|
2018-08-01 22:40:00 -04:00
|
|
|
#include "core/hle/kernel/object.h"
|
2017-06-05 00:52:19 -04:00
|
|
|
|
2019-03-05 09:20:11 -05:00
|
|
|
union ResultCode;
|
|
|
|
|
2020-05-03 12:41:30 -04:00
|
|
|
namespace Core::Memory {
|
|
|
|
class Memory;
|
|
|
|
}
|
|
|
|
|
2020-11-08 15:49:45 -05:00
|
|
|
namespace IPC {
|
|
|
|
class ResponseBuilder;
|
|
|
|
}
|
|
|
|
|
2017-06-07 00:20:52 -04:00
|
|
|
namespace Service {
|
|
|
|
class ServiceFrameworkBase;
|
|
|
|
}
|
2017-06-05 00:52:19 -04:00
|
|
|
|
2017-06-07 00:20:52 -04:00
|
|
|
namespace Kernel {
|
2017-06-05 00:52:19 -04:00
|
|
|
|
2017-12-29 00:36:22 -05:00
|
|
|
class Domain;
|
2017-06-09 08:23:13 -04:00
|
|
|
class HandleTable;
|
2017-12-29 00:36:22 -05:00
|
|
|
class HLERequestContext;
|
2020-05-03 12:41:30 -04:00
|
|
|
class KernelCore;
|
2017-06-09 08:23:13 -04:00
|
|
|
class Process;
|
2018-12-31 18:09:41 -05:00
|
|
|
class ServerSession;
|
2020-12-31 02:01:08 -05:00
|
|
|
class KThread;
|
2018-11-26 18:32:52 -05:00
|
|
|
class ReadableEvent;
|
|
|
|
class WritableEvent;
|
2017-06-09 08:23:13 -04:00
|
|
|
|
2018-12-31 18:09:41 -05:00
|
|
|
enum class ThreadWakeupReason;
|
|
|
|
|
2017-06-05 00:52:19 -04:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2017-06-06 01:39:26 -04:00
|
|
|
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
2017-06-05 00:52:19 -04:00
|
|
|
public:
|
2018-12-31 18:09:41 -05:00
|
|
|
SessionRequestHandler();
|
|
|
|
virtual ~SessionRequestHandler();
|
2017-06-06 17:51:42 -04:00
|
|
|
|
2017-06-05 00:52:19 -04:00
|
|
|
/**
|
|
|
|
* 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 ResultCode the result code of the translate operation.
|
|
|
|
*/
|
2017-12-29 00:36:22 -05:00
|
|
|
virtual ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) = 0;
|
2017-06-05 00:52:19 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Signals that a client has just connected to this HLE handler and keeps the
|
|
|
|
* associated ServerSession alive for the duration of the connection.
|
|
|
|
* @param server_session Owning pointer to the ServerSession associated with the connection.
|
|
|
|
*/
|
2019-11-24 20:15:51 -05:00
|
|
|
void ClientConnected(std::shared_ptr<ServerSession> server_session);
|
2017-06-05 00:52:19 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Signals that a client has just disconnected from this HLE handler and releases the
|
|
|
|
* associated ServerSession.
|
|
|
|
* @param server_session ServerSession associated with the connection.
|
|
|
|
*/
|
2019-11-24 20:15:51 -05:00
|
|
|
void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session);
|
2017-06-05 00:52:19 -04:00
|
|
|
|
|
|
|
protected:
|
|
|
|
/// List of sessions that are connected to this handler.
|
|
|
|
/// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
|
2018-07-18 19:02:47 -04:00
|
|
|
/// for the duration of the connection.
|
2019-11-24 20:15:51 -05:00
|
|
|
std::vector<std::shared_ptr<ServerSession>> connected_sessions;
|
2017-06-05 00:52:19 -04:00
|
|
|
};
|
|
|
|
|
2017-06-07 00:20:52 -04:00
|
|
|
/**
|
|
|
|
* 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.
|
2017-06-09 08:23:13 -04:00
|
|
|
*
|
|
|
|
* 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.
|
2017-06-07 00:20:52 -04:00
|
|
|
*/
|
|
|
|
class HLERequestContext {
|
|
|
|
public:
|
2020-05-03 12:41:30 -04:00
|
|
|
explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
|
|
|
std::shared_ptr<ServerSession> session,
|
2020-12-31 02:01:08 -05:00
|
|
|
std::shared_ptr<KThread> thread);
|
2017-06-07 00:20:52 -04:00
|
|
|
~HLERequestContext();
|
|
|
|
|
|
|
|
/// Returns a pointer to the IPC command buffer for this request.
|
2017-06-09 02:52:30 -04:00
|
|
|
u32* CommandBuffer() {
|
|
|
|
return cmd_buf.data();
|
2017-06-07 00:20:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the session through which this request was made. This can be used as a map key to
|
|
|
|
* access per-client data on services.
|
|
|
|
*/
|
2019-11-24 20:15:51 -05:00
|
|
|
const std::shared_ptr<Kernel::ServerSession>& Session() const {
|
2017-12-29 00:36:22 -05:00
|
|
|
return server_session;
|
2017-06-07 00:20:52 -04:00
|
|
|
}
|
|
|
|
|
2017-06-18 19:05:12 -04:00
|
|
|
/// Populates this context with data from the requesting process/thread.
|
2018-10-20 14:34:41 -04:00
|
|
|
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
|
|
|
u32_le* src_cmdbuf);
|
|
|
|
|
2017-06-18 19:05:12 -04:00
|
|
|
/// Writes data from this context back to the requesting process/thread.
|
2020-12-31 02:01:08 -05:00
|
|
|
ResultCode WriteToOutgoingCommandBuffer(KThread& thread);
|
2017-10-14 22:18:42 -04:00
|
|
|
|
|
|
|
u32_le GetCommand() const {
|
|
|
|
return command;
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC::CommandType GetCommandType() const {
|
|
|
|
return command_header->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned GetDataPayloadOffset() const {
|
|
|
|
return data_payload_offset;
|
|
|
|
}
|
2017-06-09 08:23:13 -04:00
|
|
|
|
2017-10-18 21:38:01 -04:00
|
|
|
const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const {
|
|
|
|
return buffer_x_desciptors;
|
|
|
|
}
|
|
|
|
|
2018-01-06 21:14:14 -05:00
|
|
|
const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const {
|
|
|
|
return buffer_a_desciptors;
|
|
|
|
}
|
|
|
|
|
2018-01-07 21:25:01 -05:00
|
|
|
const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const {
|
|
|
|
return buffer_b_desciptors;
|
|
|
|
}
|
|
|
|
|
2018-01-18 14:54:34 -05:00
|
|
|
const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
|
|
|
|
return buffer_c_desciptors;
|
|
|
|
}
|
|
|
|
|
2019-03-07 16:44:28 -05:00
|
|
|
const IPC::DomainMessageHeader& GetDomainMessageHeader() const {
|
|
|
|
return domain_message_header.value();
|
2017-12-29 00:36:22 -05:00
|
|
|
}
|
|
|
|
|
2018-10-29 23:20:17 -04:00
|
|
|
bool HasDomainMessageHeader() const {
|
2019-03-07 16:44:28 -05:00
|
|
|
return domain_message_header.has_value();
|
2018-10-29 23:20:17 -04:00
|
|
|
}
|
|
|
|
|
2018-02-13 21:41:20 -05:00
|
|
|
/// Helper function to read a buffer using the appropriate buffer descriptor
|
2020-04-16 22:02:08 -04:00
|
|
|
std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const;
|
2018-02-13 21:41:20 -05:00
|
|
|
|
|
|
|
/// Helper function to write a buffer using the appropriate buffer descriptor
|
2020-04-16 22:02:08 -04:00
|
|
|
std::size_t WriteBuffer(const void* buffer, std::size_t size,
|
|
|
|
std::size_t buffer_index = 0) const;
|
2018-02-13 21:41:20 -05:00
|
|
|
|
2018-07-19 16:10:12 -04:00
|
|
|
/* Helper function to write a buffer using the appropriate buffer descriptor
|
|
|
|
*
|
2020-08-03 07:28:54 -04:00
|
|
|
* @tparam T an arbitrary container that satisfies the
|
|
|
|
* ContiguousContainer concept in the C++ standard library or a trivially copyable type.
|
2018-07-19 16:10:12 -04:00
|
|
|
*
|
2020-08-03 07:28:54 -04:00
|
|
|
* @param data The container/data to write into a buffer.
|
2018-07-19 16:10:12 -04:00
|
|
|
* @param buffer_index The buffer in particular to write to.
|
|
|
|
*/
|
2020-08-03 07:28:54 -04:00
|
|
|
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::IsSTLContainer<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);
|
|
|
|
}
|
2018-07-19 16:10:12 -04:00
|
|
|
}
|
2018-02-13 21:41:20 -05:00
|
|
|
|
2018-02-14 00:14:17 -05:00
|
|
|
/// Helper function to get the size of the input buffer
|
2020-04-16 22:02:08 -04:00
|
|
|
std::size_t GetReadBufferSize(std::size_t buffer_index = 0) const;
|
2018-02-14 00:14:17 -05:00
|
|
|
|
2018-02-13 21:41:20 -05:00
|
|
|
/// Helper function to get the size of the output buffer
|
2020-04-16 22:02:08 -04:00
|
|
|
std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const;
|
2018-02-13 21:41:20 -05:00
|
|
|
|
2021-01-28 01:18:06 -05:00
|
|
|
/// Helper function to test whether the input buffer at buffer_index can be read
|
|
|
|
bool CanReadBuffer(std::size_t buffer_index = 0) const;
|
|
|
|
|
|
|
|
/// Helper function to test whether the output buffer at buffer_index can be written
|
|
|
|
bool CanWriteBuffer(std::size_t buffer_index = 0) const;
|
|
|
|
|
2018-01-16 13:05:21 -05:00
|
|
|
template <typename T>
|
2019-11-24 20:15:51 -05:00
|
|
|
std::shared_ptr<T> GetCopyObject(std::size_t index) {
|
2019-03-05 09:20:11 -05:00
|
|
|
return DynamicObjectCast<T>(copy_objects.at(index));
|
2018-01-07 09:22:20 -05:00
|
|
|
}
|
|
|
|
|
2018-01-16 13:05:21 -05:00
|
|
|
template <typename T>
|
2019-11-24 20:15:51 -05:00
|
|
|
std::shared_ptr<T> GetMoveObject(std::size_t index) {
|
2019-03-05 09:20:11 -05:00
|
|
|
return DynamicObjectCast<T>(move_objects.at(index));
|
2018-01-07 09:22:20 -05:00
|
|
|
}
|
|
|
|
|
2019-11-24 20:15:51 -05:00
|
|
|
void AddMoveObject(std::shared_ptr<Object> object) {
|
2018-01-07 01:50:55 -05:00
|
|
|
move_objects.emplace_back(std::move(object));
|
|
|
|
}
|
|
|
|
|
2019-11-24 20:15:51 -05:00
|
|
|
void AddCopyObject(std::shared_ptr<Object> object) {
|
2018-01-07 01:50:55 -05:00
|
|
|
copy_objects.emplace_back(std::move(object));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) {
|
|
|
|
domain_objects.emplace_back(std::move(object));
|
|
|
|
}
|
|
|
|
|
2018-04-30 23:24:31 -04:00
|
|
|
template <typename T>
|
2018-09-15 09:21:06 -04:00
|
|
|
std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const {
|
2019-03-05 09:20:11 -05:00
|
|
|
return std::static_pointer_cast<T>(domain_request_handlers.at(index));
|
2018-04-30 23:24:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetDomainRequestHandlers(
|
|
|
|
const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) {
|
|
|
|
domain_request_handlers = handlers;
|
|
|
|
}
|
|
|
|
|
2018-01-15 15:31:10 -05:00
|
|
|
/// Clears the list of objects so that no lingering objects are written accidentally to the
|
|
|
|
/// response buffer.
|
|
|
|
void ClearIncomingObjects() {
|
|
|
|
move_objects.clear();
|
|
|
|
copy_objects.clear();
|
|
|
|
domain_objects.clear();
|
|
|
|
}
|
|
|
|
|
2018-09-15 09:21:06 -04:00
|
|
|
std::size_t NumMoveObjects() const {
|
2018-01-23 18:58:25 -05:00
|
|
|
return move_objects.size();
|
|
|
|
}
|
|
|
|
|
2018-09-15 09:21:06 -04:00
|
|
|
std::size_t NumCopyObjects() const {
|
2018-01-23 18:58:25 -05:00
|
|
|
return copy_objects.size();
|
|
|
|
}
|
|
|
|
|
2018-09-15 09:21:06 -04:00
|
|
|
std::size_t NumDomainObjects() const {
|
2018-01-23 18:58:25 -05:00
|
|
|
return domain_objects.size();
|
|
|
|
}
|
|
|
|
|
2018-02-15 09:22:11 -05:00
|
|
|
std::string Description() const;
|
|
|
|
|
2020-12-31 02:01:08 -05:00
|
|
|
KThread& GetThread() {
|
2019-11-25 18:28:48 -05:00
|
|
|
return *thread;
|
|
|
|
}
|
|
|
|
|
2020-12-31 02:01:08 -05:00
|
|
|
const KThread& GetThread() const {
|
2019-11-25 18:28:48 -05:00
|
|
|
return *thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsThreadWaiting() const {
|
|
|
|
return is_thread_waiting;
|
|
|
|
}
|
|
|
|
|
2017-06-18 19:05:12 -04:00
|
|
|
private:
|
2020-11-08 15:49:45 -05:00
|
|
|
friend class IPC::ResponseBuilder;
|
|
|
|
|
2018-10-20 14:34:41 -04:00
|
|
|
void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
|
|
|
|
|
2017-06-09 02:52:30 -04:00
|
|
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
2019-11-24 20:15:51 -05:00
|
|
|
std::shared_ptr<Kernel::ServerSession> server_session;
|
2020-12-31 02:01:08 -05:00
|
|
|
std::shared_ptr<KThread> thread;
|
2017-06-11 15:51:05 -04:00
|
|
|
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
2019-11-24 20:15:51 -05:00
|
|
|
boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
|
|
|
|
boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
|
2018-01-07 01:50:55 -05:00
|
|
|
boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
|
2017-10-14 22:18:42 -04:00
|
|
|
|
2019-03-07 16:44:28 -05:00
|
|
|
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;
|
2017-10-18 21:38:01 -04:00
|
|
|
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;
|
2018-01-18 14:54:34 -05:00
|
|
|
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
|
2017-10-14 22:18:42 -04:00
|
|
|
|
|
|
|
unsigned data_payload_offset{};
|
2018-01-18 14:54:34 -05:00
|
|
|
unsigned buffer_c_offset{};
|
2017-10-14 22:18:42 -04:00
|
|
|
u32_le command{};
|
2018-04-30 23:24:31 -04:00
|
|
|
|
|
|
|
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
|
2019-11-25 18:28:48 -05:00
|
|
|
bool is_thread_waiting{};
|
2020-05-03 12:41:30 -04:00
|
|
|
|
|
|
|
KernelCore& kernel;
|
|
|
|
Core::Memory::Memory& memory;
|
2017-06-07 00:20:52 -04:00
|
|
|
};
|
|
|
|
|
2017-06-05 00:52:19 -04:00
|
|
|
} // namespace Kernel
|