Kernel/SVC: Implement LLE command buffer translation in ReplyAndReceive.

The real kernel's ReplyAndReceive will retry the call until one of the objects can be acquired without causing a translation error, this is not currently implemented and the code will instead assert that the translation was a success.
This commit is contained in:
Subv 2017-10-01 22:12:42 -05:00
parent 8f108367c9
commit 5f92dc963c

View File

@ -18,6 +18,7 @@
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/ipc.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process.h"
@ -453,6 +454,33 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
}
}
static ResultCode ReceiveIPCRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session,
Kernel::SharedPtr<Kernel::Thread> thread) {
if (server_session->parent->client == nullptr) {
return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
}
VAddr target_address = thread->GetCommandBufferAddress();
VAddr source_address = server_session->currently_handling->GetCommandBufferAddress();
ResultCode translation_result = Kernel::TranslateCommandBuffer(
server_session->currently_handling, thread, source_address, target_address);
// If a translation error occurred, immediately resume the client thread.
if (translation_result.IsError()) {
// Set the output of SendSyncRequest in the client thread to the translation output.
server_session->currently_handling->SetWaitSynchronizationResult(translation_result);
server_session->currently_handling->ResumeFromWait();
server_session->currently_handling = nullptr;
// TODO(Subv): This path should try to wait again on the same objects.
ASSERT_MSG(false, "ReplyAndReceive translation error behavior unimplemented");
}
return translation_result;
}
/// In a single operation, sends a IPC reply and waits for a new request.
static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count,
Kernel::Handle reply_target) {
@ -495,7 +523,15 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
}
// TODO(Subv): Perform IPC translation from the current thread to request_thread.
VAddr source_address = Kernel::GetCurrentThread()->GetCommandBufferAddress();
VAddr target_address = request_thread->GetCommandBufferAddress();
ResultCode translation_result = Kernel::TranslateCommandBuffer(
Kernel::GetCurrentThread(), request_thread, source_address, target_address);
// Note: The real kernel seems to always panic if the Server->Client buffer translation
// fails for whatever reason.
ASSERT(translation_result.IsSuccess());
// Note: The scheduler is not invoked here.
request_thread->ResumeFromWait();
@ -524,14 +560,11 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
object->Acquire(thread);
*index = static_cast<s32>(std::distance(objects.begin(), itr));
if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
auto server_session = static_cast<Kernel::ServerSession*>(object);
if (server_session->parent->client == nullptr)
return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
// TODO(Subv): Perform IPC translation from the ServerSession to the current thread.
}
if (object->GetHandleType() != Kernel::HandleType::ServerSession)
return RESULT_SUCCESS;
auto server_session = static_cast<Kernel::ServerSession*>(object);
return ReceiveIPCRequest(server_session, Kernel::GetCurrentThread());
}
// No objects were ready to be acquired, prepare to suspend the thread.
@ -554,10 +587,15 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
ASSERT(reason == ThreadWakeupReason::Signal);
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
ResultCode result = RESULT_SUCCESS;
// TODO(Subv): Perform IPC translation upon wakeup.
if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
auto server_session = Kernel::DynamicObjectCast<Kernel::ServerSession>(object);
result = ReceiveIPCRequest(server_session, thread);
}
thread->SetWaitSynchronizationResult(result);
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
};
Core::System::GetInstance().PrepareReschedule();