hle: Integrate Domain handling into ServerSession.
This commit is contained in:
parent
67758857e4
commit
27bad0598a
@ -76,7 +76,7 @@ public:
|
|||||||
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
|
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
|
||||||
// padding.
|
// padding.
|
||||||
u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
|
u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
|
||||||
if (context.IsDomain()) {
|
if (context.Session()->IsDomain()) {
|
||||||
raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
|
raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
|
||||||
} else {
|
} else {
|
||||||
// If we're not in a domain, turn the domain object parameters into move handles.
|
// If we're not in a domain, turn the domain object parameters into move handles.
|
||||||
@ -100,7 +100,7 @@ public:
|
|||||||
|
|
||||||
AlignWithPadding();
|
AlignWithPadding();
|
||||||
|
|
||||||
if (context.IsDomain()) {
|
if (context.Session()->IsDomain()) {
|
||||||
IPC::DomainMessageHeader domain_header{};
|
IPC::DomainMessageHeader domain_header{};
|
||||||
domain_header.num_objects = num_domain_objects;
|
domain_header.num_objects = num_domain_objects;
|
||||||
PushRaw(domain_header);
|
PushRaw(domain_header);
|
||||||
@ -114,7 +114,7 @@ public:
|
|||||||
template <class T, class... Args>
|
template <class T, class... Args>
|
||||||
void PushIpcInterface(Args&&... args) {
|
void PushIpcInterface(Args&&... args) {
|
||||||
auto iface = std::make_shared<T>(std::forward<Args>(args)...);
|
auto iface = std::make_shared<T>(std::forward<Args>(args)...);
|
||||||
if (context->IsDomain()) {
|
if (context->Session()->IsDomain()) {
|
||||||
context->AddDomainObject(std::move(iface));
|
context->AddDomainObject(std::move(iface));
|
||||||
} else {
|
} else {
|
||||||
auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName());
|
auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName());
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
@ -32,7 +33,7 @@ public:
|
|||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SendSyncRequest(SharedPtr<Thread> thread) override;
|
ResultCode SendSyncRequest(SharedPtr<Thread> thread);
|
||||||
|
|
||||||
std::string name; ///< Name of client port (optional)
|
std::string name; ///< Name of client port (optional)
|
||||||
|
|
||||||
|
@ -25,10 +25,6 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
|
|||||||
boost::range::remove_erase(connected_sessions, server_session);
|
boost::range::remove_erase(connected_sessions, server_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
HLERequestContext::HLERequestContext(SharedPtr<Kernel::Domain> domain) : domain(std::move(domain)) {
|
|
||||||
cmd_buf[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
|
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
|
||||||
: server_session(std::move(server_session)) {
|
: server_session(std::move(server_session)) {
|
||||||
cmd_buf[0] = 0;
|
cmd_buf[0] = 0;
|
||||||
@ -86,7 +82,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
|||||||
// Padding to align to 16 bytes
|
// Padding to align to 16 bytes
|
||||||
rp.AlignWithPadding();
|
rp.AlignWithPadding();
|
||||||
|
|
||||||
if (IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {
|
if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {
|
||||||
// If this is an incoming message, only CommandType "Request" has a domain header
|
// If this is an incoming message, only CommandType "Request" has a domain header
|
||||||
// All outgoing domain messages have the domain header
|
// All outgoing domain messages have the domain header
|
||||||
domain_message_header =
|
domain_message_header =
|
||||||
@ -199,12 +195,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P
|
|||||||
|
|
||||||
// TODO(Subv): Translate the X/A/B/W buffers.
|
// TODO(Subv): Translate the X/A/B/W buffers.
|
||||||
|
|
||||||
if (IsDomain()) {
|
if (Session()->IsDomain()) {
|
||||||
ASSERT(domain_message_header->num_objects == domain_objects.size());
|
ASSERT(domain_message_header->num_objects == domain_objects.size());
|
||||||
// Write the domain objects to the command buffer, these go after the raw untranslated data.
|
// Write the domain objects to the command buffer, these go after the raw untranslated data.
|
||||||
// TODO(Subv): This completely ignores C buffers.
|
// TODO(Subv): This completely ignores C buffers.
|
||||||
size_t domain_offset = size - domain_message_header->num_objects;
|
size_t domain_offset = size - domain_message_header->num_objects;
|
||||||
auto& request_handlers = domain->request_handlers;
|
auto& request_handlers = server_session->domain_request_handlers;
|
||||||
|
|
||||||
for (auto& object : domain_objects) {
|
for (auto& object : domain_objects) {
|
||||||
request_handlers.emplace_back(object);
|
request_handlers.emplace_back(object);
|
||||||
|
@ -86,7 +86,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
class HLERequestContext {
|
class HLERequestContext {
|
||||||
public:
|
public:
|
||||||
HLERequestContext(SharedPtr<Kernel::Domain> domain);
|
|
||||||
HLERequestContext(SharedPtr<Kernel::ServerSession> session);
|
HLERequestContext(SharedPtr<Kernel::ServerSession> session);
|
||||||
~HLERequestContext();
|
~HLERequestContext();
|
||||||
|
|
||||||
@ -95,18 +94,11 @@ public:
|
|||||||
return cmd_buf.data();
|
return cmd_buf.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the domain through which this request was made.
|
|
||||||
*/
|
|
||||||
const SharedPtr<Kernel::Domain>& Domain() const {
|
|
||||||
return domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the session through which this request was made. This can be used as a map key to
|
* Returns the session through which this request was made. This can be used as a map key to
|
||||||
* access per-client data on services.
|
* access per-client data on services.
|
||||||
*/
|
*/
|
||||||
const SharedPtr<Kernel::ServerSession>& ServerSession() const {
|
const SharedPtr<Kernel::ServerSession>& Session() const {
|
||||||
return server_session;
|
return server_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,10 +143,6 @@ public:
|
|||||||
return domain_message_header;
|
return domain_message_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDomain() const {
|
|
||||||
return domain != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SharedPtr<T> GetCopyObject(size_t index) {
|
SharedPtr<T> GetCopyObject(size_t index) {
|
||||||
ASSERT(index < copy_objects.size());
|
ASSERT(index < copy_objects.size());
|
||||||
@ -189,7 +177,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||||
SharedPtr<Kernel::Domain> domain;
|
|
||||||
SharedPtr<Kernel::ServerSession> server_session;
|
SharedPtr<Kernel::ServerSession> server_session;
|
||||||
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
||||||
boost::container::small_vector<SharedPtr<Object>, 8> move_objects;
|
boost::container::small_vector<SharedPtr<Object>, 8> move_objects;
|
||||||
@ -209,6 +196,7 @@ private:
|
|||||||
unsigned data_payload_offset{};
|
unsigned data_payload_offset{};
|
||||||
unsigned buffer_c_offset{};
|
unsigned buffer_c_offset{};
|
||||||
u32_le command{};
|
u32_le command{};
|
||||||
|
bool is_domain{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
@ -61,6 +62,38 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
|||||||
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
|
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
|
||||||
// similar.
|
// similar.
|
||||||
|
|
||||||
|
Kernel::HLERequestContext context(this);
|
||||||
|
u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
|
||||||
|
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
|
||||||
|
Kernel::g_handle_table);
|
||||||
|
|
||||||
|
// If the session has been converted to a domain, handle the doomain request
|
||||||
|
if (IsDomain()) {
|
||||||
|
auto& domain_message_header = context.GetDomainMessageHeader();
|
||||||
|
if (domain_message_header) {
|
||||||
|
// If there is a DomainMessageHeader, then this is CommandType "Request"
|
||||||
|
const u32 object_id{context.GetDomainMessageHeader()->object_id};
|
||||||
|
switch (domain_message_header->command) {
|
||||||
|
case IPC::DomainMessageHeader::CommandType::SendMessage:
|
||||||
|
return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
|
||||||
|
|
||||||
|
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
|
||||||
|
LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
|
||||||
|
|
||||||
|
domain_request_handlers[object_id - 1] = nullptr;
|
||||||
|
|
||||||
|
IPC::RequestBuilder rb{context, 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
return domain_request_handlers.front()->HandleSyncRequest(context);
|
||||||
|
}
|
||||||
|
|
||||||
// If this ServerSession has an associated HLE handler, forward the request to it.
|
// If this ServerSession has an associated HLE handler, forward the request to it.
|
||||||
ResultCode result{RESULT_SUCCESS};
|
ResultCode result{RESULT_SUCCESS};
|
||||||
if (hle_handler != nullptr) {
|
if (hle_handler != nullptr) {
|
||||||
@ -69,11 +102,6 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
|||||||
if (translate_result.IsError())
|
if (translate_result.IsError())
|
||||||
return translate_result;
|
return translate_result;
|
||||||
|
|
||||||
Kernel::HLERequestContext context(this);
|
|
||||||
u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
|
|
||||||
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
|
|
||||||
Kernel::g_handle_table);
|
|
||||||
|
|
||||||
result = hle_handler->HandleSyncRequest(context);
|
result = hle_handler->HandleSyncRequest(context);
|
||||||
} else {
|
} else {
|
||||||
// Add the thread to the list of threads that have issued a sync request with this
|
// Add the thread to the list of threads that have issued a sync request with this
|
||||||
@ -84,6 +112,15 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
|||||||
// If this ServerSession does not have an HLE implementation, just wake up the threads waiting
|
// If this ServerSession does not have an HLE implementation, just wake up the threads waiting
|
||||||
// on it.
|
// on it.
|
||||||
WakeupAllWaitingThreads();
|
WakeupAllWaitingThreads();
|
||||||
|
|
||||||
|
// Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the
|
||||||
|
// end of the command such that only commands following this one are handled as domains
|
||||||
|
if (convert_to_domain) {
|
||||||
|
ASSERT_MSG(domain_request_handlers.empty(), "already a domain");
|
||||||
|
domain_request_handlers.push_back(std::move(hle_handler));
|
||||||
|
convert_to_domain = false;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,10 @@ public:
|
|||||||
std::string name; ///< The name of this session (optional)
|
std::string name; ///< The name of this session (optional)
|
||||||
std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.
|
std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.
|
||||||
std::shared_ptr<SessionRequestHandler>
|
std::shared_ptr<SessionRequestHandler>
|
||||||
hle_handler; ///< This session's HLE request handler (optional)
|
hle_handler; ///< This session's HLE request handler (applicable when not a domain)
|
||||||
|
|
||||||
|
/// This is the list of domain request handlers (after conversion to a domain)
|
||||||
|
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
|
||||||
|
|
||||||
/// List of threads that are pending a response after a sync request. This list is processed in
|
/// List of threads that are pending a response after a sync request. This list is processed in
|
||||||
/// a LIFO manner, thus, the last request will be dispatched first.
|
/// a LIFO manner, thus, the last request will be dispatched first.
|
||||||
@ -91,6 +94,16 @@ public:
|
|||||||
/// TODO(Subv): Find a better name for this.
|
/// TODO(Subv): Find a better name for this.
|
||||||
SharedPtr<Thread> currently_handling;
|
SharedPtr<Thread> currently_handling;
|
||||||
|
|
||||||
|
/// Returns true if the session has been converted to a domain, otherwise False
|
||||||
|
bool IsDomain() const {
|
||||||
|
return !domain_request_handlers.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the session to a domain at the end of the current command
|
||||||
|
void ConvertToDomain() {
|
||||||
|
convert_to_domain = true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ServerSession();
|
ServerSession();
|
||||||
~ServerSession() override;
|
~ServerSession() override;
|
||||||
@ -102,6 +115,9 @@ private:
|
|||||||
* @return The created server session
|
* @return The created server session
|
||||||
*/
|
*/
|
||||||
static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
|
static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
|
||||||
|
|
||||||
|
/// When set to True, converts the session to a domain at the end of the command
|
||||||
|
bool convert_to_domain{};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,23 +10,21 @@ namespace Service {
|
|||||||
namespace SM {
|
namespace SM {
|
||||||
|
|
||||||
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
|
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
|
||||||
auto domain = Kernel::Domain::CreateFromSession(*ctx.ServerSession()->parent).Unwrap();
|
ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain");
|
||||||
|
ctx.Session()->ConvertToDomain();
|
||||||
|
|
||||||
IPC::RequestBuilder rb{ctx, 3};
|
IPC::RequestBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(static_cast<u32>(domain->request_handlers.size()));
|
rb.Push<u32>(1); // Converted sessions start with 1 request handler
|
||||||
|
|
||||||
LOG_DEBUG(Service, "called, domain=%d", domain->GetObjectId());
|
LOG_DEBUG(Service, "called, server_session=%d", ctx.Session()->GetObjectId());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
|
void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestBuilder rb{ctx, 2, 0, 1};
|
IPC::RequestBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
// TODO(Subv): Check if this is correct
|
// TODO(Subv): Check if this is correct
|
||||||
if (ctx.IsDomain())
|
rb.PushMoveObjects(ctx.Session());
|
||||||
rb.PushMoveObjects(ctx.Domain());
|
|
||||||
else
|
|
||||||
rb.PushMoveObjects(ctx.ServerSession());
|
|
||||||
|
|
||||||
LOG_DEBUG(Service, "called");
|
LOG_DEBUG(Service, "called");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user