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:
parent
8f108367c9
commit
5f92dc963c
|
@ -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();
|
||||
|
|
Reference in New Issue