diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_session.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_session.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 243 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.h | 37 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 170 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc_wrap.h | 32 | ||||
| -rw-r--r-- | src/core/hle/service/ns/ns.cpp | 30 | ||||
| -rw-r--r-- | src/core/hle/service/ns/ns.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/ptm/ts.cpp | 15 | ||||
| -rw-r--r-- | src/core/hle/service/ptm/ts.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/set/set_sys.cpp | 79 | ||||
| -rw-r--r-- | src/core/hle/service/set/set_sys.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 3 |
15 files changed, 572 insertions, 55 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 1d46f6d40..22b5d5656 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -111,6 +111,7 @@ public: | |||
| 111 | LOG_ERROR(Core_ARM, | 111 | LOG_ERROR(Core_ARM, |
| 112 | "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, | 112 | "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, |
| 113 | num_instructions, memory.Read32(pc)); | 113 | num_instructions, memory.Read32(pc)); |
| 114 | ReturnException(pc, ARM_Interface::no_execute); | ||
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, | 117 | void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, |
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index d631c0357..0cc26a211 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -152,7 +152,8 @@ public: | |||
| 152 | Kernel::LimitableResource::Sessions, 1); | 152 | Kernel::LimitableResource::Sessions, 1); |
| 153 | 153 | ||
| 154 | auto* session = Kernel::KSession::Create(kernel); | 154 | auto* session = Kernel::KSession::Create(kernel); |
| 155 | session->Initialize(nullptr, iface->GetServiceName()); | 155 | session->Initialize(nullptr, iface->GetServiceName(), |
| 156 | std::make_shared<Kernel::SessionRequestManager>(kernel)); | ||
| 156 | 157 | ||
| 157 | context->AddMoveObject(&session->GetClientSession()); | 158 | context->AddMoveObject(&session->GetClientSession()); |
| 158 | iface->ClientConnected(&session->GetServerSession()); | 159 | iface->ClientConnected(&session->GetServerSession()); |
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp index b2a887b14..8892c5b7c 100644 --- a/src/core/hle/kernel/k_client_session.cpp +++ b/src/core/hle/kernel/k_client_session.cpp | |||
| @@ -21,10 +21,9 @@ void KClientSession::Destroy() { | |||
| 21 | 21 | ||
| 22 | void KClientSession::OnServerClosed() {} | 22 | void KClientSession::OnServerClosed() {} |
| 23 | 23 | ||
| 24 | Result KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, | 24 | Result KClientSession::SendSyncRequest() { |
| 25 | Core::Timing::CoreTiming& core_timing) { | ||
| 26 | // Signal the server session that new data is available | 25 | // Signal the server session that new data is available |
| 27 | return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing); | 26 | return parent->GetServerSession().OnRequest(); |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | } // namespace Kernel | 29 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h index 0c750d756..b4a19c546 100644 --- a/src/core/hle/kernel/k_client_session.h +++ b/src/core/hle/kernel/k_client_session.h | |||
| @@ -46,8 +46,7 @@ public: | |||
| 46 | return parent; | 46 | return parent; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | Result SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, | 49 | Result SendSyncRequest(); |
| 50 | Core::Timing::CoreTiming& core_timing); | ||
| 51 | 50 | ||
| 52 | void OnServerClosed(); | 51 | void OnServerClosed(); |
| 53 | 52 | ||
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 802c646a6..4252c9adb 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/scope_exit.h" | ||
| 11 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | 12 | #include "core/core_timing.h" |
| 11 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 12 | #include "core/hle/kernel/hle_ipc.h" | 14 | #include "core/hle/kernel/hle_ipc.h" |
| @@ -18,13 +20,19 @@ | |||
| 18 | #include "core/hle/kernel/k_server_session.h" | 20 | #include "core/hle/kernel/k_server_session.h" |
| 19 | #include "core/hle/kernel/k_session.h" | 21 | #include "core/hle/kernel/k_session.h" |
| 20 | #include "core/hle/kernel/k_thread.h" | 22 | #include "core/hle/kernel/k_thread.h" |
| 23 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 21 | #include "core/hle/kernel/kernel.h" | 24 | #include "core/hle/kernel/kernel.h" |
| 22 | #include "core/hle/kernel/service_thread.h" | 25 | #include "core/hle/kernel/service_thread.h" |
| 23 | #include "core/memory.h" | 26 | #include "core/memory.h" |
| 24 | 27 | ||
| 25 | namespace Kernel { | 28 | namespace Kernel { |
| 26 | 29 | ||
| 27 | KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} | 30 | using ThreadQueueImplForKServerSessionRequest = KThreadQueue; |
| 31 | |||
| 32 | static constexpr u32 MessageBufferSize = 0x100; | ||
| 33 | |||
| 34 | KServerSession::KServerSession(KernelCore& kernel_) | ||
| 35 | : KSynchronizationObject{kernel_}, m_lock{kernel_} {} | ||
| 28 | 36 | ||
| 29 | KServerSession::~KServerSession() = default; | 37 | KServerSession::~KServerSession() = default; |
| 30 | 38 | ||
| @@ -33,17 +41,14 @@ void KServerSession::Initialize(KSession* parent_session_, std::string&& name_, | |||
| 33 | // Set member variables. | 41 | // Set member variables. |
| 34 | parent = parent_session_; | 42 | parent = parent_session_; |
| 35 | name = std::move(name_); | 43 | name = std::move(name_); |
| 36 | 44 | manager = manager_; | |
| 37 | if (manager_) { | ||
| 38 | manager = manager_; | ||
| 39 | } else { | ||
| 40 | manager = std::make_shared<SessionRequestManager>(kernel); | ||
| 41 | } | ||
| 42 | } | 45 | } |
| 43 | 46 | ||
| 44 | void KServerSession::Destroy() { | 47 | void KServerSession::Destroy() { |
| 45 | parent->OnServerClosed(); | 48 | parent->OnServerClosed(); |
| 46 | 49 | ||
| 50 | this->CleanupRequests(); | ||
| 51 | |||
| 47 | parent->Close(); | 52 | parent->Close(); |
| 48 | 53 | ||
| 49 | // Release host emulation members. | 54 | // Release host emulation members. |
| @@ -54,13 +59,13 @@ void KServerSession::Destroy() { | |||
| 54 | } | 59 | } |
| 55 | 60 | ||
| 56 | void KServerSession::OnClientClosed() { | 61 | void KServerSession::OnClientClosed() { |
| 57 | if (manager->HasSessionHandler()) { | 62 | if (manager && manager->HasSessionHandler()) { |
| 58 | manager->SessionHandler().ClientDisconnected(this); | 63 | manager->SessionHandler().ClientDisconnected(this); |
| 59 | } | 64 | } |
| 60 | } | 65 | } |
| 61 | 66 | ||
| 62 | bool KServerSession::IsSignaled() const { | 67 | bool KServerSession::IsSignaled() const { |
| 63 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 68 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); |
| 64 | 69 | ||
| 65 | // If the client is closed, we're always signaled. | 70 | // If the client is closed, we're always signaled. |
| 66 | if (parent->IsClientClosed()) { | 71 | if (parent->IsClientClosed()) { |
| @@ -68,7 +73,7 @@ bool KServerSession::IsSignaled() const { | |||
| 68 | } | 73 | } |
| 69 | 74 | ||
| 70 | // Otherwise, we're signaled if we have a request and aren't handling one. | 75 | // Otherwise, we're signaled if we have a request and aren't handling one. |
| 71 | return false; | 76 | return !m_thread_request_list.empty() && m_current_thread_request == nullptr; |
| 72 | } | 77 | } |
| 73 | 78 | ||
| 74 | void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { | 79 | void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { |
| @@ -173,9 +178,221 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 173 | return result; | 178 | return result; |
| 174 | } | 179 | } |
| 175 | 180 | ||
| 176 | Result KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, | 181 | Result KServerSession::OnRequest() { |
| 177 | Core::Timing::CoreTiming& core_timing) { | 182 | // Create the wait queue. |
| 178 | return QueueSyncRequest(thread, memory); | 183 | ThreadQueueImplForKServerSessionRequest wait_queue{kernel}; |
| 184 | |||
| 185 | { | ||
| 186 | // Lock the scheduler. | ||
| 187 | KScopedSchedulerLock sl{kernel}; | ||
| 188 | |||
| 189 | // Ensure that we can handle new requests. | ||
| 190 | R_UNLESS(!parent->IsServerClosed(), ResultSessionClosed); | ||
| 191 | |||
| 192 | // Check that we're not terminating. | ||
| 193 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested); | ||
| 194 | |||
| 195 | if (manager) { | ||
| 196 | // HLE request. | ||
| 197 | auto& memory{kernel.System().Memory()}; | ||
| 198 | this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory); | ||
| 199 | } else { | ||
| 200 | // Non-HLE request. | ||
| 201 | auto* thread{GetCurrentThreadPointer(kernel)}; | ||
| 202 | |||
| 203 | // Get whether we're empty. | ||
| 204 | const bool was_empty = m_thread_request_list.empty(); | ||
| 205 | |||
| 206 | // Add the thread to the list. | ||
| 207 | thread->Open(); | ||
| 208 | m_thread_request_list.push_back(thread); | ||
| 209 | |||
| 210 | // If we were empty, signal. | ||
| 211 | if (was_empty) { | ||
| 212 | this->NotifyAvailable(); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | // This is a synchronous request, so we should wait for our request to complete. | ||
| 217 | GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | ||
| 218 | GetCurrentThread(kernel).BeginWait(&wait_queue); | ||
| 219 | } | ||
| 220 | |||
| 221 | return GetCurrentThread(kernel).GetWaitResult(); | ||
| 222 | } | ||
| 223 | |||
| 224 | Result KServerSession::SendReply() { | ||
| 225 | // Lock the session. | ||
| 226 | KScopedLightLock lk(m_lock); | ||
| 227 | |||
| 228 | // Get the request. | ||
| 229 | KThread* client_thread; | ||
| 230 | { | ||
| 231 | KScopedSchedulerLock sl{kernel}; | ||
| 232 | |||
| 233 | // Get the current request. | ||
| 234 | client_thread = m_current_thread_request; | ||
| 235 | R_UNLESS(client_thread != nullptr, ResultInvalidState); | ||
| 236 | |||
| 237 | // Clear the current request, since we're processing it. | ||
| 238 | m_current_thread_request = nullptr; | ||
| 239 | if (!m_thread_request_list.empty()) { | ||
| 240 | this->NotifyAvailable(); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | // Close reference to the request once we're done processing it. | ||
| 245 | SCOPE_EXIT({ client_thread->Close(); }); | ||
| 246 | |||
| 247 | // Extract relevant information from the request. | ||
| 248 | // const uintptr_t client_message = request->GetAddress(); | ||
| 249 | // const size_t client_buffer_size = request->GetSize(); | ||
| 250 | // KThread *client_thread = request->GetThread(); | ||
| 251 | // KEvent *event = request->GetEvent(); | ||
| 252 | |||
| 253 | // Check whether we're closed. | ||
| 254 | const bool closed = (client_thread == nullptr || parent->IsClientClosed()); | ||
| 255 | |||
| 256 | Result result = ResultSuccess; | ||
| 257 | if (!closed) { | ||
| 258 | // If we're not closed, send the reply. | ||
| 259 | Core::Memory::Memory& memory{kernel.System().Memory()}; | ||
| 260 | KThread* server_thread{GetCurrentThreadPointer(kernel)}; | ||
| 261 | UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | ||
| 262 | |||
| 263 | auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); | ||
| 264 | auto* dst_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); | ||
| 265 | std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); | ||
| 266 | } else { | ||
| 267 | result = ResultSessionClosed; | ||
| 268 | } | ||
| 269 | |||
| 270 | // Select a result for the client. | ||
| 271 | Result client_result = result; | ||
| 272 | if (closed && R_SUCCEEDED(result)) { | ||
| 273 | result = ResultSessionClosed; | ||
| 274 | client_result = ResultSessionClosed; | ||
| 275 | } else { | ||
| 276 | result = ResultSuccess; | ||
| 277 | } | ||
| 278 | |||
| 279 | // If there's a client thread, update it. | ||
| 280 | if (client_thread != nullptr) { | ||
| 281 | // End the client thread's wait. | ||
| 282 | KScopedSchedulerLock sl{kernel}; | ||
| 283 | |||
| 284 | if (!client_thread->IsTerminationRequested()) { | ||
| 285 | client_thread->EndWait(client_result); | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | return result; | ||
| 290 | } | ||
| 291 | |||
| 292 | Result KServerSession::ReceiveRequest() { | ||
| 293 | // Lock the session. | ||
| 294 | KScopedLightLock lk(m_lock); | ||
| 295 | |||
| 296 | // Get the request and client thread. | ||
| 297 | // KSessionRequest *request; | ||
| 298 | KThread* client_thread; | ||
| 299 | |||
| 300 | { | ||
| 301 | KScopedSchedulerLock sl{kernel}; | ||
| 302 | |||
| 303 | // Ensure that we can service the request. | ||
| 304 | R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed); | ||
| 305 | |||
| 306 | // Ensure we aren't already servicing a request. | ||
| 307 | R_UNLESS(m_current_thread_request == nullptr, ResultNotFound); | ||
| 308 | |||
| 309 | // Ensure we have a request to service. | ||
| 310 | R_UNLESS(!m_thread_request_list.empty(), ResultNotFound); | ||
| 311 | |||
| 312 | // Pop the first request from the list. | ||
| 313 | client_thread = m_thread_request_list.front(); | ||
| 314 | m_thread_request_list.pop_front(); | ||
| 315 | |||
| 316 | // Get the thread for the request. | ||
| 317 | R_UNLESS(client_thread != nullptr, ResultSessionClosed); | ||
| 318 | |||
| 319 | // Open the client thread. | ||
| 320 | client_thread->Open(); | ||
| 321 | } | ||
| 322 | |||
| 323 | // SCOPE_EXIT({ client_thread->Close(); }); | ||
| 324 | |||
| 325 | // Set the request as our current. | ||
| 326 | m_current_thread_request = client_thread; | ||
| 327 | |||
| 328 | // Receive the message. | ||
| 329 | Core::Memory::Memory& memory{kernel.System().Memory()}; | ||
| 330 | KThread* server_thread{GetCurrentThreadPointer(kernel)}; | ||
| 331 | UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | ||
| 332 | |||
| 333 | auto* src_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); | ||
| 334 | auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); | ||
| 335 | std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); | ||
| 336 | |||
| 337 | // We succeeded. | ||
| 338 | return ResultSuccess; | ||
| 339 | } | ||
| 340 | |||
| 341 | void KServerSession::CleanupRequests() { | ||
| 342 | KScopedLightLock lk(m_lock); | ||
| 343 | |||
| 344 | // Clean up any pending requests. | ||
| 345 | while (true) { | ||
| 346 | // Get the next request. | ||
| 347 | // KSessionRequest *request = nullptr; | ||
| 348 | KThread* client_thread = nullptr; | ||
| 349 | { | ||
| 350 | KScopedSchedulerLock sl{kernel}; | ||
| 351 | |||
| 352 | if (m_current_thread_request) { | ||
| 353 | // Choose the current request if we have one. | ||
| 354 | client_thread = m_current_thread_request; | ||
| 355 | m_current_thread_request = nullptr; | ||
| 356 | } else if (!m_thread_request_list.empty()) { | ||
| 357 | // Pop the request from the front of the list. | ||
| 358 | client_thread = m_thread_request_list.front(); | ||
| 359 | m_thread_request_list.pop_front(); | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | // If there's no request, we're done. | ||
| 364 | if (client_thread == nullptr) { | ||
| 365 | break; | ||
| 366 | } | ||
| 367 | |||
| 368 | // Close a reference to the request once it's cleaned up. | ||
| 369 | SCOPE_EXIT({ client_thread->Close(); }); | ||
| 370 | |||
| 371 | // Extract relevant information from the request. | ||
| 372 | // const uintptr_t client_message = request->GetAddress(); | ||
| 373 | // const size_t client_buffer_size = request->GetSize(); | ||
| 374 | // KThread *client_thread = request->GetThread(); | ||
| 375 | // KEvent *event = request->GetEvent(); | ||
| 376 | |||
| 377 | // KProcess *server_process = request->GetServerProcess(); | ||
| 378 | // KProcess *client_process = (client_thread != nullptr) ? | ||
| 379 | // client_thread->GetOwnerProcess() : nullptr; | ||
| 380 | // KProcessPageTable *client_page_table = (client_process != nullptr) ? | ||
| 381 | // &client_process->GetPageTable() : nullptr; | ||
| 382 | |||
| 383 | // Cleanup the mappings. | ||
| 384 | // Result result = CleanupMap(request, server_process, client_page_table); | ||
| 385 | |||
| 386 | // If there's a client thread, update it. | ||
| 387 | if (client_thread != nullptr) { | ||
| 388 | // End the client thread's wait. | ||
| 389 | KScopedSchedulerLock sl{kernel}; | ||
| 390 | |||
| 391 | if (!client_thread->IsTerminationRequested()) { | ||
| 392 | client_thread->EndWait(ResultSessionClosed); | ||
| 393 | } | ||
| 394 | } | ||
| 395 | } | ||
| 179 | } | 396 | } |
| 180 | 397 | ||
| 181 | } // namespace Kernel | 398 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 6d0821945..748d52826 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <list> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | #include <string> | 8 | #include <string> |
| 8 | #include <utility> | 9 | #include <utility> |
| @@ -10,6 +11,7 @@ | |||
| 10 | #include <boost/intrusive/list.hpp> | 11 | #include <boost/intrusive/list.hpp> |
| 11 | 12 | ||
| 12 | #include "core/hle/kernel/hle_ipc.h" | 13 | #include "core/hle/kernel/hle_ipc.h" |
| 14 | #include "core/hle/kernel/k_light_lock.h" | ||
| 13 | #include "core/hle/kernel/k_synchronization_object.h" | 15 | #include "core/hle/kernel/k_synchronization_object.h" |
| 14 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| 15 | 17 | ||
| @@ -59,25 +61,15 @@ public: | |||
| 59 | void OnClientClosed(); | 61 | void OnClientClosed(); |
| 60 | 62 | ||
| 61 | void ClientConnected(SessionRequestHandlerPtr handler) { | 63 | void ClientConnected(SessionRequestHandlerPtr handler) { |
| 62 | manager->SetSessionHandler(std::move(handler)); | 64 | if (manager) { |
| 65 | manager->SetSessionHandler(std::move(handler)); | ||
| 66 | } | ||
| 63 | } | 67 | } |
| 64 | 68 | ||
| 65 | void ClientDisconnected() { | 69 | void ClientDisconnected() { |
| 66 | manager = nullptr; | 70 | manager = nullptr; |
| 67 | } | 71 | } |
| 68 | 72 | ||
| 69 | /** | ||
| 70 | * Handle a sync request from the emulated application. | ||
| 71 | * | ||
| 72 | * @param thread Thread that initiated the request. | ||
| 73 | * @param memory Memory context to handle the sync request under. | ||
| 74 | * @param core_timing Core timing context to schedule the request event under. | ||
| 75 | * | ||
| 76 | * @returns Result from the operation. | ||
| 77 | */ | ||
| 78 | Result HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, | ||
| 79 | Core::Timing::CoreTiming& core_timing); | ||
| 80 | |||
| 81 | /// Adds a new domain request handler to the collection of request handlers within | 73 | /// Adds a new domain request handler to the collection of request handlers within |
| 82 | /// this ServerSession instance. | 74 | /// this ServerSession instance. |
| 83 | void AppendDomainHandler(SessionRequestHandlerPtr handler); | 75 | void AppendDomainHandler(SessionRequestHandlerPtr handler); |
| @@ -88,7 +80,7 @@ public: | |||
| 88 | 80 | ||
| 89 | /// Returns true if the session has been converted to a domain, otherwise False | 81 | /// Returns true if the session has been converted to a domain, otherwise False |
| 90 | bool IsDomain() const { | 82 | bool IsDomain() const { |
| 91 | return manager->IsDomain(); | 83 | return manager && manager->IsDomain(); |
| 92 | } | 84 | } |
| 93 | 85 | ||
| 94 | /// Converts the session to a domain at the end of the current command | 86 | /// Converts the session to a domain at the end of the current command |
| @@ -101,7 +93,15 @@ public: | |||
| 101 | return manager; | 93 | return manager; |
| 102 | } | 94 | } |
| 103 | 95 | ||
| 96 | /// TODO: flesh these out to match the real kernel | ||
| 97 | Result OnRequest(); | ||
| 98 | Result SendReply(); | ||
| 99 | Result ReceiveRequest(); | ||
| 100 | |||
| 104 | private: | 101 | private: |
| 102 | /// Frees up waiting client sessions when this server session is about to die | ||
| 103 | void CleanupRequests(); | ||
| 104 | |||
| 105 | /// Queues a sync request from the emulated application. | 105 | /// Queues a sync request from the emulated application. |
| 106 | Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); | 106 | Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); |
| 107 | 107 | ||
| @@ -112,7 +112,7 @@ private: | |||
| 112 | /// object handle. | 112 | /// object handle. |
| 113 | Result HandleDomainSyncRequest(Kernel::HLERequestContext& context); | 113 | Result HandleDomainSyncRequest(Kernel::HLERequestContext& context); |
| 114 | 114 | ||
| 115 | /// This session's HLE request handlers | 115 | /// This session's HLE request handlers; if nullptr, this is not an HLE server |
| 116 | std::shared_ptr<SessionRequestManager> manager; | 116 | std::shared_ptr<SessionRequestManager> manager; |
| 117 | 117 | ||
| 118 | /// When set to True, converts the session to a domain at the end of the command | 118 | /// When set to True, converts the session to a domain at the end of the command |
| @@ -120,6 +120,13 @@ private: | |||
| 120 | 120 | ||
| 121 | /// KSession that owns this KServerSession | 121 | /// KSession that owns this KServerSession |
| 122 | KSession* parent{}; | 122 | KSession* parent{}; |
| 123 | |||
| 124 | /// List of threads which are pending a reply. | ||
| 125 | /// FIXME: KSessionRequest | ||
| 126 | std::list<KThread*> m_thread_request_list; | ||
| 127 | KThread* m_current_thread_request{}; | ||
| 128 | |||
| 129 | KLightLock m_lock; | ||
| 123 | }; | 130 | }; |
| 124 | 131 | ||
| 125 | } // namespace Kernel | 132 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 27e5a805d..510a9b3e3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "core/hle/kernel/k_resource_limit.h" | 29 | #include "core/hle/kernel/k_resource_limit.h" |
| 30 | #include "core/hle/kernel/k_scheduler.h" | 30 | #include "core/hle/kernel/k_scheduler.h" |
| 31 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | 31 | #include "core/hle/kernel/k_scoped_resource_reservation.h" |
| 32 | #include "core/hle/kernel/k_session.h" | ||
| 32 | #include "core/hle/kernel/k_shared_memory.h" | 33 | #include "core/hle/kernel/k_shared_memory.h" |
| 33 | #include "core/hle/kernel/k_synchronization_object.h" | 34 | #include "core/hle/kernel/k_synchronization_object.h" |
| 34 | #include "core/hle/kernel/k_thread.h" | 35 | #include "core/hle/kernel/k_thread.h" |
| @@ -256,6 +257,93 @@ static Result UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u3 | |||
| 256 | return UnmapMemory(system, dst_addr, src_addr, size); | 257 | return UnmapMemory(system, dst_addr, src_addr, size); |
| 257 | } | 258 | } |
| 258 | 259 | ||
| 260 | template <typename T> | ||
| 261 | Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, u64 name) { | ||
| 262 | auto& process = *system.CurrentProcess(); | ||
| 263 | auto& handle_table = process.GetHandleTable(); | ||
| 264 | |||
| 265 | // Declare the session we're going to allocate. | ||
| 266 | T* session; | ||
| 267 | |||
| 268 | // Reserve a new session from the process resource limit. | ||
| 269 | // FIXME: LimitableResource_SessionCountMax | ||
| 270 | KScopedResourceReservation session_reservation(&process, LimitableResource::Sessions); | ||
| 271 | if (session_reservation.Succeeded()) { | ||
| 272 | session = T::Create(system.Kernel()); | ||
| 273 | } else { | ||
| 274 | return ResultLimitReached; | ||
| 275 | |||
| 276 | // // We couldn't reserve a session. Check that we support dynamically expanding the | ||
| 277 | // // resource limit. | ||
| 278 | // R_UNLESS(process.GetResourceLimit() == | ||
| 279 | // &system.Kernel().GetSystemResourceLimit(), ResultLimitReached); | ||
| 280 | // R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached()); | ||
| 281 | |||
| 282 | // // Try to allocate a session from unused slab memory. | ||
| 283 | // session = T::CreateFromUnusedSlabMemory(); | ||
| 284 | // R_UNLESS(session != nullptr, ResultLimitReached); | ||
| 285 | // ON_RESULT_FAILURE { session->Close(); }; | ||
| 286 | |||
| 287 | // // If we're creating a KSession, we want to add two KSessionRequests to the heap, to | ||
| 288 | // // prevent request exhaustion. | ||
| 289 | // // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's | ||
| 290 | // // no reason to not do this statically. | ||
| 291 | // if constexpr (std::same_as<T, KSession>) { | ||
| 292 | // for (size_t i = 0; i < 2; i++) { | ||
| 293 | // KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory(); | ||
| 294 | // R_UNLESS(request != nullptr, ResultLimitReached); | ||
| 295 | // request->Close(); | ||
| 296 | // } | ||
| 297 | // } | ||
| 298 | |||
| 299 | // We successfully allocated a session, so add the object we allocated to the resource | ||
| 300 | // limit. | ||
| 301 | // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::Sessions, 1); | ||
| 302 | } | ||
| 303 | |||
| 304 | // Check that we successfully created a session. | ||
| 305 | R_UNLESS(session != nullptr, ResultOutOfResource); | ||
| 306 | |||
| 307 | // Initialize the session. | ||
| 308 | session->Initialize(nullptr, fmt::format("{}", name)); | ||
| 309 | |||
| 310 | // Commit the session reservation. | ||
| 311 | session_reservation.Commit(); | ||
| 312 | |||
| 313 | // Ensure that we clean up the session (and its only references are handle table) on function | ||
| 314 | // end. | ||
| 315 | SCOPE_EXIT({ | ||
| 316 | session->GetClientSession().Close(); | ||
| 317 | session->GetServerSession().Close(); | ||
| 318 | }); | ||
| 319 | |||
| 320 | // Register the session. | ||
| 321 | T::Register(system.Kernel(), session); | ||
| 322 | |||
| 323 | // Add the server session to the handle table. | ||
| 324 | R_TRY(handle_table.Add(out_server, &session->GetServerSession())); | ||
| 325 | |||
| 326 | // Add the client session to the handle table. | ||
| 327 | const auto result = handle_table.Add(out_client, &session->GetClientSession()); | ||
| 328 | |||
| 329 | if (!R_SUCCEEDED(result)) { | ||
| 330 | // Ensure that we maintaing a clean handle state on exit. | ||
| 331 | handle_table.Remove(*out_server); | ||
| 332 | } | ||
| 333 | |||
| 334 | return result; | ||
| 335 | } | ||
| 336 | |||
| 337 | static Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, | ||
| 338 | u32 is_light, u64 name) { | ||
| 339 | if (is_light) { | ||
| 340 | // return CreateSession<KLightSession>(system, out_server, out_client, name); | ||
| 341 | return ResultUnknown; | ||
| 342 | } else { | ||
| 343 | return CreateSession<KSession>(system, out_server, out_client, name); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 259 | /// Connect to an OS service given the port name, returns the handle to the port to out | 347 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 260 | static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { | 348 | static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { |
| 261 | auto& memory = system.Memory(); | 349 | auto& memory = system.Memory(); |
| @@ -295,7 +383,8 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n | |||
| 295 | 383 | ||
| 296 | // Create a session. | 384 | // Create a session. |
| 297 | KClientSession* session{}; | 385 | KClientSession* session{}; |
| 298 | R_TRY(port->CreateSession(std::addressof(session))); | 386 | R_TRY(port->CreateSession(std::addressof(session), |
| 387 | std::make_shared<SessionRequestManager>(kernel))); | ||
| 299 | port->Close(); | 388 | port->Close(); |
| 300 | 389 | ||
| 301 | // Register the session in the table, close the extra reference. | 390 | // Register the session in the table, close the extra reference. |
| @@ -313,7 +402,7 @@ static Result ConnectToNamedPort32(Core::System& system, Handle* out_handle, | |||
| 313 | return ConnectToNamedPort(system, out_handle, port_name_address); | 402 | return ConnectToNamedPort(system, out_handle, port_name_address); |
| 314 | } | 403 | } |
| 315 | 404 | ||
| 316 | /// Makes a blocking IPC call to an OS service. | 405 | /// Makes a blocking IPC call to a service. |
| 317 | static Result SendSyncRequest(Core::System& system, Handle handle) { | 406 | static Result SendSyncRequest(Core::System& system, Handle handle) { |
| 318 | auto& kernel = system.Kernel(); | 407 | auto& kernel = system.Kernel(); |
| 319 | 408 | ||
| @@ -327,22 +416,75 @@ static Result SendSyncRequest(Core::System& system, Handle handle) { | |||
| 327 | 416 | ||
| 328 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | 417 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); |
| 329 | 418 | ||
| 330 | { | 419 | return session->SendSyncRequest(); |
| 331 | KScopedSchedulerLock lock(kernel); | ||
| 332 | |||
| 333 | // This is a synchronous request, so we should wait for our request to complete. | ||
| 334 | GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue)); | ||
| 335 | GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | ||
| 336 | session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming()); | ||
| 337 | } | ||
| 338 | |||
| 339 | return GetCurrentThread(kernel).GetWaitResult(); | ||
| 340 | } | 420 | } |
| 341 | 421 | ||
| 342 | static Result SendSyncRequest32(Core::System& system, Handle handle) { | 422 | static Result SendSyncRequest32(Core::System& system, Handle handle) { |
| 343 | return SendSyncRequest(system, handle); | 423 | return SendSyncRequest(system, handle); |
| 344 | } | 424 | } |
| 345 | 425 | ||
| 426 | static Result ReplyAndReceive(Core::System& system, s32* out_index, Handle* handles, | ||
| 427 | s32 num_handles, Handle reply_target, s64 timeout_ns) { | ||
| 428 | auto& kernel = system.Kernel(); | ||
| 429 | auto& handle_table = GetCurrentThread(kernel).GetOwnerProcess()->GetHandleTable(); | ||
| 430 | |||
| 431 | // Convert handle list to object table. | ||
| 432 | std::vector<KSynchronizationObject*> objs(num_handles); | ||
| 433 | R_UNLESS( | ||
| 434 | handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, num_handles), | ||
| 435 | ResultInvalidHandle); | ||
| 436 | |||
| 437 | // Ensure handles are closed when we're done. | ||
| 438 | SCOPE_EXIT({ | ||
| 439 | for (auto i = 0; i < num_handles; ++i) { | ||
| 440 | objs[i]->Close(); | ||
| 441 | } | ||
| 442 | }); | ||
| 443 | |||
| 444 | // Reply to the target, if one is specified. | ||
| 445 | if (reply_target != InvalidHandle) { | ||
| 446 | KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target); | ||
| 447 | R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||
| 448 | |||
| 449 | // If we fail to reply, we want to set the output index to -1. | ||
| 450 | // ON_RESULT_FAILURE { *out_index = -1; }; | ||
| 451 | |||
| 452 | // Send the reply. | ||
| 453 | // R_TRY(session->SendReply()); | ||
| 454 | |||
| 455 | Result rc = session->SendReply(); | ||
| 456 | if (!R_SUCCEEDED(rc)) { | ||
| 457 | *out_index = -1; | ||
| 458 | return rc; | ||
| 459 | } | ||
| 460 | } | ||
| 461 | |||
| 462 | // Wait for a message. | ||
| 463 | while (true) { | ||
| 464 | // Wait for an object. | ||
| 465 | s32 index; | ||
| 466 | Result result = KSynchronizationObject::Wait(kernel, &index, objs.data(), | ||
| 467 | static_cast<s32>(objs.size()), timeout_ns); | ||
| 468 | if (result == ResultTimedOut) { | ||
| 469 | return result; | ||
| 470 | } | ||
| 471 | |||
| 472 | // Receive the request. | ||
| 473 | if (R_SUCCEEDED(result)) { | ||
| 474 | KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); | ||
| 475 | if (session != nullptr) { | ||
| 476 | result = session->ReceiveRequest(); | ||
| 477 | if (result == ResultNotFound) { | ||
| 478 | continue; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | *out_index = index; | ||
| 484 | return result; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 346 | /// Get the ID for the specified thread. | 488 | /// Get the ID for the specified thread. |
| 347 | static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { | 489 | static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { |
| 348 | // Get the thread from its handle. | 490 | // Get the thread from its handle. |
| @@ -2860,10 +3002,10 @@ static const FunctionDef SVC_Table_64[] = { | |||
| 2860 | {0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"}, | 3002 | {0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"}, |
| 2861 | {0x3E, nullptr, "Unknown3e"}, | 3003 | {0x3E, nullptr, "Unknown3e"}, |
| 2862 | {0x3F, nullptr, "Unknown3f"}, | 3004 | {0x3F, nullptr, "Unknown3f"}, |
| 2863 | {0x40, nullptr, "CreateSession"}, | 3005 | {0x40, SvcWrap64<CreateSession>, "CreateSession"}, |
| 2864 | {0x41, nullptr, "AcceptSession"}, | 3006 | {0x41, nullptr, "AcceptSession"}, |
| 2865 | {0x42, nullptr, "ReplyAndReceiveLight"}, | 3007 | {0x42, nullptr, "ReplyAndReceiveLight"}, |
| 2866 | {0x43, nullptr, "ReplyAndReceive"}, | 3008 | {0x43, SvcWrap64<ReplyAndReceive>, "ReplyAndReceive"}, |
| 2867 | {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, | 3009 | {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, |
| 2868 | {0x45, SvcWrap64<CreateEvent>, "CreateEvent"}, | 3010 | {0x45, SvcWrap64<CreateEvent>, "CreateEvent"}, |
| 2869 | {0x46, nullptr, "MapIoRegion"}, | 3011 | {0x46, nullptr, "MapIoRegion"}, |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 4bc49087e..272c54cf7 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/svc_types.h" | 9 | #include "core/hle/kernel/svc_types.h" |
| 10 | #include "core/hle/result.h" | 10 | #include "core/hle/result.h" |
| 11 | #include "core/memory.h" | ||
| 11 | 12 | ||
| 12 | namespace Kernel { | 13 | namespace Kernel { |
| 13 | 14 | ||
| @@ -346,6 +347,37 @@ void SvcWrap64(Core::System& system) { | |||
| 346 | FuncReturn(system, retval); | 347 | FuncReturn(system, retval); |
| 347 | } | 348 | } |
| 348 | 349 | ||
| 350 | // Used by CreateSession | ||
| 351 | template <Result func(Core::System&, Handle*, Handle*, u32, u64)> | ||
| 352 | void SvcWrap64(Core::System& system) { | ||
| 353 | Handle param_1 = 0; | ||
| 354 | Handle param_2 = 0; | ||
| 355 | const u32 retval = func(system, ¶m_1, ¶m_2, static_cast<u32>(Param(system, 2)), | ||
| 356 | static_cast<u32>(Param(system, 3))) | ||
| 357 | .raw; | ||
| 358 | |||
| 359 | system.CurrentArmInterface().SetReg(1, param_1); | ||
| 360 | system.CurrentArmInterface().SetReg(2, param_2); | ||
| 361 | FuncReturn(system, retval); | ||
| 362 | } | ||
| 363 | |||
| 364 | // Used by ReplyAndReceive | ||
| 365 | template <Result func(Core::System&, s32*, Handle*, s32, Handle, s64)> | ||
| 366 | void SvcWrap64(Core::System& system) { | ||
| 367 | s32 param_1 = 0; | ||
| 368 | s32 num_handles = static_cast<s32>(Param(system, 2)); | ||
| 369 | |||
| 370 | std::vector<Handle> handles(num_handles); | ||
| 371 | system.Memory().ReadBlock(Param(system, 1), handles.data(), num_handles * sizeof(Handle)); | ||
| 372 | |||
| 373 | const u32 retval = func(system, ¶m_1, handles.data(), num_handles, | ||
| 374 | static_cast<s32>(Param(system, 3)), static_cast<s64>(Param(system, 4))) | ||
| 375 | .raw; | ||
| 376 | |||
| 377 | system.CurrentArmInterface().SetReg(1, param_1); | ||
| 378 | FuncReturn(system, retval); | ||
| 379 | } | ||
| 380 | |||
| 349 | // Used by WaitForAddress | 381 | // Used by WaitForAddress |
| 350 | template <Result func(Core::System&, u64, Svc::ArbitrationType, s32, s64)> | 382 | template <Result func(Core::System&, u64, Svc::ArbitrationType, s32, s64)> |
| 351 | void SvcWrap64(Core::System& system) { | 383 | void SvcWrap64(Core::System& system) { |
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index f7318c3cb..f59a1a63d 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "core/file_sys/patch_manager.h" | 8 | #include "core/file_sys/patch_manager.h" |
| 9 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| 10 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/service/glue/glue_manager.h" | ||
| 11 | #include "core/hle/service/ns/errors.h" | 12 | #include "core/hle/service/ns/errors.h" |
| 12 | #include "core/hle/service/ns/iplatform_service_manager.h" | 13 | #include "core/hle/service/ns/iplatform_service_manager.h" |
| 13 | #include "core/hle/service/ns/language.h" | 14 | #include "core/hle/service/ns/language.h" |
| @@ -581,7 +582,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa | |||
| 581 | : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { | 582 | : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { |
| 582 | // clang-format off | 583 | // clang-format off |
| 583 | static const FunctionInfo functions[] = { | 584 | static const FunctionInfo functions[] = { |
| 584 | {0, nullptr, "GetApplicationControlData"}, | 585 | {0, &IReadOnlyApplicationControlDataInterface::GetApplicationControlData, "GetApplicationControlData"}, |
| 585 | {1, nullptr, "GetApplicationDesiredLanguage"}, | 586 | {1, nullptr, "GetApplicationDesiredLanguage"}, |
| 586 | {2, nullptr, "ConvertApplicationLanguageToLanguageCode"}, | 587 | {2, nullptr, "ConvertApplicationLanguageToLanguageCode"}, |
| 587 | {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, | 588 | {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, |
| @@ -594,6 +595,33 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa | |||
| 594 | 595 | ||
| 595 | IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; | 596 | IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; |
| 596 | 597 | ||
| 598 | void IReadOnlyApplicationControlDataInterface::GetApplicationControlData( | ||
| 599 | Kernel::HLERequestContext& ctx) { | ||
| 600 | enum class ApplicationControlSource : u8 { | ||
| 601 | CacheOnly, | ||
| 602 | Storage, | ||
| 603 | StorageOnly, | ||
| 604 | }; | ||
| 605 | |||
| 606 | struct RequestParameters { | ||
| 607 | ApplicationControlSource source; | ||
| 608 | u64 application_id; | ||
| 609 | }; | ||
| 610 | static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size."); | ||
| 611 | |||
| 612 | IPC::RequestParser rp{ctx}; | ||
| 613 | const auto parameters{rp.PopRaw<RequestParameters>()}; | ||
| 614 | const auto nacp_data{system.GetARPManager().GetControlProperty(parameters.application_id)}; | ||
| 615 | const auto result = nacp_data ? ResultSuccess : ResultUnknown; | ||
| 616 | |||
| 617 | if (nacp_data) { | ||
| 618 | ctx.WriteBuffer(nacp_data->data(), nacp_data->size()); | ||
| 619 | } | ||
| 620 | |||
| 621 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 622 | rb.Push(result); | ||
| 623 | } | ||
| 624 | |||
| 597 | NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { | 625 | NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { |
| 598 | // clang-format off | 626 | // clang-format off |
| 599 | static const FunctionInfo functions[] = { | 627 | static const FunctionInfo functions[] = { |
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 4dc191518..9c18e935c 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h | |||
| @@ -78,6 +78,9 @@ class IReadOnlyApplicationControlDataInterface final | |||
| 78 | public: | 78 | public: |
| 79 | explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); | 79 | explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); |
| 80 | ~IReadOnlyApplicationControlDataInterface() override; | 80 | ~IReadOnlyApplicationControlDataInterface() override; |
| 81 | |||
| 82 | private: | ||
| 83 | void GetApplicationControlData(Kernel::HLERequestContext& ctx); | ||
| 81 | }; | 84 | }; |
| 82 | 85 | ||
| 83 | class NS final : public ServiceFramework<NS> { | 86 | class NS final : public ServiceFramework<NS> { |
diff --git a/src/core/hle/service/ptm/ts.cpp b/src/core/hle/service/ptm/ts.cpp index 65c3f135f..b1a0a5544 100644 --- a/src/core/hle/service/ptm/ts.cpp +++ b/src/core/hle/service/ptm/ts.cpp | |||
| @@ -15,7 +15,7 @@ TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} { | |||
| 15 | {0, nullptr, "GetTemperatureRange"}, | 15 | {0, nullptr, "GetTemperatureRange"}, |
| 16 | {1, &TS::GetTemperature, "GetTemperature"}, | 16 | {1, &TS::GetTemperature, "GetTemperature"}, |
| 17 | {2, nullptr, "SetMeasurementMode"}, | 17 | {2, nullptr, "SetMeasurementMode"}, |
| 18 | {3, nullptr, "GetTemperatureMilliC"}, | 18 | {3, &TS::GetTemperatureMilliC, "GetTemperatureMilliC"}, |
| 19 | {4, nullptr, "OpenSession"}, | 19 | {4, nullptr, "OpenSession"}, |
| 20 | }; | 20 | }; |
| 21 | // clang-format on | 21 | // clang-format on |
| @@ -29,8 +29,6 @@ void TS::GetTemperature(Kernel::HLERequestContext& ctx) { | |||
| 29 | IPC::RequestParser rp{ctx}; | 29 | IPC::RequestParser rp{ctx}; |
| 30 | const auto location{rp.PopEnum<Location>()}; | 30 | const auto location{rp.PopEnum<Location>()}; |
| 31 | 31 | ||
| 32 | LOG_WARNING(Service_HID, "(STUBBED) called. location={}", location); | ||
| 33 | |||
| 34 | const s32 temperature = location == Location::Internal ? 35 : 20; | 32 | const s32 temperature = location == Location::Internal ? 35 : 20; |
| 35 | 33 | ||
| 36 | IPC::ResponseBuilder rb{ctx, 3}; | 34 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -38,4 +36,15 @@ void TS::GetTemperature(Kernel::HLERequestContext& ctx) { | |||
| 38 | rb.Push(temperature); | 36 | rb.Push(temperature); |
| 39 | } | 37 | } |
| 40 | 38 | ||
| 39 | void TS::GetTemperatureMilliC(Kernel::HLERequestContext& ctx) { | ||
| 40 | IPC::RequestParser rp{ctx}; | ||
| 41 | const auto location{rp.PopEnum<Location>()}; | ||
| 42 | |||
| 43 | const s32 temperature = location == Location::Internal ? 35000 : 20000; | ||
| 44 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 46 | rb.Push(ResultSuccess); | ||
| 47 | rb.Push(temperature); | ||
| 48 | } | ||
| 49 | |||
| 41 | } // namespace Service::PTM | 50 | } // namespace Service::PTM |
diff --git a/src/core/hle/service/ptm/ts.h b/src/core/hle/service/ptm/ts.h index 39a734ef7..39d51847e 100644 --- a/src/core/hle/service/ptm/ts.h +++ b/src/core/hle/service/ptm/ts.h | |||
| @@ -20,6 +20,7 @@ private: | |||
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | void GetTemperature(Kernel::HLERequestContext& ctx); | 22 | void GetTemperature(Kernel::HLERequestContext& ctx); |
| 23 | void GetTemperatureMilliC(Kernel::HLERequestContext& ctx); | ||
| 23 | }; | 24 | }; |
| 24 | 25 | ||
| 25 | } // namespace Service::PTM | 26 | } // namespace Service::PTM |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 2a0b812c1..d7cea6aac 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -101,6 +101,81 @@ void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { | |||
| 101 | rb.Push(ResultSuccess); | 101 | rb.Push(ResultSuccess); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | // FIXME: implement support for the real system_settings.ini | ||
| 105 | |||
| 106 | template <typename T> | ||
| 107 | static std::vector<u8> ToBytes(const T& value) { | ||
| 108 | static_assert(std::is_trivially_copyable_v<T>); | ||
| 109 | |||
| 110 | const auto* begin = reinterpret_cast<const u8*>(&value); | ||
| 111 | const auto* end = begin + sizeof(T); | ||
| 112 | |||
| 113 | return std::vector<u8>(begin, end); | ||
| 114 | } | ||
| 115 | |||
| 116 | using Settings = | ||
| 117 | std::map<std::string, std::map<std::string, std::vector<u8>, std::less<>>, std::less<>>; | ||
| 118 | |||
| 119 | static Settings GetSettings() { | ||
| 120 | Settings ret; | ||
| 121 | |||
| 122 | ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0}); | ||
| 123 | ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000}); | ||
| 124 | |||
| 125 | return ret; | ||
| 126 | } | ||
| 127 | |||
| 128 | void SET_SYS::GetSettingsItemValueSize(Kernel::HLERequestContext& ctx) { | ||
| 129 | LOG_DEBUG(Service_SET, "called"); | ||
| 130 | |||
| 131 | // The category of the setting. This corresponds to the top-level keys of | ||
| 132 | // system_settings.ini. | ||
| 133 | const auto setting_category_buf{ctx.ReadBuffer(0)}; | ||
| 134 | const std::string setting_category{setting_category_buf.begin(), setting_category_buf.end()}; | ||
| 135 | |||
| 136 | // The name of the setting. This corresponds to the second-level keys of | ||
| 137 | // system_settings.ini. | ||
| 138 | const auto setting_name_buf{ctx.ReadBuffer(1)}; | ||
| 139 | const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()}; | ||
| 140 | |||
| 141 | auto settings{GetSettings()}; | ||
| 142 | u64 response_size{0}; | ||
| 143 | |||
| 144 | if (settings.contains(setting_category) && settings[setting_category].contains(setting_name)) { | ||
| 145 | response_size = settings[setting_category][setting_name].size(); | ||
| 146 | } | ||
| 147 | |||
| 148 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 149 | rb.Push(response_size == 0 ? ResultUnknown : ResultSuccess); | ||
| 150 | rb.Push(response_size); | ||
| 151 | } | ||
| 152 | |||
| 153 | void SET_SYS::GetSettingsItemValue(Kernel::HLERequestContext& ctx) { | ||
| 154 | LOG_DEBUG(Service_SET, "called"); | ||
| 155 | |||
| 156 | // The category of the setting. This corresponds to the top-level keys of | ||
| 157 | // system_settings.ini. | ||
| 158 | const auto setting_category_buf{ctx.ReadBuffer(0)}; | ||
| 159 | const std::string setting_category{setting_category_buf.begin(), setting_category_buf.end()}; | ||
| 160 | |||
| 161 | // The name of the setting. This corresponds to the second-level keys of | ||
| 162 | // system_settings.ini. | ||
| 163 | const auto setting_name_buf{ctx.ReadBuffer(1)}; | ||
| 164 | const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()}; | ||
| 165 | |||
| 166 | auto settings{GetSettings()}; | ||
| 167 | Result response{ResultUnknown}; | ||
| 168 | |||
| 169 | if (settings.contains(setting_category) && settings[setting_category].contains(setting_name)) { | ||
| 170 | auto setting_value = settings[setting_category][setting_name]; | ||
| 171 | ctx.WriteBuffer(setting_value.data(), setting_value.size()); | ||
| 172 | response = ResultSuccess; | ||
| 173 | } | ||
| 174 | |||
| 175 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 176 | rb.Push(response); | ||
| 177 | } | ||
| 178 | |||
| 104 | SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { | 179 | SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { |
| 105 | // clang-format off | 180 | // clang-format off |
| 106 | static const FunctionInfo functions[] = { | 181 | static const FunctionInfo functions[] = { |
| @@ -138,8 +213,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { | |||
| 138 | {32, nullptr, "SetAccountNotificationSettings"}, | 213 | {32, nullptr, "SetAccountNotificationSettings"}, |
| 139 | {35, nullptr, "GetVibrationMasterVolume"}, | 214 | {35, nullptr, "GetVibrationMasterVolume"}, |
| 140 | {36, nullptr, "SetVibrationMasterVolume"}, | 215 | {36, nullptr, "SetVibrationMasterVolume"}, |
| 141 | {37, nullptr, "GetSettingsItemValueSize"}, | 216 | {37, &SET_SYS::GetSettingsItemValueSize, "GetSettingsItemValueSize"}, |
| 142 | {38, nullptr, "GetSettingsItemValue"}, | 217 | {38, &SET_SYS::GetSettingsItemValue, "GetSettingsItemValue"}, |
| 143 | {39, nullptr, "GetTvSettings"}, | 218 | {39, nullptr, "GetTvSettings"}, |
| 144 | {40, nullptr, "SetTvSettings"}, | 219 | {40, nullptr, "SetTvSettings"}, |
| 145 | {41, nullptr, "GetEdid"}, | 220 | {41, nullptr, "GetEdid"}, |
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h index ac97772b7..258ef8c57 100644 --- a/src/core/hle/service/set/set_sys.h +++ b/src/core/hle/service/set/set_sys.h | |||
| @@ -23,6 +23,8 @@ private: | |||
| 23 | BasicBlack = 1, | 23 | BasicBlack = 1, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | void GetSettingsItemValueSize(Kernel::HLERequestContext& ctx); | ||
| 27 | void GetSettingsItemValue(Kernel::HLERequestContext& ctx); | ||
| 26 | void GetFirmwareVersion(Kernel::HLERequestContext& ctx); | 28 | void GetFirmwareVersion(Kernel::HLERequestContext& ctx); |
| 27 | void GetFirmwareVersion2(Kernel::HLERequestContext& ctx); | 29 | void GetFirmwareVersion2(Kernel::HLERequestContext& ctx); |
| 28 | void GetColorSetId(Kernel::HLERequestContext& ctx); | 30 | void GetColorSetId(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 246c94623..48e70f93c 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -156,7 +156,8 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& | |||
| 156 | 156 | ||
| 157 | // Create a new session. | 157 | // Create a new session. |
| 158 | Kernel::KClientSession* session{}; | 158 | Kernel::KClientSession* session{}; |
| 159 | if (const auto result = port->GetClientPort().CreateSession(std::addressof(session)); | 159 | if (const auto result = port->GetClientPort().CreateSession( |
| 160 | std::addressof(session), std::make_shared<Kernel::SessionRequestManager>(kernel)); | ||
| 160 | result.IsError()) { | 161 | result.IsError()) { |
| 161 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); | 162 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); |
| 162 | return result; | 163 | return result; |