2018-01-13 13:22:39 -08:00
|
|
|
// Copyright 2018 yuzu emulator team
|
2017-06-04 21:52:19 -07:00
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2017-06-08 23:52:30 -07:00
|
|
|
#include <array>
|
2019-11-24 17:15:51 -08:00
|
|
|
#include <functional>
|
2017-06-05 22:39:26 -07:00
|
|
|
#include <memory>
|
2019-03-07 13:44:28 -08:00
|
|
|
#include <optional>
|
2018-03-18 17:22:46 -07:00
|
|
|
#include <string>
|
2018-07-19 13:10:12 -07:00
|
|
|
#include <type_traits>
|
2017-06-04 21:52:19 -07:00
|
|
|
#include <vector>
|
2017-06-11 12:51:05 -07:00
|
|
|
#include <boost/container/small_vector.hpp>
|
2017-06-08 23:52:30 -07:00
|
|
|
#include "common/common_types.h"
|
2020-08-03 04:28:54 -07:00
|
|
|
#include "common/concepts.h"
|
2017-06-09 05:23:13 -07:00
|
|
|
#include "common/swap.h"
|
2017-06-08 23:52:30 -07:00
|
|
|
#include "core/hle/ipc.h"
|
2018-08-01 19:40:00 -07:00
|
|
|
#include "core/hle/kernel/object.h"
|
2017-06-04 21:52:19 -07:00
|
|
|
|
2019-03-05 06:20:11 -08:00
|
|
|
union ResultCode;
|
|
|
|
|
2020-05-03 09:41:30 -07:00
|
|
|
namespace Core::Memory {
|
|
|
|
class Memory;
|
|
|
|
}
|
|
|
|
|
2020-11-08 12:49:45 -08:00
|
|
|
namespace IPC {
|
|
|
|
class ResponseBuilder;
|
|
|
|
}
|
|
|
|
|
2017-06-06 21:20:52 -07:00
|
|
|
namespace Service {
|
|
|
|
class ServiceFrameworkBase;
|
|
|
|
}
|
2017-06-04 21:52:19 -07:00
|
|
|
|
2017-06-06 21:20:52 -07:00
|
|
|
namespace Kernel {
|
2017-06-04 21:52:19 -07:00
|
|
|
|
2017-12-28 21:36:22 -08:00
|
|
|
class Domain;
|
2017-06-09 05:23:13 -07:00
|
|
|
class HandleTable;
|
2017-12-28 21:36:22 -08:00
|
|
|
class HLERequestContext;
|
2020-05-03 09:41:30 -07:00
|
|
|
class KernelCore;
|
2017-06-09 05:23:13 -07:00
|
|
|
class Process;
|
2021-04-03 21:21:22 -07:00
|
|
|
class ClientSession;
|
2018-12-31 15:09:41 -08:00
|
|
|
class ServerSession;
|
2020-12-30 23:01:08 -08:00
|
|
|
class KThread;
|
2021-01-29 22:48:06 -08:00
|
|
|
class KReadableEvent;
|
2021-01-29 23:51:40 -08:00
|
|
|
class KWritableEvent;
|
2017-06-09 05:23:13 -07:00
|
|
|
|
2018-12-31 15:09:41 -08:00
|
|
|
enum class ThreadWakeupReason;
|
|
|
|
|
2017-06-04 21:52:19 -07: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-05 22:39:26 -07:00
|
|
|
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
2017-06-04 21:52:19 -07:00
|
|
|
public:
|
2018-12-31 15:09:41 -08:00
|
|
|
SessionRequestHandler();
|
|
|
|
virtual ~SessionRequestHandler();
|
2017-06-06 14:51:42 -07:00
|
|
|
|
2017-06-04 21:52:19 -07: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-28 21:36:22 -08:00
|
|
|
virtual ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) = 0;
|
2017-06-04 21:52:19 -07: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.
|
|
|
|
*/
|
2021-04-03 21:21:22 -07:00
|
|
|
void ClientConnected(
|
|
|
|
std::shared_ptr<ClientSession> client_session, std::shared_ptr<ServerSession> server_session);
|
2017-06-04 21:52:19 -07: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 17:15:51 -08:00
|
|
|
void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session);
|
2017-06-04 21:52:19 -07: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 16:02:47 -07:00
|
|
|
/// for the duration of the connection.
|
2021-04-03 21:21:22 -07:00
|
|
|
std::vector<std::shared_ptr<ClientSession>> client_sessions;
|
|
|
|
std::vector<std::shared_ptr<ServerSession>> server_sessions;
|
2017-06-04 21:52:19 -07:00
|
|
|
};
|
|
|
|
|
2017-06-06 21:20:52 -07: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 05:23:13 -07: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-06 21:20:52 -07:00
|
|
|
*/
|
|
|
|
class HLERequestContext {
|
|
|
|
public:
|
2020-05-03 09:41:30 -07:00
|
|
|
explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
2021-04-02 18:02:10 -07:00
|
|
|
std::shared_ptr<ServerSession> session, KThread* thread);
|
2017-06-06 21:20:52 -07:00
|
|
|
~HLERequestContext();
|
|
|
|
|
|
|
|
/// Returns a pointer to the IPC command buffer for this request.
|
2017-06-08 23:52:30 -07:00
|
|
|
u32* CommandBuffer() {
|
|
|
|
return cmd_buf.data();
|
2017-06-06 21:20:52 -07: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 17:15:51 -08:00
|
|
|
const std::shared_ptr<Kernel::ServerSession>& Session() const {
|
2017-12-28 21:36:22 -08:00
|
|
|
return server_session;
|
2017-06-06 21:20:52 -07:00
|
|
|
}
|
|
|
|
|
2017-06-18 16:05:12 -07:00
|
|
|
/// Populates this context with data from the requesting process/thread.
|
2018-10-20 11:34:41 -07:00
|
|
|
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
|
|
|
u32_le* src_cmdbuf);
|
|
|
|
|
2017-06-18 16:05:12 -07:00
|
|
|
/// Writes data from this context back to the requesting process/thread.
|
2020-12-30 23:01:08 -08:00
|
|
|
ResultCode WriteToOutgoingCommandBuffer(KThread& thread);
|
2017-10-14 19:18:42 -07: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 05:23:13 -07:00
|
|
|
|
2017-10-18 18:38:01 -07:00
|
|
|
const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const {
|
|
|
|
return buffer_x_desciptors;
|
|
|
|
}
|
|
|
|
|
2018-01-06 18:14:14 -08:00
|
|
|
const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const {
|
|
|
|
return buffer_a_desciptors;
|
|
|
|
}
|
|
|
|
|
2018-01-07 18:25:01 -08:00
|
|
|
const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const {
|
|
|
|
return buffer_b_desciptors;
|
|
|
|
}
|
|
|
|
|
2018-01-18 11:54:34 -08:00
|
|
|
const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
|
|
|
|
return buffer_c_desciptors;
|
|
|
|
}
|
|
|
|
|
2019-03-07 13:44:28 -08:00
|
|
|
const IPC::DomainMessageHeader& GetDomainMessageHeader() const {
|
|
|
|
return domain_message_header.value();
|
2017-12-28 21:36:22 -08:00
|
|
|
}
|
|
|
|
|
2018-10-29 20:20:17 -07:00
|
|
|
bool HasDomainMessageHeader() const {
|
2019-03-07 13:44:28 -08:00
|
|
|
return domain_message_header.has_value();
|
2018-10-29 20:20:17 -07:00
|
|
|
}
|
|
|
|
|
2018-02-13 18:41:20 -08:00
|
|
|
/// Helper function to read a buffer using the appropriate buffer descriptor
|
2020-04-16 19:02:08 -07:00
|
|
|
std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const;
|
2018-02-13 18:41:20 -08:00
|
|
|
|
|
|
|
/// Helper function to write a buffer using the appropriate buffer descriptor
|
2020-04-16 19:02:08 -07:00
|
|
|
std::size_t WriteBuffer(const void* buffer, std::size_t size,
|
|
|
|
std::size_t buffer_index = 0) const;
|
2018-02-13 18:41:20 -08:00
|
|
|
|
2018-07-19 13:10:12 -07:00
|
|
|
/* Helper function to write a buffer using the appropriate buffer descriptor
|
|
|
|
*
|
2020-08-03 04:28:54 -07:00
|
|
|
* @tparam T an arbitrary container that satisfies the
|
|
|
|
* ContiguousContainer concept in the C++ standard library or a trivially copyable type.
|
2018-07-19 13:10:12 -07:00
|
|
|
*
|
2020-08-03 04:28:54 -07:00
|
|
|
* @param data The container/data to write into a buffer.
|
2018-07-19 13:10:12 -07:00
|
|
|
* @param buffer_index The buffer in particular to write to.
|
|
|
|
*/
|
2020-08-03 04:28:54 -07: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 13:10:12 -07:00
|
|
|
}
|
2018-02-13 18:41:20 -08:00
|
|
|
|
2018-02-13 21:14:17 -08:00
|
|
|
/// Helper function to get the size of the input buffer
|
2020-04-16 19:02:08 -07:00
|
|
|
std::size_t GetReadBufferSize(std::size_t buffer_index = 0) const;
|
2018-02-13 21:14:17 -08:00
|
|
|
|
2018-02-13 18:41:20 -08:00
|
|
|
/// Helper function to get the size of the output buffer
|
2020-04-16 19:02:08 -07:00
|
|
|
std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const;
|
2018-02-13 18:41:20 -08:00
|
|
|
|
2021-01-27 22:18:06 -08: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;
|
|
|
|
|
2021-03-12 07:13:31 -08:00
|
|
|
Handle GetCopyHandle(std::size_t index) const {
|
|
|
|
return copy_handles.at(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
Handle GetMoveHandle(std::size_t index) const {
|
|
|
|
return move_handles.at(index);
|
|
|
|
}
|
|
|
|
|
2018-01-16 10:05:21 -08:00
|
|
|
template <typename T>
|
2021-04-03 21:21:22 -07:00
|
|
|
T* GetCopyObject(std::size_t index) {
|
2019-03-05 06:20:11 -08:00
|
|
|
return DynamicObjectCast<T>(copy_objects.at(index));
|
2018-01-07 06:22:20 -08:00
|
|
|
}
|
|
|
|
|
2018-01-16 10:05:21 -08:00
|
|
|
template <typename T>
|
2021-04-03 21:21:22 -07:00
|
|
|
T* GetMoveObject(std::size_t index) {
|
2019-03-05 06:20:11 -08:00
|
|
|
return DynamicObjectCast<T>(move_objects.at(index));
|
2018-01-07 06:22:20 -08:00
|
|
|
}
|
|
|
|
|
2021-04-03 21:21:22 -07:00
|
|
|
void AddMoveObject(Object* object) {
|
|
|
|
move_objects.emplace_back(object);
|
2018-01-06 22:50:55 -08:00
|
|
|
}
|
|
|
|
|
2021-04-03 21:21:22 -07:00
|
|
|
void AddCopyObject(Object* object) {
|
|
|
|
copy_objects.emplace_back(object);
|
2018-01-06 22:50:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) {
|
|
|
|
domain_objects.emplace_back(std::move(object));
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:24:31 -07:00
|
|
|
template <typename T>
|
2018-09-15 06:21:06 -07:00
|
|
|
std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const {
|
2019-03-05 06:20:11 -08:00
|
|
|
return std::static_pointer_cast<T>(domain_request_handlers.at(index));
|
2018-04-30 20:24:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetDomainRequestHandlers(
|
|
|
|
const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) {
|
|
|
|
domain_request_handlers = handlers;
|
|
|
|
}
|
|
|
|
|
2018-01-15 12:31:10 -08: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 06:21:06 -07:00
|
|
|
std::size_t NumMoveObjects() const {
|
2018-01-23 15:58:25 -08:00
|
|
|
return move_objects.size();
|
|
|
|
}
|
|
|
|
|
2018-09-15 06:21:06 -07:00
|
|
|
std::size_t NumCopyObjects() const {
|
2018-01-23 15:58:25 -08:00
|
|
|
return copy_objects.size();
|
|
|
|
}
|
|
|
|
|
2018-09-15 06:21:06 -07:00
|
|
|
std::size_t NumDomainObjects() const {
|
2018-01-23 15:58:25 -08:00
|
|
|
return domain_objects.size();
|
|
|
|
}
|
|
|
|
|
2018-02-15 06:22:11 -08:00
|
|
|
std::string Description() const;
|
|
|
|
|
2020-12-30 23:01:08 -08:00
|
|
|
KThread& GetThread() {
|
2019-11-25 15:28:48 -08:00
|
|
|
return *thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsThreadWaiting() const {
|
|
|
|
return is_thread_waiting;
|
|
|
|
}
|
|
|
|
|
2017-06-18 16:05:12 -07:00
|
|
|
private:
|
2020-11-08 12:49:45 -08:00
|
|
|
friend class IPC::ResponseBuilder;
|
|
|
|
|
2018-10-20 11:34:41 -07:00
|
|
|
void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
|
|
|
|
|
2017-06-08 23:52:30 -07:00
|
|
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
2019-11-24 17:15:51 -08:00
|
|
|
std::shared_ptr<Kernel::ServerSession> server_session;
|
2021-04-02 18:02:10 -07:00
|
|
|
KThread* thread;
|
|
|
|
|
2017-06-11 12:51:05 -07:00
|
|
|
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
2021-03-12 07:13:31 -08:00
|
|
|
boost::container::small_vector<Handle, 8> move_handles;
|
|
|
|
boost::container::small_vector<Handle, 8> copy_handles;
|
2021-04-03 19:11:46 -07:00
|
|
|
boost::container::small_vector<Object*, 8> move_objects;
|
|
|
|
boost::container::small_vector<Object*, 8> copy_objects;
|
2018-01-06 22:50:55 -08:00
|
|
|
boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
|
2017-10-14 19:18:42 -07:00
|
|
|
|
2019-03-07 13:44:28 -08: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 18:38:01 -07: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 11:54:34 -08:00
|
|
|
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
|
2017-10-14 19:18:42 -07:00
|
|
|
|
|
|
|
unsigned data_payload_offset{};
|
2018-01-18 11:54:34 -08:00
|
|
|
unsigned buffer_c_offset{};
|
2017-10-14 19:18:42 -07:00
|
|
|
u32_le command{};
|
2018-04-30 20:24:31 -07:00
|
|
|
|
|
|
|
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
|
2019-11-25 15:28:48 -08:00
|
|
|
bool is_thread_waiting{};
|
2020-05-03 09:41:30 -07:00
|
|
|
|
|
|
|
KernelCore& kernel;
|
|
|
|
Core::Memory::Memory& memory;
|
2017-06-06 21:20:52 -07:00
|
|
|
};
|
|
|
|
|
2017-06-04 21:52:19 -07:00
|
|
|
} // namespace Kernel
|