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/errors.h"
|
||||||
#include "core/hle/kernel/event.h"
|
#include "core/hle/kernel/event.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
|
#include "core/hle/kernel/ipc.h"
|
||||||
#include "core/hle/kernel/memory.h"
|
#include "core/hle/kernel/memory.h"
|
||||||
#include "core/hle/kernel/mutex.h"
|
#include "core/hle/kernel/mutex.h"
|
||||||
#include "core/hle/kernel/process.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.
|
/// 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,
|
static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count,
|
||||||
Kernel::Handle reply_target) {
|
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;
|
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.
|
// Note: The scheduler is not invoked here.
|
||||||
request_thread->ResumeFromWait();
|
request_thread->ResumeFromWait();
|
||||||
|
@ -524,14 +560,11 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
|
||||||
object->Acquire(thread);
|
object->Acquire(thread);
|
||||||
*index = static_cast<s32>(std::distance(objects.begin(), itr));
|
*index = static_cast<s32>(std::distance(objects.begin(), itr));
|
||||||
|
|
||||||
if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
|
if (object->GetHandleType() != Kernel::HandleType::ServerSession)
|
||||||
auto server_session = static_cast<Kernel::ServerSession*>(object);
|
return RESULT_SUCCESS;
|
||||||
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.
|
auto server_session = static_cast<Kernel::ServerSession*>(object);
|
||||||
}
|
return ReceiveIPCRequest(server_session, Kernel::GetCurrentThread());
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No objects were ready to be acquired, prepare to suspend the thread.
|
// 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(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
|
||||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||||
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
ResultCode result = RESULT_SUCCESS;
|
||||||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
|
||||||
|
|
||||||
// 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();
|
Core::System::GetInstance().PrepareReschedule();
|
||||||
|
|
Reference in New Issue