mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-23 10:52:13 +00:00
kern/ipc: implement SendReply, declare SendMessage
This commit is contained in:
parent
4db9d95958
commit
b29dc76b20
1 changed files with 144 additions and 3 deletions
|
@ -265,7 +265,6 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ALWAYS_INLINE void CleanupSpecialData(KProcess &dst_process, u32 *dst_msg_ptr, size_t dst_buffer_size) {
|
ALWAYS_INLINE void CleanupSpecialData(KProcess &dst_process, u32 *dst_msg_ptr, size_t dst_buffer_size) {
|
||||||
/* Parse the message. */
|
/* Parse the message. */
|
||||||
const ipc::MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
|
const ipc::MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
|
||||||
|
@ -298,6 +297,52 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Result CleanupServerHandles(uintptr_t message, size_t buffer_size, KPhysicalAddress message_paddr) {
|
||||||
|
/* Server is assumed to be current thread. */
|
||||||
|
const KThread &thread = GetCurrentThread();
|
||||||
|
|
||||||
|
/* Get the linear message pointer. */
|
||||||
|
u32 *msg_ptr;
|
||||||
|
if (message) {
|
||||||
|
msg_ptr = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(message_paddr));
|
||||||
|
} else {
|
||||||
|
msg_ptr = static_cast<ams::svc::ThreadLocalRegion *>(thread.GetThreadLocalRegionHeapAddress())->message_buffer;
|
||||||
|
buffer_size = sizeof(ams::svc::ThreadLocalRegion{}.message_buffer);
|
||||||
|
message = GetInteger(thread.GetThreadLocalRegionAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the message. */
|
||||||
|
const ipc::MessageBuffer msg(msg_ptr, buffer_size);
|
||||||
|
const ipc::MessageBuffer::MessageHeader header(msg);
|
||||||
|
const ipc::MessageBuffer::SpecialHeader special_header(msg, header);
|
||||||
|
|
||||||
|
/* Check that the size is big enough. */
|
||||||
|
R_UNLESS(ipc::MessageBuffer::GetMessageBufferSize(header, special_header) <= buffer_size, svc::ResultInvalidCombination());
|
||||||
|
|
||||||
|
/* If there's a special header, there may be move handles we need to close. */
|
||||||
|
if (header.GetHasSpecialHeader()) {
|
||||||
|
/* Determine the offset to the start of handles. */
|
||||||
|
auto offset = msg.GetSpecialDataIndex(header, special_header);
|
||||||
|
if (special_header.GetHasProcessId()) {
|
||||||
|
offset += sizeof(u64) / sizeof(u32);
|
||||||
|
}
|
||||||
|
if (auto copy_count = special_header.GetCopyHandleCount(); copy_count > 0) {
|
||||||
|
offset += (sizeof(ams::svc::Handle) * copy_count) / sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the handle table. */
|
||||||
|
auto &handle_table = thread.GetOwnerProcess()->GetHandleTable();
|
||||||
|
|
||||||
|
/* Close the handles. */
|
||||||
|
for (auto i = 0; i < special_header.GetMoveHandleCount(); ++i) {
|
||||||
|
handle_table.Remove(msg.GetHandle(offset));
|
||||||
|
offset += sizeof(ams::svc::Handle) / sizeof(u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Result CleanupServerMap(KSessionRequest *request, KProcess *server_process) {
|
ALWAYS_INLINE Result CleanupServerMap(KSessionRequest *request, KProcess *server_process) {
|
||||||
/* If there's no server process, there's nothing to clean up. */
|
/* If there's no server process, there's nothing to clean up. */
|
||||||
R_SUCCEED_IF(server_process == nullptr);
|
R_SUCCEED_IF(server_process == nullptr);
|
||||||
|
@ -586,6 +631,10 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Result SendMessage(uintptr_t src_message_buffer, size_t src_buffer_size, KPhysicalAddress src_message_paddr, KThread &dst_thread, uintptr_t dst_message_buffer, size_t dst_buffer_size, KServerSession *session, KSessionRequest *request) {
|
||||||
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void ReplyAsyncError(KProcess *to_process, uintptr_t to_msg_buf, size_t to_msg_buf_size, Result result) {
|
ALWAYS_INLINE void ReplyAsyncError(KProcess *to_process, uintptr_t to_msg_buf, size_t to_msg_buf_size, Result result) {
|
||||||
/* Convert the buffer to a physical address. */
|
/* Convert the buffer to a physical address. */
|
||||||
KPhysicalAddress phys_addr;
|
KPhysicalAddress phys_addr;
|
||||||
|
@ -710,8 +759,100 @@ namespace ams::kern {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KServerSession::SendReply(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr) {
|
Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buffer_size, KPhysicalAddress server_message_paddr) {
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
|
/* Lock the session. */
|
||||||
|
KScopedLightLock lk(this->lock);
|
||||||
|
|
||||||
|
/* Get the request. */
|
||||||
|
KSessionRequest *request;
|
||||||
|
{
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
|
/* Get the current request. */
|
||||||
|
request = this->current_request;
|
||||||
|
R_UNLESS(request != nullptr, svc::ResultInvalidState());
|
||||||
|
|
||||||
|
/* Clear the current request, since we're processing it. */
|
||||||
|
this->current_request = nullptr;
|
||||||
|
if (!this->request_list.empty()) {
|
||||||
|
this->NotifyAvailable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close reference to the request once we're done processing it. */
|
||||||
|
ON_SCOPE_EXIT { request->Close(); };
|
||||||
|
|
||||||
|
/* Extract relevant information from the request. */
|
||||||
|
const uintptr_t client_message = request->GetAddress();
|
||||||
|
const size_t client_buffer_size = request->GetSize();
|
||||||
|
KThread *client_thread = request->GetThread();
|
||||||
|
KWritableEvent *event = request->GetEvent();
|
||||||
|
|
||||||
|
/* Check whether we're closed. */
|
||||||
|
const bool closed = (client_thread == nullptr || this->parent->IsClientClosed());
|
||||||
|
|
||||||
|
Result result;
|
||||||
|
if (!closed) {
|
||||||
|
/* If we're not closed, send the reply. */
|
||||||
|
result = SendMessage(server_message, server_buffer_size, server_message_paddr, *client_thread, client_message, client_buffer_size, this, request);
|
||||||
|
} else {
|
||||||
|
/* Otherwise, we'll need to do some cleanup. */
|
||||||
|
KProcess *server_process = request->GetServerProcess();
|
||||||
|
KProcess *client_process = (client_thread != nullptr) ? client_thread->GetOwnerProcess() : nullptr;
|
||||||
|
KProcessPageTable *client_page_table = (client_process != nullptr) ? std::addressof(client_process->GetPageTable()) : nullptr;
|
||||||
|
|
||||||
|
/* Cleanup server handles. */
|
||||||
|
result = CleanupServerHandles(server_message, server_buffer_size, server_message_paddr);
|
||||||
|
|
||||||
|
/* Cleanup mappings. */
|
||||||
|
Result cleanup_map_result = CleanupMap(request, server_process, client_page_table);
|
||||||
|
|
||||||
|
/* If we successfully cleaned up handles, use the map cleanup result as our result. */
|
||||||
|
if (R_SUCCEEDED(result)) {
|
||||||
|
result = cleanup_map_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select a result for the client. */
|
||||||
|
Result client_result = result;
|
||||||
|
if (closed && R_SUCCEEDED(result)) {
|
||||||
|
result = svc::ResultSessionClosed();
|
||||||
|
client_result = svc::ResultSessionClosed();
|
||||||
|
} else {
|
||||||
|
result = ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there's a client thread, update it. */
|
||||||
|
if (client_thread != nullptr) {
|
||||||
|
if (event != nullptr) {
|
||||||
|
/* Get the client process/page table. */
|
||||||
|
KProcess *client_process = client_thread->GetOwnerProcess();
|
||||||
|
KProcessPageTable *client_page_table = std::addressof(client_process->GetPageTable());
|
||||||
|
|
||||||
|
/* If we need to, reply with an async error. */
|
||||||
|
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 {
|
||||||
|
/* Set the thread as runnable. */
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
if (client_thread->GetState() == KThread::ThreadState_Waiting) {
|
||||||
|
client_thread->SetSyncedObject(nullptr, client_result);
|
||||||
|
client_thread->SetState(KThread::ThreadState_Runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KServerSession::OnRequest(KSessionRequest *request) {
|
Result KServerSession::OnRequest(KSessionRequest *request) {
|
||||||
|
|
Loading…
Reference in a new issue