forked from suyu/suyu
kernel: add KSessionRequest
This commit is contained in:
parent
5ffb8b8039
commit
3efb8eb2dc
13 changed files with 488 additions and 61 deletions
|
@ -243,6 +243,8 @@ add_library(core STATIC
|
||||||
hle/kernel/k_server_session.h
|
hle/kernel/k_server_session.h
|
||||||
hle/kernel/k_session.cpp
|
hle/kernel/k_session.cpp
|
||||||
hle/kernel/k_session.h
|
hle/kernel/k_session.h
|
||||||
|
hle/kernel/k_session_request.cpp
|
||||||
|
hle/kernel/k_session_request.h
|
||||||
hle/kernel/k_shared_memory.cpp
|
hle/kernel/k_shared_memory.cpp
|
||||||
hle/kernel/k_shared_memory.h
|
hle/kernel/k_shared_memory.h
|
||||||
hle/kernel/k_shared_memory_info.h
|
hle/kernel/k_shared_memory_info.h
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_resource_limit.h"
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
#include "core/hle/kernel/k_session.h"
|
#include "core/hle/kernel/k_session.h"
|
||||||
|
#include "core/hle/kernel/k_session_request.h"
|
||||||
#include "core/hle/kernel/k_shared_memory.h"
|
#include "core/hle/kernel/k_shared_memory.h"
|
||||||
#include "core/hle/kernel/k_shared_memory_info.h"
|
#include "core/hle/kernel/k_shared_memory_info.h"
|
||||||
#include "core/hle/kernel/k_system_control.h"
|
#include "core/hle/kernel/k_system_control.h"
|
||||||
|
@ -34,6 +35,7 @@ namespace Kernel::Init {
|
||||||
HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
|
HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
|
||||||
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
|
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
|
||||||
HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
|
HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
|
||||||
|
HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ##__VA_ARGS__) \
|
||||||
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
|
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
|
||||||
HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \
|
HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \
|
||||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/scope_exit.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/k_client_session.h"
|
#include "core/hle/kernel/k_client_session.h"
|
||||||
#include "core/hle/kernel/k_server_session.h"
|
#include "core/hle/kernel/k_server_session.h"
|
||||||
|
@ -10,6 +11,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
static constexpr u32 MessageBufferSize = 0x100;
|
||||||
|
|
||||||
KClientSession::KClientSession(KernelCore& kernel_)
|
KClientSession::KClientSession(KernelCore& kernel_)
|
||||||
: KAutoObjectWithSlabHeapAndContainer{kernel_} {}
|
: KAutoObjectWithSlabHeapAndContainer{kernel_} {}
|
||||||
KClientSession::~KClientSession() = default;
|
KClientSession::~KClientSession() = default;
|
||||||
|
@ -22,8 +25,16 @@ void KClientSession::Destroy() {
|
||||||
void KClientSession::OnServerClosed() {}
|
void KClientSession::OnServerClosed() {}
|
||||||
|
|
||||||
Result KClientSession::SendSyncRequest() {
|
Result KClientSession::SendSyncRequest() {
|
||||||
// Signal the server session that new data is available
|
// Create a session request.
|
||||||
return parent->GetServerSession().OnRequest();
|
KSessionRequest* request = KSessionRequest::Create(kernel);
|
||||||
|
R_UNLESS(request != nullptr, ResultOutOfResource);
|
||||||
|
SCOPE_EXIT({ request->Close(); });
|
||||||
|
|
||||||
|
// Initialize the request.
|
||||||
|
request->Initialize(nullptr, GetCurrentThread(kernel).GetTLSAddress(), MessageBufferSize);
|
||||||
|
|
||||||
|
// Send the request.
|
||||||
|
return parent->GetServerSession().OnRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -16,6 +16,7 @@ class KLinkedListNode : public boost::intrusive::list_base_hook<>,
|
||||||
public KSlabAllocated<KLinkedListNode> {
|
public KSlabAllocated<KLinkedListNode> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit KLinkedListNode(KernelCore&) {}
|
||||||
KLinkedListNode() = default;
|
KLinkedListNode() = default;
|
||||||
|
|
||||||
void Initialize(void* it) {
|
void Initialize(void* it) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Kernel {
|
||||||
|
|
||||||
class KPageBuffer final : public KSlabAllocated<KPageBuffer> {
|
class KPageBuffer final : public KSlabAllocated<KPageBuffer> {
|
||||||
public:
|
public:
|
||||||
|
explicit KPageBuffer(KernelCore&) {}
|
||||||
KPageBuffer() = default;
|
KPageBuffer() = default;
|
||||||
|
|
||||||
static KPageBuffer* FromPhysicalAddress(Core::System& system, PAddr phys_addr);
|
static KPageBuffer* FromPhysicalAddress(Core::System& system, PAddr phys_addr);
|
||||||
|
|
|
@ -29,8 +29,6 @@ namespace Kernel {
|
||||||
|
|
||||||
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
|
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
|
||||||
|
|
||||||
static constexpr u32 MessageBufferSize = 0x100;
|
|
||||||
|
|
||||||
KServerSession::KServerSession(KernelCore& kernel_)
|
KServerSession::KServerSession(KernelCore& kernel_)
|
||||||
: KSynchronizationObject{kernel_}, m_lock{kernel_} {}
|
: KSynchronizationObject{kernel_}, m_lock{kernel_} {}
|
||||||
|
|
||||||
|
@ -73,7 +71,7 @@ bool KServerSession::IsSignaled() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we're signaled if we have a request and aren't handling one.
|
// Otherwise, we're signaled if we have a request and aren't handling one.
|
||||||
return !m_thread_request_list.empty() && m_current_thread_request == nullptr;
|
return !m_request_list.empty() && m_current_request == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
|
void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
|
||||||
|
@ -178,7 +176,7 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KServerSession::OnRequest() {
|
Result KServerSession::OnRequest(KSessionRequest* request) {
|
||||||
// Create the wait queue.
|
// Create the wait queue.
|
||||||
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
|
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
|
||||||
|
|
||||||
|
@ -198,14 +196,13 @@ Result KServerSession::OnRequest() {
|
||||||
this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
|
this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
|
||||||
} else {
|
} else {
|
||||||
// Non-HLE request.
|
// Non-HLE request.
|
||||||
auto* thread{GetCurrentThreadPointer(kernel)};
|
|
||||||
|
|
||||||
// Get whether we're empty.
|
// Get whether we're empty.
|
||||||
const bool was_empty = m_thread_request_list.empty();
|
const bool was_empty = m_request_list.empty();
|
||||||
|
|
||||||
// Add the thread to the list.
|
// Add the request to the list.
|
||||||
thread->Open();
|
request->Open();
|
||||||
m_thread_request_list.push_back(thread);
|
m_request_list.push_back(*request);
|
||||||
|
|
||||||
// If we were empty, signal.
|
// If we were empty, signal.
|
||||||
if (was_empty) {
|
if (was_empty) {
|
||||||
|
@ -213,6 +210,9 @@ Result KServerSession::OnRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have a request event, this is asynchronous, and we don't need to wait.
|
||||||
|
R_SUCCEED_IF(request->GetEvent() != nullptr);
|
||||||
|
|
||||||
// This is a synchronous request, so we should wait for our request to complete.
|
// This is a synchronous request, so we should wait for our request to complete.
|
||||||
GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
|
GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
|
||||||
GetCurrentThread(kernel).BeginWait(&wait_queue);
|
GetCurrentThread(kernel).BeginWait(&wait_queue);
|
||||||
|
@ -223,32 +223,32 @@ Result KServerSession::OnRequest() {
|
||||||
|
|
||||||
Result KServerSession::SendReply() {
|
Result KServerSession::SendReply() {
|
||||||
// Lock the session.
|
// Lock the session.
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk{m_lock};
|
||||||
|
|
||||||
// Get the request.
|
// Get the request.
|
||||||
KThread* client_thread;
|
KSessionRequest* request;
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl{kernel};
|
KScopedSchedulerLock sl{kernel};
|
||||||
|
|
||||||
// Get the current request.
|
// Get the current request.
|
||||||
client_thread = m_current_thread_request;
|
request = m_current_request;
|
||||||
R_UNLESS(client_thread != nullptr, ResultInvalidState);
|
R_UNLESS(request != nullptr, ResultInvalidState);
|
||||||
|
|
||||||
// Clear the current request, since we're processing it.
|
// Clear the current request, since we're processing it.
|
||||||
m_current_thread_request = nullptr;
|
m_current_request = nullptr;
|
||||||
if (!m_thread_request_list.empty()) {
|
if (!m_request_list.empty()) {
|
||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close reference to the request once we're done processing it.
|
// Close reference to the request once we're done processing it.
|
||||||
SCOPE_EXIT({ client_thread->Close(); });
|
SCOPE_EXIT({ request->Close(); });
|
||||||
|
|
||||||
// Extract relevant information from the request.
|
// Extract relevant information from the request.
|
||||||
// const uintptr_t client_message = request->GetAddress();
|
const uintptr_t client_message = request->GetAddress();
|
||||||
// const size_t client_buffer_size = request->GetSize();
|
const size_t client_buffer_size = request->GetSize();
|
||||||
// KThread *client_thread = request->GetThread();
|
KThread* client_thread = request->GetThread();
|
||||||
// KEvent *event = request->GetEvent();
|
KEvent* event = request->GetEvent();
|
||||||
|
|
||||||
// Check whether we're closed.
|
// Check whether we're closed.
|
||||||
const bool closed = (client_thread == nullptr || parent->IsClientClosed());
|
const bool closed = (client_thread == nullptr || parent->IsClientClosed());
|
||||||
|
@ -261,8 +261,8 @@ Result KServerSession::SendReply() {
|
||||||
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
||||||
|
|
||||||
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
||||||
auto* dst_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress());
|
auto* dst_msg_buffer = memory.GetPointer(client_message);
|
||||||
std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize);
|
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
||||||
} else {
|
} else {
|
||||||
result = ResultSessionClosed;
|
result = ResultSessionClosed;
|
||||||
}
|
}
|
||||||
|
@ -278,11 +278,30 @@ Result KServerSession::SendReply() {
|
||||||
|
|
||||||
// If there's a client thread, update it.
|
// If there's a client thread, update it.
|
||||||
if (client_thread != nullptr) {
|
if (client_thread != nullptr) {
|
||||||
// End the client thread's wait.
|
if (event != nullptr) {
|
||||||
KScopedSchedulerLock sl{kernel};
|
// // Get the client process/page table.
|
||||||
|
// KProcess *client_process = client_thread->GetOwnerProcess();
|
||||||
|
// KPageTable *client_page_table = &client_process->PageTable();
|
||||||
|
|
||||||
if (!client_thread->IsTerminationRequested()) {
|
// // If we need to, reply with an async error.
|
||||||
client_thread->EndWait(client_result);
|
// if (R_FAILED(client_result)) {
|
||||||
|
// ReplyAsyncError(client_process, client_message, client_buffer_size,
|
||||||
|
// client_result);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Unlock the client buffer.
|
||||||
|
// // NOTE: Nintendo does not check the result of this.
|
||||||
|
// client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
|
||||||
|
|
||||||
|
// Signal the event.
|
||||||
|
event->Signal();
|
||||||
|
} else {
|
||||||
|
// End the client thread's wait.
|
||||||
|
KScopedSchedulerLock sl{kernel};
|
||||||
|
|
||||||
|
if (!client_thread->IsTerminationRequested()) {
|
||||||
|
client_thread->EndWait(client_result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,10 +310,10 @@ Result KServerSession::SendReply() {
|
||||||
|
|
||||||
Result KServerSession::ReceiveRequest() {
|
Result KServerSession::ReceiveRequest() {
|
||||||
// Lock the session.
|
// Lock the session.
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk{m_lock};
|
||||||
|
|
||||||
// Get the request and client thread.
|
// Get the request and client thread.
|
||||||
// KSessionRequest *request;
|
KSessionRequest* request;
|
||||||
KThread* client_thread;
|
KThread* client_thread;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -304,35 +323,41 @@ Result KServerSession::ReceiveRequest() {
|
||||||
R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
|
R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
|
||||||
|
|
||||||
// Ensure we aren't already servicing a request.
|
// Ensure we aren't already servicing a request.
|
||||||
R_UNLESS(m_current_thread_request == nullptr, ResultNotFound);
|
R_UNLESS(m_current_request == nullptr, ResultNotFound);
|
||||||
|
|
||||||
// Ensure we have a request to service.
|
// Ensure we have a request to service.
|
||||||
R_UNLESS(!m_thread_request_list.empty(), ResultNotFound);
|
R_UNLESS(!m_request_list.empty(), ResultNotFound);
|
||||||
|
|
||||||
// Pop the first request from the list.
|
// Pop the first request from the list.
|
||||||
client_thread = m_thread_request_list.front();
|
request = &m_request_list.front();
|
||||||
m_thread_request_list.pop_front();
|
m_request_list.pop_front();
|
||||||
|
|
||||||
// Get the thread for the request.
|
// Get the thread for the request.
|
||||||
|
client_thread = request->GetThread();
|
||||||
R_UNLESS(client_thread != nullptr, ResultSessionClosed);
|
R_UNLESS(client_thread != nullptr, ResultSessionClosed);
|
||||||
|
|
||||||
// Open the client thread.
|
// Open the client thread.
|
||||||
client_thread->Open();
|
client_thread->Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCOPE_EXIT({ client_thread->Close(); });
|
SCOPE_EXIT({ client_thread->Close(); });
|
||||||
|
|
||||||
// Set the request as our current.
|
// Set the request as our current.
|
||||||
m_current_thread_request = client_thread;
|
m_current_request = request;
|
||||||
|
|
||||||
|
// Get the client address.
|
||||||
|
uintptr_t client_message = request->GetAddress();
|
||||||
|
size_t client_buffer_size = request->GetSize();
|
||||||
|
// bool recv_list_broken = false;
|
||||||
|
|
||||||
// Receive the message.
|
// Receive the message.
|
||||||
Core::Memory::Memory& memory{kernel.System().Memory()};
|
Core::Memory::Memory& memory{kernel.System().Memory()};
|
||||||
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
||||||
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
||||||
|
|
||||||
auto* src_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress());
|
auto* src_msg_buffer = memory.GetPointer(client_message);
|
||||||
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
||||||
std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize);
|
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
||||||
|
|
||||||
// We succeeded.
|
// We succeeded.
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
|
@ -344,35 +369,34 @@ void KServerSession::CleanupRequests() {
|
||||||
// Clean up any pending requests.
|
// Clean up any pending requests.
|
||||||
while (true) {
|
while (true) {
|
||||||
// Get the next request.
|
// Get the next request.
|
||||||
// KSessionRequest *request = nullptr;
|
KSessionRequest* request = nullptr;
|
||||||
KThread* client_thread = nullptr;
|
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl{kernel};
|
KScopedSchedulerLock sl{kernel};
|
||||||
|
|
||||||
if (m_current_thread_request) {
|
if (m_current_request) {
|
||||||
// Choose the current request if we have one.
|
// Choose the current request if we have one.
|
||||||
client_thread = m_current_thread_request;
|
request = m_current_request;
|
||||||
m_current_thread_request = nullptr;
|
m_current_request = nullptr;
|
||||||
} else if (!m_thread_request_list.empty()) {
|
} else if (!m_request_list.empty()) {
|
||||||
// Pop the request from the front of the list.
|
// Pop the request from the front of the list.
|
||||||
client_thread = m_thread_request_list.front();
|
request = &m_request_list.front();
|
||||||
m_thread_request_list.pop_front();
|
m_request_list.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no request, we're done.
|
// If there's no request, we're done.
|
||||||
if (client_thread == nullptr) {
|
if (request == nullptr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close a reference to the request once it's cleaned up.
|
// Close a reference to the request once it's cleaned up.
|
||||||
SCOPE_EXIT({ client_thread->Close(); });
|
SCOPE_EXIT({ request->Close(); });
|
||||||
|
|
||||||
// Extract relevant information from the request.
|
// Extract relevant information from the request.
|
||||||
// const uintptr_t client_message = request->GetAddress();
|
// const uintptr_t client_message = request->GetAddress();
|
||||||
// const size_t client_buffer_size = request->GetSize();
|
// const size_t client_buffer_size = request->GetSize();
|
||||||
// KThread *client_thread = request->GetThread();
|
KThread* client_thread = request->GetThread();
|
||||||
// KEvent *event = request->GetEvent();
|
KEvent* event = request->GetEvent();
|
||||||
|
|
||||||
// KProcess *server_process = request->GetServerProcess();
|
// KProcess *server_process = request->GetServerProcess();
|
||||||
// KProcess *client_process = (client_thread != nullptr) ?
|
// KProcess *client_process = (client_thread != nullptr) ?
|
||||||
|
@ -385,11 +409,24 @@ void KServerSession::CleanupRequests() {
|
||||||
|
|
||||||
// If there's a client thread, update it.
|
// If there's a client thread, update it.
|
||||||
if (client_thread != nullptr) {
|
if (client_thread != nullptr) {
|
||||||
// End the client thread's wait.
|
if (event != nullptr) {
|
||||||
KScopedSchedulerLock sl{kernel};
|
// // We need to reply async.
|
||||||
|
// ReplyAsyncError(client_process, client_message, client_buffer_size,
|
||||||
|
// (R_SUCCEEDED(result) ? ResultSessionClosed : result));
|
||||||
|
|
||||||
if (!client_thread->IsTerminationRequested()) {
|
// // Unlock the client buffer.
|
||||||
client_thread->EndWait(ResultSessionClosed);
|
// NOTE: Nintendo does not check the result of this.
|
||||||
|
// client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
|
||||||
|
|
||||||
|
// Signal the event.
|
||||||
|
event->Signal();
|
||||||
|
} else {
|
||||||
|
// End the client thread's wait.
|
||||||
|
KScopedSchedulerLock sl{kernel};
|
||||||
|
|
||||||
|
if (!client_thread->IsTerminationRequested()) {
|
||||||
|
client_thread->EndWait(ResultSessionClosed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/k_light_lock.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/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: flesh these out to match the real kernel
|
/// TODO: flesh these out to match the real kernel
|
||||||
Result OnRequest();
|
Result OnRequest(KSessionRequest* request);
|
||||||
Result SendReply();
|
Result SendReply();
|
||||||
Result ReceiveRequest();
|
Result ReceiveRequest();
|
||||||
|
|
||||||
|
@ -122,9 +123,8 @@ private:
|
||||||
KSession* parent{};
|
KSession* parent{};
|
||||||
|
|
||||||
/// List of threads which are pending a reply.
|
/// List of threads which are pending a reply.
|
||||||
/// FIXME: KSessionRequest
|
boost::intrusive::list<KSessionRequest> m_request_list;
|
||||||
std::list<KThread*> m_thread_request_list;
|
KSessionRequest* m_current_request;
|
||||||
KThread* m_current_thread_request{};
|
|
||||||
|
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
};
|
};
|
||||||
|
|
61
src/core/hle/kernel/k_session_request.cpp
Normal file
61
src/core/hle/kernel/k_session_request.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/kernel/k_page_buffer.h"
|
||||||
|
#include "core/hle/kernel/k_session_request.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushMap(VAddr client, VAddr server, size_t size,
|
||||||
|
KMemoryState state, size_t index) {
|
||||||
|
// At most 15 buffers of each type (4-bit descriptor counts).
|
||||||
|
ASSERT(index < ((1ul << 4) - 1) * 3);
|
||||||
|
|
||||||
|
// Get the mapping.
|
||||||
|
Mapping* mapping;
|
||||||
|
if (index < NumStaticMappings) {
|
||||||
|
mapping = &m_static_mappings[index];
|
||||||
|
} else {
|
||||||
|
// Allocate a page for the extra mappings.
|
||||||
|
if (m_mappings == nullptr) {
|
||||||
|
KPageBuffer* page_buffer = KPageBuffer::Allocate(kernel);
|
||||||
|
R_UNLESS(page_buffer != nullptr, ResultOutOfMemory);
|
||||||
|
|
||||||
|
m_mappings = reinterpret_cast<Mapping*>(page_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping = &m_mappings[index - NumStaticMappings];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the mapping.
|
||||||
|
mapping->Set(client, server, size, state);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushSend(VAddr client, VAddr server, size_t size,
|
||||||
|
KMemoryState state) {
|
||||||
|
ASSERT(m_num_recv == 0);
|
||||||
|
ASSERT(m_num_exch == 0);
|
||||||
|
return this->PushMap(client, server, size, state, m_num_send++);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushReceive(VAddr client, VAddr server, size_t size,
|
||||||
|
KMemoryState state) {
|
||||||
|
ASSERT(m_num_exch == 0);
|
||||||
|
return this->PushMap(client, server, size, state, m_num_send + m_num_recv++);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushExchange(VAddr client, VAddr server, size_t size,
|
||||||
|
KMemoryState state) {
|
||||||
|
return this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KSessionRequest::SessionMappings::Finalize() {
|
||||||
|
if (m_mappings) {
|
||||||
|
KPageBuffer::Free(kernel, reinterpret_cast<KPageBuffer*>(m_mappings));
|
||||||
|
m_mappings = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
307
src/core/hle/kernel/k_session_request.h
Normal file
307
src/core/hle/kernel/k_session_request.h
Normal file
|
@ -0,0 +1,307 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
#include "core/hle/kernel/k_memory_block.h"
|
||||||
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
#include "core/hle/kernel/k_thread.h"
|
||||||
|
#include "core/hle/kernel/slab_helpers.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KSessionRequest final : public KSlabAllocated<KSessionRequest>,
|
||||||
|
public KAutoObject,
|
||||||
|
public boost::intrusive::list_base_hook<> {
|
||||||
|
KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject);
|
||||||
|
|
||||||
|
public:
|
||||||
|
class SessionMappings {
|
||||||
|
private:
|
||||||
|
static constexpr size_t NumStaticMappings = 8;
|
||||||
|
|
||||||
|
class Mapping {
|
||||||
|
public:
|
||||||
|
constexpr void Set(VAddr c, VAddr s, size_t sz, KMemoryState st) {
|
||||||
|
m_client_address = c;
|
||||||
|
m_server_address = s;
|
||||||
|
m_size = sz;
|
||||||
|
m_state = st;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr VAddr GetClientAddress() const {
|
||||||
|
return m_client_address;
|
||||||
|
}
|
||||||
|
constexpr VAddr GetServerAddress() const {
|
||||||
|
return m_server_address;
|
||||||
|
}
|
||||||
|
constexpr size_t GetSize() const {
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
constexpr KMemoryState GetMemoryState() const {
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VAddr m_client_address;
|
||||||
|
VAddr m_server_address;
|
||||||
|
size_t m_size;
|
||||||
|
KMemoryState m_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SessionMappings(KernelCore& kernel_)
|
||||||
|
: kernel(kernel_), m_mappings(nullptr), m_num_send(), m_num_recv(), m_num_exch() {}
|
||||||
|
|
||||||
|
void Initialize() {}
|
||||||
|
void Finalize();
|
||||||
|
|
||||||
|
size_t GetSendCount() const {
|
||||||
|
return m_num_send;
|
||||||
|
}
|
||||||
|
size_t GetReceiveCount() const {
|
||||||
|
return m_num_recv;
|
||||||
|
}
|
||||||
|
size_t GetExchangeCount() const {
|
||||||
|
return m_num_exch;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state);
|
||||||
|
Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state);
|
||||||
|
Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state);
|
||||||
|
|
||||||
|
VAddr GetSendClientAddress(size_t i) const {
|
||||||
|
return GetSendMapping(i).GetClientAddress();
|
||||||
|
}
|
||||||
|
VAddr GetSendServerAddress(size_t i) const {
|
||||||
|
return GetSendMapping(i).GetServerAddress();
|
||||||
|
}
|
||||||
|
size_t GetSendSize(size_t i) const {
|
||||||
|
return GetSendMapping(i).GetSize();
|
||||||
|
}
|
||||||
|
KMemoryState GetSendMemoryState(size_t i) const {
|
||||||
|
return GetSendMapping(i).GetMemoryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr GetReceiveClientAddress(size_t i) const {
|
||||||
|
return GetReceiveMapping(i).GetClientAddress();
|
||||||
|
}
|
||||||
|
VAddr GetReceiveServerAddress(size_t i) const {
|
||||||
|
return GetReceiveMapping(i).GetServerAddress();
|
||||||
|
}
|
||||||
|
size_t GetReceiveSize(size_t i) const {
|
||||||
|
return GetReceiveMapping(i).GetSize();
|
||||||
|
}
|
||||||
|
KMemoryState GetReceiveMemoryState(size_t i) const {
|
||||||
|
return GetReceiveMapping(i).GetMemoryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr GetExchangeClientAddress(size_t i) const {
|
||||||
|
return GetExchangeMapping(i).GetClientAddress();
|
||||||
|
}
|
||||||
|
VAddr GetExchangeServerAddress(size_t i) const {
|
||||||
|
return GetExchangeMapping(i).GetServerAddress();
|
||||||
|
}
|
||||||
|
size_t GetExchangeSize(size_t i) const {
|
||||||
|
return GetExchangeMapping(i).GetSize();
|
||||||
|
}
|
||||||
|
KMemoryState GetExchangeMemoryState(size_t i) const {
|
||||||
|
return GetExchangeMapping(i).GetMemoryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result PushMap(VAddr client, VAddr server, size_t size, KMemoryState state, size_t index);
|
||||||
|
|
||||||
|
const Mapping& GetSendMapping(size_t i) const {
|
||||||
|
ASSERT(i < m_num_send);
|
||||||
|
|
||||||
|
const size_t index = i;
|
||||||
|
if (index < NumStaticMappings) {
|
||||||
|
return m_static_mappings[index];
|
||||||
|
} else {
|
||||||
|
return m_mappings[index - NumStaticMappings];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Mapping& GetReceiveMapping(size_t i) const {
|
||||||
|
ASSERT(i < m_num_recv);
|
||||||
|
|
||||||
|
const size_t index = m_num_send + i;
|
||||||
|
if (index < NumStaticMappings) {
|
||||||
|
return m_static_mappings[index];
|
||||||
|
} else {
|
||||||
|
return m_mappings[index - NumStaticMappings];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Mapping& GetExchangeMapping(size_t i) const {
|
||||||
|
ASSERT(i < m_num_exch);
|
||||||
|
|
||||||
|
const size_t index = m_num_send + m_num_recv + i;
|
||||||
|
if (index < NumStaticMappings) {
|
||||||
|
return m_static_mappings[index];
|
||||||
|
} else {
|
||||||
|
return m_mappings[index - NumStaticMappings];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
KernelCore& kernel;
|
||||||
|
Mapping m_static_mappings[NumStaticMappings];
|
||||||
|
Mapping* m_mappings;
|
||||||
|
u8 m_num_send;
|
||||||
|
u8 m_num_recv;
|
||||||
|
u8 m_num_exch;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit KSessionRequest(KernelCore& kernel_)
|
||||||
|
: KAutoObject(kernel_), m_mappings(kernel_), m_thread(nullptr), m_server(nullptr),
|
||||||
|
m_event(nullptr) {}
|
||||||
|
|
||||||
|
static KSessionRequest* Create(KernelCore& kernel) {
|
||||||
|
KSessionRequest* req = KSessionRequest::Allocate(kernel);
|
||||||
|
if (req != nullptr) [[likely]] {
|
||||||
|
KAutoObject::Create(req);
|
||||||
|
}
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Destroy() override {
|
||||||
|
this->Finalize();
|
||||||
|
KSessionRequest::Free(kernel, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize(KEvent* event, uintptr_t address, size_t size) {
|
||||||
|
m_mappings.Initialize();
|
||||||
|
|
||||||
|
m_thread = GetCurrentThreadPointer(kernel);
|
||||||
|
m_event = event;
|
||||||
|
m_address = address;
|
||||||
|
m_size = size;
|
||||||
|
|
||||||
|
m_thread->Open();
|
||||||
|
if (m_event != nullptr) {
|
||||||
|
m_event->Open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PostDestroy(uintptr_t arg) {}
|
||||||
|
|
||||||
|
KThread* GetThread() const {
|
||||||
|
return m_thread;
|
||||||
|
}
|
||||||
|
KEvent* GetEvent() const {
|
||||||
|
return m_event;
|
||||||
|
}
|
||||||
|
uintptr_t GetAddress() const {
|
||||||
|
return m_address;
|
||||||
|
}
|
||||||
|
size_t GetSize() const {
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
KProcess* GetServerProcess() const {
|
||||||
|
return m_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetServerProcess(KProcess* process) {
|
||||||
|
m_server = process;
|
||||||
|
m_server->Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearThread() {
|
||||||
|
m_thread = nullptr;
|
||||||
|
}
|
||||||
|
void ClearEvent() {
|
||||||
|
m_event = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetSendCount() const {
|
||||||
|
return m_mappings.GetSendCount();
|
||||||
|
}
|
||||||
|
size_t GetReceiveCount() const {
|
||||||
|
return m_mappings.GetReceiveCount();
|
||||||
|
}
|
||||||
|
size_t GetExchangeCount() const {
|
||||||
|
return m_mappings.GetExchangeCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state) {
|
||||||
|
return m_mappings.PushSend(client, server, size, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state) {
|
||||||
|
return m_mappings.PushReceive(client, server, size, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state) {
|
||||||
|
return m_mappings.PushExchange(client, server, size, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr GetSendClientAddress(size_t i) const {
|
||||||
|
return m_mappings.GetSendClientAddress(i);
|
||||||
|
}
|
||||||
|
VAddr GetSendServerAddress(size_t i) const {
|
||||||
|
return m_mappings.GetSendServerAddress(i);
|
||||||
|
}
|
||||||
|
size_t GetSendSize(size_t i) const {
|
||||||
|
return m_mappings.GetSendSize(i);
|
||||||
|
}
|
||||||
|
KMemoryState GetSendMemoryState(size_t i) const {
|
||||||
|
return m_mappings.GetSendMemoryState(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr GetReceiveClientAddress(size_t i) const {
|
||||||
|
return m_mappings.GetReceiveClientAddress(i);
|
||||||
|
}
|
||||||
|
VAddr GetReceiveServerAddress(size_t i) const {
|
||||||
|
return m_mappings.GetReceiveServerAddress(i);
|
||||||
|
}
|
||||||
|
size_t GetReceiveSize(size_t i) const {
|
||||||
|
return m_mappings.GetReceiveSize(i);
|
||||||
|
}
|
||||||
|
KMemoryState GetReceiveMemoryState(size_t i) const {
|
||||||
|
return m_mappings.GetReceiveMemoryState(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr GetExchangeClientAddress(size_t i) const {
|
||||||
|
return m_mappings.GetExchangeClientAddress(i);
|
||||||
|
}
|
||||||
|
VAddr GetExchangeServerAddress(size_t i) const {
|
||||||
|
return m_mappings.GetExchangeServerAddress(i);
|
||||||
|
}
|
||||||
|
size_t GetExchangeSize(size_t i) const {
|
||||||
|
return m_mappings.GetExchangeSize(i);
|
||||||
|
}
|
||||||
|
KMemoryState GetExchangeMemoryState(size_t i) const {
|
||||||
|
return m_mappings.GetExchangeMemoryState(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// NOTE: This is public and virtual in Nintendo's kernel.
|
||||||
|
void Finalize() {
|
||||||
|
m_mappings.Finalize();
|
||||||
|
|
||||||
|
if (m_thread) {
|
||||||
|
m_thread->Close();
|
||||||
|
}
|
||||||
|
if (m_event) {
|
||||||
|
m_event->Close();
|
||||||
|
}
|
||||||
|
if (m_server) {
|
||||||
|
m_server->Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SessionMappings m_mappings;
|
||||||
|
KThread* m_thread;
|
||||||
|
KProcess* m_server;
|
||||||
|
KEvent* m_event;
|
||||||
|
uintptr_t m_address;
|
||||||
|
size_t m_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -15,7 +15,8 @@ class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>,
|
||||||
public boost::intrusive::list_base_hook<> {
|
public boost::intrusive::list_base_hook<> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit KSharedMemoryInfo() = default;
|
explicit KSharedMemoryInfo(KernelCore&) {}
|
||||||
|
KSharedMemoryInfo() = default;
|
||||||
|
|
||||||
constexpr void Initialize(KSharedMemory* shmem) {
|
constexpr void Initialize(KSharedMemory* shmem) {
|
||||||
shared_memory = shmem;
|
shared_memory = shmem;
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
static_assert(RegionsPerPage > 0);
|
static_assert(RegionsPerPage > 0);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr explicit KThreadLocalPage(VAddr addr = {}) : m_virt_addr(addr) {
|
constexpr explicit KThreadLocalPage(KernelCore&, VAddr addr = {}) : m_virt_addr(addr) {
|
||||||
m_is_region_free.fill(true);
|
m_is_region_free.fill(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ class KResourceLimit;
|
||||||
class KScheduler;
|
class KScheduler;
|
||||||
class KServerSession;
|
class KServerSession;
|
||||||
class KSession;
|
class KSession;
|
||||||
|
class KSessionRequest;
|
||||||
class KSharedMemory;
|
class KSharedMemory;
|
||||||
class KSharedMemoryInfo;
|
class KSharedMemoryInfo;
|
||||||
class KThread;
|
class KThread;
|
||||||
|
@ -360,6 +361,8 @@ public:
|
||||||
return slab_heap_container->page_buffer;
|
return slab_heap_container->page_buffer;
|
||||||
} else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
|
} else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
|
||||||
return slab_heap_container->thread_local_page;
|
return slab_heap_container->thread_local_page;
|
||||||
|
} else if constexpr (std::is_same_v<T, KSessionRequest>) {
|
||||||
|
return slab_heap_container->session_request;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +425,7 @@ private:
|
||||||
KSlabHeap<KCodeMemory> code_memory;
|
KSlabHeap<KCodeMemory> code_memory;
|
||||||
KSlabHeap<KPageBuffer> page_buffer;
|
KSlabHeap<KPageBuffer> page_buffer;
|
||||||
KSlabHeap<KThreadLocalPage> thread_local_page;
|
KSlabHeap<KThreadLocalPage> thread_local_page;
|
||||||
|
KSlabHeap<KSessionRequest> session_request;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<SlabHeapContainer> slab_heap_container;
|
std::unique_ptr<SlabHeapContainer> slab_heap_container;
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static Derived* Allocate(KernelCore& kernel) {
|
static Derived* Allocate(KernelCore& kernel) {
|
||||||
return kernel.SlabHeap<Derived>().Allocate();
|
return kernel.SlabHeap<Derived>().Allocate(kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Free(KernelCore& kernel, Derived* obj) {
|
static void Free(KernelCore& kernel, Derived* obj) {
|
||||||
|
|
Loading…
Reference in a new issue