diff options
| author | 2022-10-14 17:30:11 -0400 | |
|---|---|---|
| committer | 2022-10-14 17:30:11 -0400 | |
| commit | 1d3810971453df275ccd0fcdfb9c480a070c30c3 (patch) | |
| tree | d55dcc3f619ea075f55b4085648ffafb7717eed9 /src/core/hle/kernel/svc.cpp | |
| parent | Merge pull request #9069 from german77/sdl2 (diff) | |
| parent | k_server_session: preliminary support for userspace server sessions (diff) | |
| download | yuzu-1d3810971453df275ccd0fcdfb9c480a070c30c3.tar.gz yuzu-1d3810971453df275ccd0fcdfb9c480a070c30c3.tar.xz yuzu-1d3810971453df275ccd0fcdfb9c480a070c30c3.zip | |
Merge pull request #9055 from liamwhite/hbl
Preliminary support for nx-hbloader
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 170 |
1 files changed, 156 insertions, 14 deletions
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"}, |