diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/server_session.cpp | 97 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h | 14 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 1 |
4 files changed, 63 insertions, 50 deletions
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 54481f7f1..5608418c3 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -57,6 +57,33 @@ void ServerSession::Acquire(Thread* thread) { | |||
| 57 | pending_requesting_threads.pop_back(); | 57 | pending_requesting_threads.pop_back(); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { | ||
| 61 | auto& domain_message_header = context.GetDomainMessageHeader(); | ||
| 62 | if (domain_message_header) { | ||
| 63 | // If there is a DomainMessageHeader, then this is CommandType "Request" | ||
| 64 | const u32 object_id{context.GetDomainMessageHeader()->object_id}; | ||
| 65 | switch (domain_message_header->command) { | ||
| 66 | case IPC::DomainMessageHeader::CommandType::SendMessage: | ||
| 67 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); | ||
| 68 | |||
| 69 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | ||
| 70 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); | ||
| 71 | |||
| 72 | domain_request_handlers[object_id - 1] = nullptr; | ||
| 73 | |||
| 74 | IPC::ResponseBuilder rb{context, 2}; | ||
| 75 | rb.Push(RESULT_SUCCESS); | ||
| 76 | return RESULT_SUCCESS; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); | ||
| 81 | ASSERT(false); | ||
| 82 | } | ||
| 83 | |||
| 84 | return RESULT_SUCCESS; | ||
| 85 | } | ||
| 86 | |||
| 60 | ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { | 87 | ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { |
| 61 | // The ServerSession received a sync request, this means that there's new data available | 88 | // The ServerSession received a sync request, this means that there's new data available |
| 62 | // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or | 89 | // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or |
| @@ -67,46 +94,39 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { | |||
| 67 | context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, | 94 | context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, |
| 68 | Kernel::g_handle_table); | 95 | Kernel::g_handle_table); |
| 69 | 96 | ||
| 70 | // If the session has been converted to a domain, handle the doomain request | 97 | ResultCode result = RESULT_SUCCESS; |
| 98 | // If the session has been converted to a domain, handle the domain request | ||
| 71 | if (IsDomain()) { | 99 | if (IsDomain()) { |
| 72 | auto& domain_message_header = context.GetDomainMessageHeader(); | 100 | result = HandleDomainSyncRequest(context); |
| 73 | if (domain_message_header) { | ||
| 74 | // If there is a DomainMessageHeader, then this is CommandType "Request" | ||
| 75 | const u32 object_id{context.GetDomainMessageHeader()->object_id}; | ||
| 76 | switch (domain_message_header->command) { | ||
| 77 | case IPC::DomainMessageHeader::CommandType::SendMessage: | ||
| 78 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); | ||
| 79 | |||
| 80 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | ||
| 81 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); | ||
| 82 | |||
| 83 | domain_request_handlers[object_id - 1] = nullptr; | ||
| 84 | |||
| 85 | IPC::ResponseBuilder rb{context, 2}; | ||
| 86 | rb.Push(RESULT_SUCCESS); | ||
| 87 | return RESULT_SUCCESS; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); | ||
| 92 | ASSERT(false); | ||
| 93 | } | ||
| 94 | // If there is no domain header, the regular session handler is used | 101 | // If there is no domain header, the regular session handler is used |
| 102 | } else if (hle_handler != nullptr) { | ||
| 103 | // If this ServerSession has an associated HLE handler, forward the request to it. | ||
| 104 | result = hle_handler->HandleSyncRequest(context); | ||
| 95 | } | 105 | } |
| 96 | 106 | ||
| 97 | // If this ServerSession has an associated HLE handler, forward the request to it. | 107 | if (thread->status == THREADSTATUS_RUNNING) { |
| 98 | ResultCode result{RESULT_SUCCESS}; | 108 | // Put the thread to sleep until the server replies, it will be awoken in |
| 99 | if (hle_handler != nullptr) { | 109 | // svcReplyAndReceive for LLE servers. |
| 100 | // Attempt to translate the incoming request's command buffer. | 110 | thread->status = THREADSTATUS_WAIT_IPC; |
| 101 | ResultCode translate_result = TranslateHLERequest(this); | 111 | |
| 102 | if (translate_result.IsError()) | 112 | if (hle_handler != nullptr) { |
| 103 | return translate_result; | 113 | // For HLE services, we put the request threads to sleep for a short duration to |
| 104 | 114 | // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for | |
| 105 | result = hle_handler->HandleSyncRequest(context); | 115 | // other reasons like an async callback. The IPC overhead is needed to prevent |
| 106 | } else { | 116 | // starvation when a thread only does sync requests to HLE services while a |
| 107 | // Add the thread to the list of threads that have issued a sync request with this | 117 | // lower-priority thread is waiting to run. |
| 108 | // server. | 118 | |
| 109 | pending_requesting_threads.push_back(std::move(thread)); | 119 | // This delay was approximated in a homebrew application by measuring the average time |
| 120 | // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC | ||
| 121 | // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have | ||
| 122 | // a high variance and vary between models. | ||
| 123 | static constexpr u64 IPCDelayNanoseconds = 39000; | ||
| 124 | thread->WakeAfterDelay(IPCDelayNanoseconds); | ||
| 125 | } else { | ||
| 126 | // Add the thread to the list of threads that have issued a sync request with this | ||
| 127 | // server. | ||
| 128 | pending_requesting_threads.push_back(std::move(thread)); | ||
| 129 | } | ||
| 110 | } | 130 | } |
| 111 | 131 | ||
| 112 | // If this ServerSession does not have an HLE implementation, just wake up the threads waiting | 132 | // If this ServerSession does not have an HLE implementation, just wake up the threads waiting |
| @@ -140,9 +160,4 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& n | |||
| 140 | 160 | ||
| 141 | return std::make_tuple(std::move(server_session), std::move(client_session)); | 161 | return std::make_tuple(std::move(server_session), std::move(client_session)); |
| 142 | } | 162 | } |
| 143 | |||
| 144 | ResultCode TranslateHLERequest(ServerSession* server_session) { | ||
| 145 | // TODO(Subv): Implement this function once multiple concurrent processes are supported. | ||
| 146 | return RESULT_SUCCESS; | ||
| 147 | } | ||
| 148 | } // namespace Kernel | 163 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 144692106..2da807042 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -21,6 +21,7 @@ class ServerSession; | |||
| 21 | class Session; | 21 | class Session; |
| 22 | class SessionRequestHandler; | 22 | class SessionRequestHandler; |
| 23 | class Thread; | 23 | class Thread; |
| 24 | class HLERequestContext; | ||
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS | 27 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS |
| @@ -116,17 +117,12 @@ private: | |||
| 116 | */ | 117 | */ |
| 117 | static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); | 118 | static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); |
| 118 | 119 | ||
| 120 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an | ||
| 121 | /// object handle. | ||
| 122 | ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); | ||
| 123 | |||
| 119 | /// When set to True, converts the session to a domain at the end of the command | 124 | /// When set to True, converts the session to a domain at the end of the command |
| 120 | bool convert_to_domain{}; | 125 | bool convert_to_domain{}; |
| 121 | }; | 126 | }; |
| 122 | 127 | ||
| 123 | /** | ||
| 124 | * Performs command buffer translation for an HLE IPC request. | ||
| 125 | * The command buffer from the ServerSession thread's TLS is copied into a | ||
| 126 | * buffer and all descriptors in the buffer are processed. | ||
| 127 | * TODO(Subv): Implement this function, currently we do not support multiple processes running at | ||
| 128 | * once, but once that is implemented we'll need to properly translate all descriptors | ||
| 129 | * in the command buffer. | ||
| 130 | */ | ||
| 131 | ResultCode TranslateHLERequest(ServerSession* server_session); | ||
| 132 | } // namespace Kernel | 128 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1a33cc6cb..130b669a0 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -284,6 +284,7 @@ void Thread::ResumeFromWait() { | |||
| 284 | case THREADSTATUS_WAIT_SYNCH_ANY: | 284 | case THREADSTATUS_WAIT_SYNCH_ANY: |
| 285 | case THREADSTATUS_WAIT_ARB: | 285 | case THREADSTATUS_WAIT_ARB: |
| 286 | case THREADSTATUS_WAIT_SLEEP: | 286 | case THREADSTATUS_WAIT_SLEEP: |
| 287 | case THREADSTATUS_WAIT_IPC: | ||
| 287 | break; | 288 | break; |
| 288 | 289 | ||
| 289 | case THREADSTATUS_READY: | 290 | case THREADSTATUS_READY: |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0a1ada27d..bbffaf4cf 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -40,6 +40,7 @@ enum ThreadStatus { | |||
| 40 | THREADSTATUS_READY, ///< Ready to run | 40 | THREADSTATUS_READY, ///< Ready to run |
| 41 | THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter | 41 | THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter |
| 42 | THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC | 42 | THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC |
| 43 | THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request | ||
| 43 | THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false | 44 | THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false |
| 44 | THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true | 45 | THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true |
| 45 | THREADSTATUS_DORMANT, ///< Created but not yet made ready | 46 | THREADSTATUS_DORMANT, ///< Created but not yet made ready |