diff options
| author | 2021-05-07 23:30:17 -0700 | |
|---|---|---|
| committer | 2021-05-07 23:30:17 -0700 | |
| commit | faa067f175cbf5e916ed75776817f0046e6731c4 (patch) | |
| tree | 8ab02a72a6e4d6578848c8da2c02af02684aeec7 /src/core/hle/kernel/svc.cpp | |
| parent | Merge pull request #6287 from lioncash/ldr-copy (diff) | |
| parent | hle: kernel: KPageTable: CanContain should not be constexpr. (diff) | |
| download | yuzu-faa067f175cbf5e916ed75776817f0046e6731c4.tar.gz yuzu-faa067f175cbf5e916ed75776817f0046e6731c4.tar.xz yuzu-faa067f175cbf5e916ed75776817f0046e6731c4.zip | |
Merge pull request #6266 from bunnei/kautoobject-refactor
Kernel Rework: Migrate kernel objects to KAutoObject
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 995 |
1 files changed, 466 insertions, 529 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index bebb86154..52011be9c 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -21,15 +21,16 @@ | |||
| 21 | #include "core/core_timing.h" | 21 | #include "core/core_timing.h" |
| 22 | #include "core/core_timing_util.h" | 22 | #include "core/core_timing_util.h" |
| 23 | #include "core/cpu_manager.h" | 23 | #include "core/cpu_manager.h" |
| 24 | #include "core/hle/kernel/client_port.h" | ||
| 25 | #include "core/hle/kernel/client_session.h" | ||
| 26 | #include "core/hle/kernel/handle_table.h" | ||
| 27 | #include "core/hle/kernel/k_address_arbiter.h" | 24 | #include "core/hle/kernel/k_address_arbiter.h" |
| 25 | #include "core/hle/kernel/k_client_port.h" | ||
| 26 | #include "core/hle/kernel/k_client_session.h" | ||
| 28 | #include "core/hle/kernel/k_condition_variable.h" | 27 | #include "core/hle/kernel/k_condition_variable.h" |
| 29 | #include "core/hle/kernel/k_event.h" | 28 | #include "core/hle/kernel/k_event.h" |
| 29 | #include "core/hle/kernel/k_handle_table.h" | ||
| 30 | #include "core/hle/kernel/k_memory_block.h" | 30 | #include "core/hle/kernel/k_memory_block.h" |
| 31 | #include "core/hle/kernel/k_memory_layout.h" | 31 | #include "core/hle/kernel/k_memory_layout.h" |
| 32 | #include "core/hle/kernel/k_page_table.h" | 32 | #include "core/hle/kernel/k_page_table.h" |
| 33 | #include "core/hle/kernel/k_process.h" | ||
| 33 | #include "core/hle/kernel/k_readable_event.h" | 34 | #include "core/hle/kernel/k_readable_event.h" |
| 34 | #include "core/hle/kernel/k_resource_limit.h" | 35 | #include "core/hle/kernel/k_resource_limit.h" |
| 35 | #include "core/hle/kernel/k_scheduler.h" | 36 | #include "core/hle/kernel/k_scheduler.h" |
| @@ -38,16 +39,15 @@ | |||
| 38 | #include "core/hle/kernel/k_shared_memory.h" | 39 | #include "core/hle/kernel/k_shared_memory.h" |
| 39 | #include "core/hle/kernel/k_synchronization_object.h" | 40 | #include "core/hle/kernel/k_synchronization_object.h" |
| 40 | #include "core/hle/kernel/k_thread.h" | 41 | #include "core/hle/kernel/k_thread.h" |
| 42 | #include "core/hle/kernel/k_transfer_memory.h" | ||
| 41 | #include "core/hle/kernel/k_writable_event.h" | 43 | #include "core/hle/kernel/k_writable_event.h" |
| 42 | #include "core/hle/kernel/kernel.h" | 44 | #include "core/hle/kernel/kernel.h" |
| 43 | #include "core/hle/kernel/physical_core.h" | 45 | #include "core/hle/kernel/physical_core.h" |
| 44 | #include "core/hle/kernel/process.h" | ||
| 45 | #include "core/hle/kernel/svc.h" | 46 | #include "core/hle/kernel/svc.h" |
| 46 | #include "core/hle/kernel/svc_results.h" | 47 | #include "core/hle/kernel/svc_results.h" |
| 47 | #include "core/hle/kernel/svc_types.h" | 48 | #include "core/hle/kernel/svc_types.h" |
| 48 | #include "core/hle/kernel/svc_wrap.h" | 49 | #include "core/hle/kernel/svc_wrap.h" |
| 49 | #include "core/hle/kernel/time_manager.h" | 50 | #include "core/hle/kernel/time_manager.h" |
| 50 | #include "core/hle/kernel/transfer_memory.h" | ||
| 51 | #include "core/hle/lock.h" | 51 | #include "core/hle/lock.h" |
| 52 | #include "core/hle/result.h" | 52 | #include "core/hle/result.h" |
| 53 | #include "core/hle/service/service.h" | 53 | #include "core/hle/service/service.h" |
| @@ -113,7 +113,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, | |||
| 113 | LOG_ERROR(Kernel_SVC, | 113 | LOG_ERROR(Kernel_SVC, |
| 114 | "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", | 114 | "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", |
| 115 | dst_addr, size); | 115 | dst_addr, size); |
| 116 | return ResultInvalidMemoryRange; | 116 | return ResultInvalidMemoryRegion; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | if (manager.IsInsideHeapRegion(dst_addr, size)) { | 119 | if (manager.IsInsideHeapRegion(dst_addr, size)) { |
| @@ -121,7 +121,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, | |||
| 121 | "Destination does not fit within the heap region, addr=0x{:016X}, " | 121 | "Destination does not fit within the heap region, addr=0x{:016X}, " |
| 122 | "size=0x{:016X}", | 122 | "size=0x{:016X}", |
| 123 | dst_addr, size); | 123 | dst_addr, size); |
| 124 | return ResultInvalidMemoryRange; | 124 | return ResultInvalidMemoryRegion; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | if (manager.IsInsideAliasRegion(dst_addr, size)) { | 127 | if (manager.IsInsideAliasRegion(dst_addr, size)) { |
| @@ -129,7 +129,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, | |||
| 129 | "Destination does not fit within the map region, addr=0x{:016X}, " | 129 | "Destination does not fit within the map region, addr=0x{:016X}, " |
| 130 | "size=0x{:016X}", | 130 | "size=0x{:016X}", |
| 131 | dst_addr, size); | 131 | dst_addr, size); |
| 132 | return ResultInvalidMemoryRange; | 132 | return ResultInvalidMemoryRegion; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | return RESULT_SUCCESS; | 135 | return RESULT_SUCCESS; |
| @@ -141,38 +141,6 @@ enum class ResourceLimitValueType { | |||
| 141 | PeakValue, | 141 | PeakValue, |
| 142 | }; | 142 | }; |
| 143 | 143 | ||
| 144 | ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, | ||
| 145 | u32 resource_type, ResourceLimitValueType value_type) { | ||
| 146 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 147 | const auto type = static_cast<LimitableResource>(resource_type); | ||
| 148 | if (!IsValidResourceType(type)) { | ||
| 149 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 150 | return ResultInvalidEnumValue; | ||
| 151 | } | ||
| 152 | |||
| 153 | const auto* const current_process = system.Kernel().CurrentProcess(); | ||
| 154 | ASSERT(current_process != nullptr); | ||
| 155 | |||
| 156 | const auto resource_limit_object = | ||
| 157 | current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); | ||
| 158 | if (!resource_limit_object) { | ||
| 159 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | ||
| 160 | resource_limit); | ||
| 161 | return ResultInvalidHandle; | ||
| 162 | } | ||
| 163 | |||
| 164 | switch (value_type) { | ||
| 165 | case ResourceLimitValueType::CurrentValue: | ||
| 166 | return MakeResult(resource_limit_object->GetCurrentValue(type)); | ||
| 167 | case ResourceLimitValueType::LimitValue: | ||
| 168 | return MakeResult(resource_limit_object->GetLimitValue(type)); | ||
| 169 | case ResourceLimitValueType::PeakValue: | ||
| 170 | return MakeResult(resource_limit_object->GetPeakValue(type)); | ||
| 171 | default: | ||
| 172 | LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type); | ||
| 173 | return ResultInvalidEnumValue; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } // Anonymous namespace | 144 | } // Anonymous namespace |
| 177 | 145 | ||
| 178 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 146 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| @@ -291,11 +259,8 @@ static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr | |||
| 291 | } | 259 | } |
| 292 | 260 | ||
| 293 | /// Connect to an OS service given the port name, returns the handle to the port to out | 261 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 294 | static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, | 262 | static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { |
| 295 | VAddr port_name_address) { | ||
| 296 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 297 | auto& memory = system.Memory(); | 263 | auto& memory = system.Memory(); |
| 298 | |||
| 299 | if (!memory.IsValidVirtualAddress(port_name_address)) { | 264 | if (!memory.IsValidVirtualAddress(port_name_address)) { |
| 300 | LOG_ERROR(Kernel_SVC, | 265 | LOG_ERROR(Kernel_SVC, |
| 301 | "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", | 266 | "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", |
| @@ -314,21 +279,33 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, | |||
| 314 | 279 | ||
| 315 | LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); | 280 | LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); |
| 316 | 281 | ||
| 282 | // Get the current handle table. | ||
| 317 | auto& kernel = system.Kernel(); | 283 | auto& kernel = system.Kernel(); |
| 284 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||
| 285 | |||
| 286 | // Find the client port. | ||
| 318 | const auto it = kernel.FindNamedPort(port_name); | 287 | const auto it = kernel.FindNamedPort(port_name); |
| 319 | if (!kernel.IsValidNamedPort(it)) { | 288 | if (!kernel.IsValidNamedPort(it)) { |
| 320 | LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); | 289 | LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); |
| 321 | return ResultNotFound; | 290 | return ResultNotFound; |
| 322 | } | 291 | } |
| 292 | auto port = it->second; | ||
| 323 | 293 | ||
| 324 | auto client_port = it->second; | 294 | // Reserve a handle for the port. |
| 295 | // NOTE: Nintendo really does write directly to the output handle here. | ||
| 296 | R_TRY(handle_table.Reserve(out)); | ||
| 297 | auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); }); | ||
| 325 | 298 | ||
| 326 | std::shared_ptr<ClientSession> client_session; | 299 | // Create a session. |
| 327 | CASCADE_RESULT(client_session, client_port->Connect()); | 300 | KClientSession* session{}; |
| 301 | R_TRY(port->CreateSession(std::addressof(session))); | ||
| 328 | 302 | ||
| 329 | // Return the client session | 303 | // Register the session in the table, close the extra reference. |
| 330 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 304 | handle_table.Register(*out, session); |
| 331 | CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); | 305 | session->Close(); |
| 306 | |||
| 307 | // We succeeded. | ||
| 308 | handle_guard.Cancel(); | ||
| 332 | return RESULT_SUCCESS; | 309 | return RESULT_SUCCESS; |
| 333 | } | 310 | } |
| 334 | 311 | ||
| @@ -340,14 +317,12 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, | |||
| 340 | 317 | ||
| 341 | /// Makes a blocking IPC call to an OS service. | 318 | /// Makes a blocking IPC call to an OS service. |
| 342 | static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | 319 | static ResultCode SendSyncRequest(Core::System& system, Handle handle) { |
| 320 | |||
| 343 | auto& kernel = system.Kernel(); | 321 | auto& kernel = system.Kernel(); |
| 344 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||
| 345 | std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle); | ||
| 346 | if (!session) { | ||
| 347 | LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); | ||
| 348 | return ResultInvalidHandle; | ||
| 349 | } | ||
| 350 | 322 | ||
| 323 | KScopedAutoObject session = | ||
| 324 | kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); | ||
| 325 | R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||
| 351 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | 326 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); |
| 352 | 327 | ||
| 353 | auto thread = kernel.CurrentScheduler()->GetCurrentThread(); | 328 | auto thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| @@ -355,7 +330,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 355 | KScopedSchedulerLock lock(kernel); | 330 | KScopedSchedulerLock lock(kernel); |
| 356 | thread->SetState(ThreadState::Waiting); | 331 | thread->SetState(ThreadState::Waiting); |
| 357 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | 332 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); |
| 358 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); | 333 | session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); |
| 359 | } | 334 | } |
| 360 | 335 | ||
| 361 | KSynchronizationObject* dummy{}; | 336 | KSynchronizationObject* dummy{}; |
| @@ -368,18 +343,13 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { | |||
| 368 | 343 | ||
| 369 | /// Get the ID for the specified thread. | 344 | /// Get the ID for the specified thread. |
| 370 | static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { | 345 | static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { |
| 371 | LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | ||
| 372 | |||
| 373 | // Get the thread from its handle. | 346 | // Get the thread from its handle. |
| 374 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 347 | KScopedAutoObject thread = |
| 375 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 348 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); |
| 376 | if (!thread) { | 349 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 377 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 378 | return ResultInvalidHandle; | ||
| 379 | } | ||
| 380 | 350 | ||
| 381 | // Get the thread's id. | 351 | // Get the thread's id. |
| 382 | *out_thread_id = thread->GetThreadID(); | 352 | *out_thread_id = thread->GetId(); |
| 383 | return RESULT_SUCCESS; | 353 | return RESULT_SUCCESS; |
| 384 | } | 354 | } |
| 385 | 355 | ||
| @@ -395,110 +365,101 @@ static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, | |||
| 395 | } | 365 | } |
| 396 | 366 | ||
| 397 | /// Gets the ID of the specified process or a specified thread's owning process. | 367 | /// Gets the ID of the specified process or a specified thread's owning process. |
| 398 | static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { | 368 | static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle handle) { |
| 399 | LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); | 369 | LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); |
| 400 | 370 | ||
| 401 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 371 | // Get the object from the handle table. |
| 402 | const std::shared_ptr<Process> process = handle_table.Get<Process>(handle); | 372 | KScopedAutoObject obj = |
| 403 | if (process) { | 373 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>( |
| 404 | *process_id = process->GetProcessID(); | 374 | static_cast<Handle>(handle)); |
| 405 | return RESULT_SUCCESS; | 375 | R_UNLESS(obj.IsNotNull(), ResultInvalidHandle); |
| 376 | |||
| 377 | // Get the process from the object. | ||
| 378 | KProcess* process = nullptr; | ||
| 379 | if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) { | ||
| 380 | // The object is a process, so we can use it directly. | ||
| 381 | process = p; | ||
| 382 | } else if (KThread* t = obj->DynamicCast<KThread*>(); t != nullptr) { | ||
| 383 | // The object is a thread, so we want to use its parent. | ||
| 384 | process = reinterpret_cast<KThread*>(obj.GetPointerUnsafe())->GetOwnerProcess(); | ||
| 385 | } else { | ||
| 386 | // TODO(bunnei): This should also handle debug objects before returning. | ||
| 387 | UNIMPLEMENTED_MSG("Debug objects not implemented"); | ||
| 406 | } | 388 | } |
| 407 | 389 | ||
| 408 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); | 390 | // Make sure the target process exists. |
| 409 | if (thread) { | 391 | R_UNLESS(process != nullptr, ResultInvalidHandle); |
| 410 | const Process* const owner_process = thread->GetOwnerProcess(); | ||
| 411 | if (!owner_process) { | ||
| 412 | LOG_ERROR(Kernel_SVC, "Non-existent owning process encountered."); | ||
| 413 | return ResultInvalidHandle; | ||
| 414 | } | ||
| 415 | |||
| 416 | *process_id = owner_process->GetProcessID(); | ||
| 417 | return RESULT_SUCCESS; | ||
| 418 | } | ||
| 419 | 392 | ||
| 420 | // NOTE: This should also handle debug objects before returning. | 393 | // Get the process id. |
| 394 | *out_process_id = process->GetId(); | ||
| 421 | 395 | ||
| 422 | LOG_ERROR(Kernel_SVC, "Handle does not exist, handle=0x{:08X}", handle); | ||
| 423 | return ResultInvalidHandle; | 396 | return ResultInvalidHandle; |
| 424 | } | 397 | } |
| 425 | 398 | ||
| 426 | static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, | 399 | static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low, |
| 427 | Handle handle) { | 400 | u32* out_process_id_high, Handle handle) { |
| 428 | u64 process_id{}; | 401 | u64 out_process_id{}; |
| 429 | const auto result = GetProcessId(system, &process_id, handle); | 402 | const auto result = GetProcessId(system, &out_process_id, handle); |
| 430 | *process_id_low = static_cast<u32>(process_id); | 403 | *out_process_id_low = static_cast<u32>(out_process_id); |
| 431 | *process_id_high = static_cast<u32>(process_id >> 32); | 404 | *out_process_id_high = static_cast<u32>(out_process_id >> 32); |
| 432 | return result; | 405 | return result; |
| 433 | } | 406 | } |
| 434 | 407 | ||
| 435 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 408 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 436 | static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, | 409 | static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, |
| 437 | u64 handle_count, s64 nano_seconds) { | 410 | u64 num_handles, s64 nano_seconds) { |
| 438 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", | 411 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}", |
| 439 | handles_address, handle_count, nano_seconds); | 412 | handles_address, num_handles, nano_seconds); |
| 440 | 413 | ||
| 441 | auto& memory = system.Memory(); | 414 | // Ensure number of handles is valid. |
| 442 | if (!memory.IsValidVirtualAddress(handles_address)) { | 415 | R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); |
| 443 | LOG_ERROR(Kernel_SVC, | ||
| 444 | "Handle address is not a valid virtual address, handle_address=0x{:016X}", | ||
| 445 | handles_address); | ||
| 446 | return ResultInvalidPointer; | ||
| 447 | } | ||
| 448 | |||
| 449 | static constexpr u64 MaxHandles = 0x40; | ||
| 450 | |||
| 451 | if (handle_count > MaxHandles) { | ||
| 452 | LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}", | ||
| 453 | MaxHandles, handle_count); | ||
| 454 | return ResultOutOfRange; | ||
| 455 | } | ||
| 456 | 416 | ||
| 457 | auto& kernel = system.Kernel(); | 417 | auto& kernel = system.Kernel(); |
| 458 | std::vector<KSynchronizationObject*> objects(handle_count); | 418 | std::vector<KSynchronizationObject*> objs(num_handles); |
| 459 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 419 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 420 | Handle* handles = system.Memory().GetPointer<Handle>(handles_address); | ||
| 460 | 421 | ||
| 461 | for (u64 i = 0; i < handle_count; ++i) { | 422 | // Copy user handles. |
| 462 | const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); | 423 | if (num_handles > 0) { |
| 463 | const auto object = handle_table.Get<KSynchronizationObject>(handle); | 424 | // Convert the handles to objects. |
| 425 | R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, | ||
| 426 | num_handles), | ||
| 427 | ResultInvalidHandle); | ||
| 428 | } | ||
| 464 | 429 | ||
| 465 | if (object == nullptr) { | 430 | // Ensure handles are closed when we're done. |
| 466 | LOG_ERROR(Kernel_SVC, "Object is a nullptr"); | 431 | SCOPE_EXIT({ |
| 467 | return ResultInvalidHandle; | 432 | for (u64 i = 0; i < num_handles; ++i) { |
| 433 | objs[i]->Close(); | ||
| 468 | } | 434 | } |
| 435 | }); | ||
| 469 | 436 | ||
| 470 | objects[i] = object.get(); | 437 | return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()), |
| 471 | } | 438 | nano_seconds); |
| 472 | return KSynchronizationObject::Wait(kernel, index, objects.data(), | ||
| 473 | static_cast<s32>(objects.size()), nano_seconds); | ||
| 474 | } | 439 | } |
| 475 | 440 | ||
| 476 | static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, | 441 | static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, |
| 477 | s32 handle_count, u32 timeout_high, s32* index) { | 442 | s32 num_handles, u32 timeout_high, s32* index) { |
| 478 | const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; | 443 | const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; |
| 479 | return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); | 444 | return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds); |
| 480 | } | 445 | } |
| 481 | 446 | ||
| 482 | /// Resumes a thread waiting on WaitSynchronization | 447 | /// Resumes a thread waiting on WaitSynchronization |
| 483 | static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { | 448 | static ResultCode CancelSynchronization(Core::System& system, Handle handle) { |
| 484 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); | 449 | LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); |
| 485 | 450 | ||
| 486 | // Get the thread from its handle. | 451 | // Get the thread from its handle. |
| 487 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 452 | KScopedAutoObject thread = |
| 488 | std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 453 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>( |
| 489 | 454 | static_cast<Handle>(handle)); | |
| 490 | if (!thread) { | ||
| 491 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 492 | return ResultInvalidHandle; | ||
| 493 | } | ||
| 494 | 455 | ||
| 495 | // Cancel the thread's wait. | 456 | // Cancel the thread's wait. |
| 496 | thread->WaitCancel(); | 457 | thread->WaitCancel(); |
| 497 | return RESULT_SUCCESS; | 458 | return RESULT_SUCCESS; |
| 498 | } | 459 | } |
| 499 | 460 | ||
| 500 | static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { | 461 | static ResultCode CancelSynchronization32(Core::System& system, Handle handle) { |
| 501 | return CancelSynchronization(system, thread_handle); | 462 | return CancelSynchronization(system, handle); |
| 502 | } | 463 | } |
| 503 | 464 | ||
| 504 | /// Attempts to locks a mutex | 465 | /// Attempts to locks a mutex |
| @@ -678,7 +639,7 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) { | |||
| 678 | } | 639 | } |
| 679 | 640 | ||
| 680 | /// Gets system/memory information for the current process | 641 | /// Gets system/memory information for the current process |
| 681 | static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, | 642 | static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle, |
| 682 | u64 info_sub_id) { | 643 | u64 info_sub_id) { |
| 683 | std::lock_guard lock{HLE::g_hle_lock}; | 644 | std::lock_guard lock{HLE::g_hle_lock}; |
| 684 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, | 645 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, |
| @@ -744,10 +705,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 744 | return ResultInvalidEnumValue; | 705 | return ResultInvalidEnumValue; |
| 745 | } | 706 | } |
| 746 | 707 | ||
| 747 | const auto& current_process_handle_table = | 708 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 748 | system.Kernel().CurrentProcess()->GetHandleTable(); | 709 | KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); |
| 749 | const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle)); | 710 | if (process.IsNull()) { |
| 750 | if (!process) { | ||
| 751 | LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", | 711 | LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", |
| 752 | info_id, info_sub_id, handle); | 712 | info_id, info_sub_id, handle); |
| 753 | return ResultInvalidHandle; | 713 | return ResultInvalidHandle; |
| @@ -851,21 +811,19 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 851 | return ResultInvalidCombination; | 811 | return ResultInvalidCombination; |
| 852 | } | 812 | } |
| 853 | 813 | ||
| 854 | Process* const current_process = system.Kernel().CurrentProcess(); | 814 | KProcess* const current_process = system.Kernel().CurrentProcess(); |
| 855 | HandleTable& handle_table = current_process->GetHandleTable(); | 815 | KHandleTable& handle_table = current_process->GetHandleTable(); |
| 856 | const auto resource_limit = current_process->GetResourceLimit(); | 816 | const auto resource_limit = current_process->GetResourceLimit(); |
| 857 | if (!resource_limit) { | 817 | if (!resource_limit) { |
| 858 | *result = KernelHandle::InvalidHandle; | 818 | *result = Svc::InvalidHandle; |
| 859 | // Yes, the kernel considers this a successful operation. | 819 | // Yes, the kernel considers this a successful operation. |
| 860 | return RESULT_SUCCESS; | 820 | return RESULT_SUCCESS; |
| 861 | } | 821 | } |
| 862 | 822 | ||
| 863 | const auto table_result = handle_table.Create(resource_limit); | 823 | Handle handle{}; |
| 864 | if (table_result.Failed()) { | 824 | R_TRY(handle_table.Add(&handle, resource_limit)); |
| 865 | return table_result.Code(); | ||
| 866 | } | ||
| 867 | 825 | ||
| 868 | *result = *table_result; | 826 | *result = handle; |
| 869 | return RESULT_SUCCESS; | 827 | return RESULT_SUCCESS; |
| 870 | } | 828 | } |
| 871 | 829 | ||
| @@ -876,9 +834,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 876 | return ResultInvalidHandle; | 834 | return ResultInvalidHandle; |
| 877 | } | 835 | } |
| 878 | 836 | ||
| 879 | if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { | 837 | if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) { |
| 880 | LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", | 838 | LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", |
| 881 | Process::RANDOM_ENTROPY_SIZE, info_sub_id); | 839 | KProcess::RANDOM_ENTROPY_SIZE, info_sub_id); |
| 882 | return ResultInvalidCombination; | 840 | return ResultInvalidCombination; |
| 883 | } | 841 | } |
| 884 | 842 | ||
| @@ -899,9 +857,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 899 | return ResultInvalidCombination; | 857 | return ResultInvalidCombination; |
| 900 | } | 858 | } |
| 901 | 859 | ||
| 902 | const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>( | 860 | KScopedAutoObject thread = |
| 903 | static_cast<Handle>(handle)); | 861 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>( |
| 904 | if (!thread) { | 862 | static_cast<Handle>(handle)); |
| 863 | if (thread.IsNull()) { | ||
| 905 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", | 864 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", |
| 906 | static_cast<Handle>(handle)); | 865 | static_cast<Handle>(handle)); |
| 907 | return ResultInvalidHandle; | 866 | return ResultInvalidHandle; |
| @@ -910,7 +869,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 910 | const auto& core_timing = system.CoreTiming(); | 869 | const auto& core_timing = system.CoreTiming(); |
| 911 | const auto& scheduler = *system.Kernel().CurrentScheduler(); | 870 | const auto& scheduler = *system.Kernel().CurrentScheduler(); |
| 912 | const auto* const current_thread = scheduler.GetCurrentThread(); | 871 | const auto* const current_thread = scheduler.GetCurrentThread(); |
| 913 | const bool same_thread = current_thread == thread.get(); | 872 | const bool same_thread = current_thread == thread.GetPointerUnsafe(); |
| 914 | 873 | ||
| 915 | const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); | 874 | const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); |
| 916 | u64 out_ticks = 0; | 875 | u64 out_ticks = 0; |
| @@ -966,10 +925,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) | |||
| 966 | 925 | ||
| 967 | if (!(addr < addr + size)) { | 926 | if (!(addr < addr + size)) { |
| 968 | LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); | 927 | LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); |
| 969 | return ResultInvalidMemoryRange; | 928 | return ResultInvalidMemoryRegion; |
| 970 | } | 929 | } |
| 971 | 930 | ||
| 972 | Process* const current_process{system.Kernel().CurrentProcess()}; | 931 | KProcess* const current_process{system.Kernel().CurrentProcess()}; |
| 973 | auto& page_table{current_process->PageTable()}; | 932 | auto& page_table{current_process->PageTable()}; |
| 974 | 933 | ||
| 975 | if (current_process->GetSystemResourceSize() == 0) { | 934 | if (current_process->GetSystemResourceSize() == 0) { |
| @@ -981,14 +940,14 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) | |||
| 981 | LOG_ERROR(Kernel_SVC, | 940 | LOG_ERROR(Kernel_SVC, |
| 982 | "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, | 941 | "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, |
| 983 | size); | 942 | size); |
| 984 | return ResultInvalidMemoryRange; | 943 | return ResultInvalidMemoryRegion; |
| 985 | } | 944 | } |
| 986 | 945 | ||
| 987 | if (page_table.IsOutsideAliasRegion(addr, size)) { | 946 | if (page_table.IsOutsideAliasRegion(addr, size)) { |
| 988 | LOG_ERROR(Kernel_SVC, | 947 | LOG_ERROR(Kernel_SVC, |
| 989 | "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, | 948 | "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, |
| 990 | size); | 949 | size); |
| 991 | return ResultInvalidMemoryRange; | 950 | return ResultInvalidMemoryRegion; |
| 992 | } | 951 | } |
| 993 | 952 | ||
| 994 | return page_table.MapPhysicalMemory(addr, size); | 953 | return page_table.MapPhysicalMemory(addr, size); |
| @@ -1020,10 +979,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size | |||
| 1020 | 979 | ||
| 1021 | if (!(addr < addr + size)) { | 980 | if (!(addr < addr + size)) { |
| 1022 | LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); | 981 | LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); |
| 1023 | return ResultInvalidMemoryRange; | 982 | return ResultInvalidMemoryRegion; |
| 1024 | } | 983 | } |
| 1025 | 984 | ||
| 1026 | Process* const current_process{system.Kernel().CurrentProcess()}; | 985 | KProcess* const current_process{system.Kernel().CurrentProcess()}; |
| 1027 | auto& page_table{current_process->PageTable()}; | 986 | auto& page_table{current_process->PageTable()}; |
| 1028 | 987 | ||
| 1029 | if (current_process->GetSystemResourceSize() == 0) { | 988 | if (current_process->GetSystemResourceSize() == 0) { |
| @@ -1035,14 +994,14 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size | |||
| 1035 | LOG_ERROR(Kernel_SVC, | 994 | LOG_ERROR(Kernel_SVC, |
| 1036 | "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, | 995 | "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, |
| 1037 | size); | 996 | size); |
| 1038 | return ResultInvalidMemoryRange; | 997 | return ResultInvalidMemoryRegion; |
| 1039 | } | 998 | } |
| 1040 | 999 | ||
| 1041 | if (page_table.IsOutsideAliasRegion(addr, size)) { | 1000 | if (page_table.IsOutsideAliasRegion(addr, size)) { |
| 1042 | LOG_ERROR(Kernel_SVC, | 1001 | LOG_ERROR(Kernel_SVC, |
| 1043 | "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, | 1002 | "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, |
| 1044 | size); | 1003 | size); |
| 1045 | return ResultInvalidMemoryRange; | 1004 | return ResultInvalidMemoryRegion; |
| 1046 | } | 1005 | } |
| 1047 | 1006 | ||
| 1048 | return page_table.UnmapPhysicalMemory(addr, size); | 1007 | return page_table.UnmapPhysicalMemory(addr, size); |
| @@ -1062,37 +1021,19 @@ static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, | |||
| 1062 | constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { | 1021 | constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { |
| 1063 | return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; | 1022 | return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; |
| 1064 | }; | 1023 | }; |
| 1065 | if (!IsValidThreadActivity(thread_activity)) { | 1024 | R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue); |
| 1066 | LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})", | ||
| 1067 | thread_activity); | ||
| 1068 | return ResultInvalidEnumValue; | ||
| 1069 | } | ||
| 1070 | 1025 | ||
| 1071 | // Get the thread from its handle. | 1026 | // Get the thread from its handle. |
| 1072 | auto& kernel = system.Kernel(); | 1027 | KScopedAutoObject thread = |
| 1073 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 1028 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); |
| 1074 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1029 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 1075 | if (!thread) { | ||
| 1076 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 1077 | return ResultInvalidHandle; | ||
| 1078 | } | ||
| 1079 | 1030 | ||
| 1080 | // Check that the activity is being set on a non-current thread for the current process. | 1031 | // Check that the activity is being set on a non-current thread for the current process. |
| 1081 | if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { | 1032 | R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle); |
| 1082 | LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); | 1033 | R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy); |
| 1083 | return ResultInvalidHandle; | ||
| 1084 | } | ||
| 1085 | if (thread.get() == GetCurrentThreadPointer(kernel)) { | ||
| 1086 | LOG_ERROR(Kernel_SVC, "Thread is busy"); | ||
| 1087 | return ResultBusy; | ||
| 1088 | } | ||
| 1089 | 1034 | ||
| 1090 | // Set the activity. | 1035 | // Set the activity. |
| 1091 | const auto set_result = thread->SetActivity(thread_activity); | 1036 | R_TRY(thread->SetActivity(thread_activity)); |
| 1092 | if (set_result.IsError()) { | ||
| 1093 | LOG_ERROR(Kernel_SVC, "Failed to set thread activity."); | ||
| 1094 | return set_result; | ||
| 1095 | } | ||
| 1096 | 1037 | ||
| 1097 | return RESULT_SUCCESS; | 1038 | return RESULT_SUCCESS; |
| 1098 | } | 1039 | } |
| @@ -1107,36 +1048,55 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand | |||
| 1107 | LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, | 1048 | LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, |
| 1108 | thread_handle); | 1049 | thread_handle); |
| 1109 | 1050 | ||
| 1051 | auto& kernel = system.Kernel(); | ||
| 1052 | |||
| 1110 | // Get the thread from its handle. | 1053 | // Get the thread from its handle. |
| 1111 | const auto* current_process = system.Kernel().CurrentProcess(); | 1054 | KScopedAutoObject thread = |
| 1112 | const std::shared_ptr<KThread> thread = | 1055 | kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); |
| 1113 | current_process->GetHandleTable().Get<KThread>(thread_handle); | 1056 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 1114 | if (!thread) { | ||
| 1115 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle); | ||
| 1116 | return ResultInvalidHandle; | ||
| 1117 | } | ||
| 1118 | 1057 | ||
| 1119 | // Require the handle be to a non-current thread in the current process. | 1058 | // Require the handle be to a non-current thread in the current process. |
| 1120 | if (thread->GetOwnerProcess() != current_process) { | 1059 | const auto* current_process = kernel.CurrentProcess(); |
| 1121 | LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); | 1060 | R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId); |
| 1122 | return ResultInvalidHandle; | ||
| 1123 | } | ||
| 1124 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { | ||
| 1125 | LOG_ERROR(Kernel_SVC, "Current thread is busy."); | ||
| 1126 | return ResultBusy; | ||
| 1127 | } | ||
| 1128 | 1061 | ||
| 1129 | // Get the thread context. | 1062 | // Verify that the thread isn't terminated. |
| 1130 | std::vector<u8> context; | 1063 | R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested); |
| 1131 | const auto context_result = thread->GetThreadContext3(context); | 1064 | |
| 1132 | if (context_result.IsError()) { | 1065 | /// Check that the thread is not the current one. |
| 1133 | LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", | 1066 | /// NOTE: Nintendo does not check this, and thus the following loop will deadlock. |
| 1134 | context_result.raw); | 1067 | R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId); |
| 1135 | return context_result; | 1068 | |
| 1136 | } | 1069 | // Try to get the thread context until the thread isn't current on any core. |
| 1070 | while (true) { | ||
| 1071 | KScopedSchedulerLock sl{kernel}; | ||
| 1137 | 1072 | ||
| 1138 | // Copy the thread context to user space. | 1073 | // TODO(bunnei): Enforce that thread is suspended for debug here. |
| 1139 | system.Memory().WriteBlock(out_context, context.data(), context.size()); | 1074 | |
| 1075 | // If the thread's raw state isn't runnable, check if it's current on some core. | ||
| 1076 | if (thread->GetRawState() != ThreadState::Runnable) { | ||
| 1077 | bool current = false; | ||
| 1078 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { | ||
| 1079 | if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) { | ||
| 1080 | current = true; | ||
| 1081 | } | ||
| 1082 | break; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | // If the thread is current, retry until it isn't. | ||
| 1086 | if (current) { | ||
| 1087 | continue; | ||
| 1088 | } | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | // Get the thread context. | ||
| 1092 | std::vector<u8> context; | ||
| 1093 | R_TRY(thread->GetThreadContext3(context)); | ||
| 1094 | |||
| 1095 | // Copy the thread context to user space. | ||
| 1096 | system.Memory().WriteBlock(out_context, context.data(), context.size()); | ||
| 1097 | |||
| 1098 | return RESULT_SUCCESS; | ||
| 1099 | } | ||
| 1140 | 1100 | ||
| 1141 | return RESULT_SUCCESS; | 1101 | return RESULT_SUCCESS; |
| 1142 | } | 1102 | } |
| @@ -1150,12 +1110,9 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han | |||
| 1150 | LOG_TRACE(Kernel_SVC, "called"); | 1110 | LOG_TRACE(Kernel_SVC, "called"); |
| 1151 | 1111 | ||
| 1152 | // Get the thread from its handle. | 1112 | // Get the thread from its handle. |
| 1153 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1113 | KScopedAutoObject thread = |
| 1154 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); | 1114 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle); |
| 1155 | if (!thread) { | 1115 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 1156 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle); | ||
| 1157 | return ResultInvalidHandle; | ||
| 1158 | } | ||
| 1159 | 1116 | ||
| 1160 | // Get the thread's priority. | 1117 | // Get the thread's priority. |
| 1161 | *out_priority = thread->GetPriority(); | 1118 | *out_priority = thread->GetPriority(); |
| @@ -1167,30 +1124,26 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, H | |||
| 1167 | } | 1124 | } |
| 1168 | 1125 | ||
| 1169 | /// Sets the priority for the specified thread | 1126 | /// Sets the priority for the specified thread |
| 1170 | static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { | 1127 | static ResultCode SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) { |
| 1171 | LOG_TRACE(Kernel_SVC, "called"); | 1128 | // Get the current process. |
| 1129 | KProcess& process = *system.Kernel().CurrentProcess(); | ||
| 1172 | 1130 | ||
| 1173 | // Validate the priority. | 1131 | // Validate the priority. |
| 1174 | if (HighestThreadPriority > priority || priority > LowestThreadPriority) { | 1132 | R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority, |
| 1175 | LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); | 1133 | ResultInvalidPriority); |
| 1176 | return ResultInvalidPriority; | 1134 | R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority); |
| 1177 | } | ||
| 1178 | 1135 | ||
| 1179 | // Get the thread from its handle. | 1136 | // Get the thread from its handle. |
| 1180 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1137 | KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle); |
| 1181 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); | 1138 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 1182 | if (!thread) { | ||
| 1183 | LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle); | ||
| 1184 | return ResultInvalidHandle; | ||
| 1185 | } | ||
| 1186 | 1139 | ||
| 1187 | // Set the thread priority. | 1140 | // Set the thread priority. |
| 1188 | thread->SetBasePriority(priority); | 1141 | thread->SetBasePriority(priority); |
| 1189 | return RESULT_SUCCESS; | 1142 | return RESULT_SUCCESS; |
| 1190 | } | 1143 | } |
| 1191 | 1144 | ||
| 1192 | static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { | 1145 | static ResultCode SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) { |
| 1193 | return SetThreadPriority(system, handle, priority); | 1146 | return SetThreadPriority(system, thread_handle, priority); |
| 1194 | } | 1147 | } |
| 1195 | 1148 | ||
| 1196 | /// Get which CPU core is executing the current thread | 1149 | /// Get which CPU core is executing the current thread |
| @@ -1203,82 +1156,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) { | |||
| 1203 | return GetCurrentProcessorNumber(system); | 1156 | return GetCurrentProcessorNumber(system); |
| 1204 | } | 1157 | } |
| 1205 | 1158 | ||
| 1206 | static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, | 1159 | constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { |
| 1207 | u64 size, u32 permissions) { | 1160 | switch (perm) { |
| 1208 | std::lock_guard lock{HLE::g_hle_lock}; | 1161 | case Svc::MemoryPermission::Read: |
| 1162 | case Svc::MemoryPermission::ReadWrite: | ||
| 1163 | return true; | ||
| 1164 | default: | ||
| 1165 | return false; | ||
| 1166 | } | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1170 | return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, | ||
| 1174 | u64 size, Svc::MemoryPermission map_perm) { | ||
| 1209 | LOG_TRACE(Kernel_SVC, | 1175 | LOG_TRACE(Kernel_SVC, |
| 1210 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", | 1176 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", |
| 1211 | shared_memory_handle, addr, size, permissions); | 1177 | shmem_handle, address, size, map_perm); |
| 1212 | 1178 | ||
| 1213 | if (!Common::Is4KBAligned(addr)) { | 1179 | // Validate the address/size. |
| 1214 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | 1180 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); |
| 1215 | return ResultInvalidAddress; | 1181 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); |
| 1216 | } | 1182 | R_UNLESS(size > 0, ResultInvalidSize); |
| 1183 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 1217 | 1184 | ||
| 1218 | if (size == 0) { | 1185 | // Validate the permission. |
| 1219 | LOG_ERROR(Kernel_SVC, "Size is 0"); | 1186 | R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); |
| 1220 | return ResultInvalidSize; | ||
| 1221 | } | ||
| 1222 | 1187 | ||
| 1223 | if (!Common::Is4KBAligned(size)) { | 1188 | // Get the current process. |
| 1224 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | 1189 | auto& process = *system.Kernel().CurrentProcess(); |
| 1225 | return ResultInvalidSize; | 1190 | auto& page_table = process.PageTable(); |
| 1226 | } | ||
| 1227 | 1191 | ||
| 1228 | if (!IsValidAddressRange(addr, size)) { | 1192 | // Get the shared memory. |
| 1229 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | 1193 | KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); |
| 1230 | addr, size); | 1194 | R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); |
| 1231 | return ResultInvalidCurrentMemory; | ||
| 1232 | } | ||
| 1233 | 1195 | ||
| 1234 | const auto permission_type = static_cast<MemoryPermission>(permissions); | 1196 | // Verify that the mapping is in range. |
| 1235 | if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { | 1197 | R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); |
| 1236 | LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", | ||
| 1237 | permissions); | ||
| 1238 | return ResultInvalidMemoryPermissions; | ||
| 1239 | } | ||
| 1240 | 1198 | ||
| 1241 | auto* const current_process{system.Kernel().CurrentProcess()}; | 1199 | // Add the shared memory to the process. |
| 1242 | auto& page_table{current_process->PageTable()}; | 1200 | R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size)); |
| 1243 | 1201 | ||
| 1244 | if (page_table.IsInvalidRegion(addr, size)) { | 1202 | // Ensure that we clean up the shared memory if we fail to map it. |
| 1245 | LOG_ERROR(Kernel_SVC, | 1203 | auto guard = |
| 1246 | "Addr does not fit within the valid region, addr=0x{:016X}, " | 1204 | SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); }); |
| 1247 | "size=0x{:016X}", | ||
| 1248 | addr, size); | ||
| 1249 | return ResultInvalidMemoryRange; | ||
| 1250 | } | ||
| 1251 | 1205 | ||
| 1252 | if (page_table.IsInsideHeapRegion(addr, size)) { | 1206 | // Map the shared memory. |
| 1253 | LOG_ERROR(Kernel_SVC, | 1207 | R_TRY(shmem->Map(process, address, size, map_perm)); |
| 1254 | "Addr does not fit within the heap region, addr=0x{:016X}, " | ||
| 1255 | "size=0x{:016X}", | ||
| 1256 | addr, size); | ||
| 1257 | return ResultInvalidMemoryRange; | ||
| 1258 | } | ||
| 1259 | 1208 | ||
| 1260 | if (page_table.IsInsideAliasRegion(addr, size)) { | 1209 | // We succeeded. |
| 1261 | LOG_ERROR(Kernel_SVC, | 1210 | guard.Cancel(); |
| 1262 | "Address does not fit within the map region, addr=0x{:016X}, " | 1211 | return RESULT_SUCCESS; |
| 1263 | "size=0x{:016X}", | 1212 | } |
| 1264 | addr, size); | ||
| 1265 | return ResultInvalidMemoryRange; | ||
| 1266 | } | ||
| 1267 | 1213 | ||
| 1268 | auto shared_memory{current_process->GetHandleTable().Get<KSharedMemory>(shared_memory_handle)}; | 1214 | static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, |
| 1269 | if (!shared_memory) { | 1215 | u32 size, Svc::MemoryPermission map_perm) { |
| 1270 | LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", | 1216 | return MapSharedMemory(system, shmem_handle, address, size, map_perm); |
| 1271 | shared_memory_handle); | 1217 | } |
| 1272 | return ResultInvalidHandle; | 1218 | |
| 1273 | } | 1219 | static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, |
| 1220 | u64 size) { | ||
| 1221 | // Validate the address/size. | ||
| 1222 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | ||
| 1223 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 1224 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 1225 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 1226 | |||
| 1227 | // Get the current process. | ||
| 1228 | auto& process = *system.Kernel().CurrentProcess(); | ||
| 1229 | auto& page_table = process.PageTable(); | ||
| 1230 | |||
| 1231 | // Get the shared memory. | ||
| 1232 | KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); | ||
| 1233 | R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); | ||
| 1274 | 1234 | ||
| 1275 | return shared_memory->Map(*current_process, addr, size, | 1235 | // Verify that the mapping is in range. |
| 1276 | static_cast<KMemoryPermission>(permission_type)); | 1236 | R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); |
| 1237 | |||
| 1238 | // Unmap the shared memory. | ||
| 1239 | R_TRY(shmem->Unmap(process, address, size)); | ||
| 1240 | |||
| 1241 | // Remove the shared memory from the process. | ||
| 1242 | process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); | ||
| 1243 | |||
| 1244 | return RESULT_SUCCESS; | ||
| 1277 | } | 1245 | } |
| 1278 | 1246 | ||
| 1279 | static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, | 1247 | static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, |
| 1280 | u32 size, u32 permissions) { | 1248 | u32 size) { |
| 1281 | return MapSharedMemory(system, shared_memory_handle, addr, size, permissions); | 1249 | return UnmapSharedMemory(system, shmem_handle, address, size); |
| 1282 | } | 1250 | } |
| 1283 | 1251 | ||
| 1284 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, | 1252 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, |
| @@ -1287,8 +1255,8 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add | |||
| 1287 | std::lock_guard lock{HLE::g_hle_lock}; | 1255 | std::lock_guard lock{HLE::g_hle_lock}; |
| 1288 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); | 1256 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); |
| 1289 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1257 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1290 | std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle); | 1258 | KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); |
| 1291 | if (!process) { | 1259 | if (process.IsNull()) { |
| 1292 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | 1260 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", |
| 1293 | process_handle); | 1261 | process_handle); |
| 1294 | return ResultInvalidHandle; | 1262 | return ResultInvalidHandle; |
| @@ -1369,8 +1337,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand | |||
| 1369 | } | 1337 | } |
| 1370 | 1338 | ||
| 1371 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1339 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1372 | auto process = handle_table.Get<Process>(process_handle); | 1340 | KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); |
| 1373 | if (!process) { | 1341 | if (process.IsNull()) { |
| 1374 | LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", | 1342 | LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", |
| 1375 | process_handle); | 1343 | process_handle); |
| 1376 | return ResultInvalidHandle; | 1344 | return ResultInvalidHandle; |
| @@ -1390,7 +1358,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand | |||
| 1390 | "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " | 1358 | "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " |
| 1391 | "size=0x{:016X}).", | 1359 | "size=0x{:016X}).", |
| 1392 | dst_address, size); | 1360 | dst_address, size); |
| 1393 | return ResultInvalidMemoryRange; | 1361 | return ResultInvalidMemoryRegion; |
| 1394 | } | 1362 | } |
| 1395 | 1363 | ||
| 1396 | return page_table.MapProcessCodeMemory(dst_address, src_address, size); | 1364 | return page_table.MapProcessCodeMemory(dst_address, src_address, size); |
| @@ -1437,8 +1405,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha | |||
| 1437 | } | 1405 | } |
| 1438 | 1406 | ||
| 1439 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1407 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1440 | auto process = handle_table.Get<Process>(process_handle); | 1408 | KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); |
| 1441 | if (!process) { | 1409 | if (process.IsNull()) { |
| 1442 | LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", | 1410 | LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", |
| 1443 | process_handle); | 1411 | process_handle); |
| 1444 | return ResultInvalidHandle; | 1412 | return ResultInvalidHandle; |
| @@ -1458,7 +1426,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha | |||
| 1458 | "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " | 1426 | "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " |
| 1459 | "size=0x{:016X}).", | 1427 | "size=0x{:016X}).", |
| 1460 | dst_address, size); | 1428 | dst_address, size); |
| 1461 | return ResultInvalidMemoryRange; | 1429 | return ResultInvalidMemoryRegion; |
| 1462 | } | 1430 | } |
| 1463 | 1431 | ||
| 1464 | return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); | 1432 | return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); |
| @@ -1483,7 +1451,7 @@ static void ExitProcess32(Core::System& system) { | |||
| 1483 | ExitProcess(system); | 1451 | ExitProcess(system); |
| 1484 | } | 1452 | } |
| 1485 | 1453 | ||
| 1486 | static constexpr bool IsValidCoreId(int32_t core_id) { | 1454 | static constexpr bool IsValidVirtualCoreId(int32_t core_id) { |
| 1487 | return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); | 1455 | return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); |
| 1488 | } | 1456 | } |
| 1489 | 1457 | ||
| @@ -1503,7 +1471,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1503 | } | 1471 | } |
| 1504 | 1472 | ||
| 1505 | // Validate arguments. | 1473 | // Validate arguments. |
| 1506 | if (!IsValidCoreId(core_id)) { | 1474 | if (!IsValidVirtualCoreId(core_id)) { |
| 1507 | LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); | 1475 | LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); |
| 1508 | return ResultInvalidCoreId; | 1476 | return ResultInvalidCoreId; |
| 1509 | } | 1477 | } |
| @@ -1521,35 +1489,42 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1521 | return ResultInvalidPriority; | 1489 | return ResultInvalidPriority; |
| 1522 | } | 1490 | } |
| 1523 | 1491 | ||
| 1492 | // Reserve a new thread from the process resource limit (waiting up to 100ms). | ||
| 1524 | KScopedResourceReservation thread_reservation( | 1493 | KScopedResourceReservation thread_reservation( |
| 1525 | kernel.CurrentProcess(), LimitableResource::Threads, 1, | 1494 | kernel.CurrentProcess(), LimitableResource::Threads, 1, |
| 1526 | system.CoreTiming().GetGlobalTimeNs().count() + 100000000); | 1495 | system.CoreTiming().GetGlobalTimeNs().count() + 100000000); |
| 1527 | if (!thread_reservation.Succeeded()) { | 1496 | if (!thread_reservation.Succeeded()) { |
| 1528 | LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); | 1497 | LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); |
| 1529 | return ResultResourceLimitedExceeded; | 1498 | return ResultLimitReached; |
| 1530 | } | 1499 | } |
| 1531 | 1500 | ||
| 1532 | std::shared_ptr<KThread> thread; | 1501 | // Create the thread. |
| 1533 | { | 1502 | KThread* thread = KThread::Create(kernel); |
| 1534 | KScopedLightLock lk{process.GetStateLock()}; | 1503 | if (!thread) { |
| 1535 | CASCADE_RESULT(thread, | 1504 | LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached."); |
| 1536 | KThread::CreateUserThread(system, ThreadType::User, "", entry_point, | 1505 | return ResultOutOfResource; |
| 1537 | priority, arg, core_id, stack_bottom, &process)); | ||
| 1538 | } | 1506 | } |
| 1507 | SCOPE_EXIT({ thread->Close(); }); | ||
| 1539 | 1508 | ||
| 1540 | const auto new_thread_handle = process.GetHandleTable().Create(thread); | 1509 | // Initialize the thread. |
| 1541 | if (new_thread_handle.Failed()) { | 1510 | { |
| 1542 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", | 1511 | KScopedLightLock lk{process.GetStateLock()}; |
| 1543 | new_thread_handle.Code().raw); | 1512 | R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom, |
| 1544 | return new_thread_handle.Code(); | 1513 | priority, core_id, &process)); |
| 1545 | } | 1514 | } |
| 1546 | *out_handle = *new_thread_handle; | ||
| 1547 | 1515 | ||
| 1548 | // Set the thread name for debugging purposes. | 1516 | // Set the thread name for debugging purposes. |
| 1549 | thread->SetName( | 1517 | thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle)); |
| 1550 | fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); | 1518 | |
| 1519 | // Commit the thread reservation. | ||
| 1551 | thread_reservation.Commit(); | 1520 | thread_reservation.Commit(); |
| 1552 | 1521 | ||
| 1522 | // Register the new thread. | ||
| 1523 | KThread::Register(kernel, thread); | ||
| 1524 | |||
| 1525 | // Add the thread to the handle table. | ||
| 1526 | R_TRY(process.GetHandleTable().Add(out_handle, thread)); | ||
| 1527 | |||
| 1553 | return RESULT_SUCCESS; | 1528 | return RESULT_SUCCESS; |
| 1554 | } | 1529 | } |
| 1555 | 1530 | ||
| @@ -1563,21 +1538,15 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { | |||
| 1563 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 1538 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 1564 | 1539 | ||
| 1565 | // Get the thread from its handle. | 1540 | // Get the thread from its handle. |
| 1566 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1541 | KScopedAutoObject thread = |
| 1567 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1542 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); |
| 1568 | if (!thread) { | 1543 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 1569 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 1570 | return ResultInvalidHandle; | ||
| 1571 | } | ||
| 1572 | 1544 | ||
| 1573 | // Try to start the thread. | 1545 | // Try to start the thread. |
| 1574 | const auto run_result = thread->Run(); | 1546 | R_TRY(thread->Run()); |
| 1575 | if (run_result.IsError()) { | 1547 | |
| 1576 | LOG_ERROR(Kernel_SVC, | 1548 | // If we succeeded, persist a reference to the thread. |
| 1577 | "Unable to successfuly start thread (thread handle={:08X}, result={})", | 1549 | thread->Open(); |
| 1578 | thread_handle, run_result.raw); | ||
| 1579 | return run_result; | ||
| 1580 | } | ||
| 1581 | 1550 | ||
| 1582 | return RESULT_SUCCESS; | 1551 | return RESULT_SUCCESS; |
| 1583 | } | 1552 | } |
| @@ -1591,7 +1560,7 @@ static void ExitThread(Core::System& system) { | |||
| 1591 | LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); | 1560 | LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); |
| 1592 | 1561 | ||
| 1593 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 1562 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 1594 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); | 1563 | system.GlobalSchedulerContext().RemoveThread(current_thread); |
| 1595 | current_thread->Exit(); | 1564 | current_thread->Exit(); |
| 1596 | } | 1565 | } |
| 1597 | 1566 | ||
| @@ -1824,8 +1793,11 @@ static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) | |||
| 1824 | static ResultCode CloseHandle(Core::System& system, Handle handle) { | 1793 | static ResultCode CloseHandle(Core::System& system, Handle handle) { |
| 1825 | LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); | 1794 | LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); |
| 1826 | 1795 | ||
| 1827 | auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1796 | // Remove the handle. |
| 1828 | return handle_table.Close(handle); | 1797 | R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle), |
| 1798 | ResultInvalidHandle); | ||
| 1799 | |||
| 1800 | return RESULT_SUCCESS; | ||
| 1829 | } | 1801 | } |
| 1830 | 1802 | ||
| 1831 | static ResultCode CloseHandle32(Core::System& system, Handle handle) { | 1803 | static ResultCode CloseHandle32(Core::System& system, Handle handle) { |
| @@ -1841,16 +1813,16 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { | |||
| 1841 | 1813 | ||
| 1842 | // Try to reset as readable event. | 1814 | // Try to reset as readable event. |
| 1843 | { | 1815 | { |
| 1844 | auto readable_event = handle_table.Get<KReadableEvent>(handle); | 1816 | KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle); |
| 1845 | if (readable_event) { | 1817 | if (readable_event.IsNotNull()) { |
| 1846 | return readable_event->Reset(); | 1818 | return readable_event->Reset(); |
| 1847 | } | 1819 | } |
| 1848 | } | 1820 | } |
| 1849 | 1821 | ||
| 1850 | // Try to reset as process. | 1822 | // Try to reset as process. |
| 1851 | { | 1823 | { |
| 1852 | auto process = handle_table.Get<Process>(handle); | 1824 | KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); |
| 1853 | if (process) { | 1825 | if (process.IsNotNull()) { |
| 1854 | return process->Reset(); | 1826 | return process->Reset(); |
| 1855 | } | 1827 | } |
| 1856 | } | 1828 | } |
| @@ -1864,65 +1836,68 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) { | |||
| 1864 | return ResetSignal(system, handle); | 1836 | return ResetSignal(system, handle); |
| 1865 | } | 1837 | } |
| 1866 | 1838 | ||
| 1867 | /// Creates a TransferMemory object | 1839 | static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { |
| 1868 | static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, | 1840 | switch (perm) { |
| 1869 | u32 permissions) { | 1841 | case MemoryPermission::None: |
| 1870 | std::lock_guard lock{HLE::g_hle_lock}; | 1842 | case MemoryPermission::Read: |
| 1871 | LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, | 1843 | case MemoryPermission::ReadWrite: |
| 1872 | permissions); | 1844 | return true; |
| 1873 | 1845 | default: | |
| 1874 | if (!Common::Is4KBAligned(addr)) { | 1846 | return false; |
| 1875 | LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr); | ||
| 1876 | return ResultInvalidAddress; | ||
| 1877 | } | 1847 | } |
| 1848 | } | ||
| 1878 | 1849 | ||
| 1879 | if (!Common::Is4KBAligned(size) || size == 0) { | 1850 | /// Creates a TransferMemory object |
| 1880 | LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size); | 1851 | static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, |
| 1881 | return ResultInvalidAddress; | 1852 | MemoryPermission map_perm) { |
| 1882 | } | 1853 | auto& kernel = system.Kernel(); |
| 1883 | 1854 | ||
| 1884 | if (!IsValidAddressRange(addr, size)) { | 1855 | // Validate the size. |
| 1885 | LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", | 1856 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); |
| 1886 | addr, size); | 1857 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); |
| 1887 | return ResultInvalidCurrentMemory; | 1858 | R_UNLESS(size > 0, ResultInvalidSize); |
| 1888 | } | 1859 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); |
| 1889 | 1860 | ||
| 1890 | const auto perms{static_cast<MemoryPermission>(permissions)}; | 1861 | // Validate the permissions. |
| 1891 | if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) { | 1862 | R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); |
| 1892 | LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", | 1863 | |
| 1893 | permissions); | 1864 | // Get the current process and handle table. |
| 1894 | return ResultInvalidMemoryPermissions; | 1865 | auto& process = *kernel.CurrentProcess(); |
| 1895 | } | 1866 | auto& handle_table = process.GetHandleTable(); |
| 1896 | 1867 | ||
| 1897 | auto& kernel = system.Kernel(); | ||
| 1898 | // Reserve a new transfer memory from the process resource limit. | 1868 | // Reserve a new transfer memory from the process resource limit. |
| 1899 | KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), | 1869 | KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), |
| 1900 | LimitableResource::TransferMemory); | 1870 | LimitableResource::TransferMemory); |
| 1901 | if (!trmem_reservation.Succeeded()) { | 1871 | R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached); |
| 1902 | LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); | ||
| 1903 | return ResultResourceLimitedExceeded; | ||
| 1904 | } | ||
| 1905 | auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, | ||
| 1906 | static_cast<KMemoryPermission>(perms)); | ||
| 1907 | 1872 | ||
| 1908 | if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { | 1873 | // Create the transfer memory. |
| 1909 | return reserve_result; | 1874 | KTransferMemory* trmem = KTransferMemory::Create(kernel); |
| 1910 | } | 1875 | R_UNLESS(trmem != nullptr, ResultOutOfResource); |
| 1911 | 1876 | ||
| 1912 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 1877 | // Ensure the only reference is in the handle table when we're done. |
| 1913 | const auto result{handle_table.Create(std::move(transfer_mem_handle))}; | 1878 | SCOPE_EXIT({ trmem->Close(); }); |
| 1914 | if (result.Failed()) { | 1879 | |
| 1915 | return result.Code(); | 1880 | // Ensure that the region is in range. |
| 1916 | } | 1881 | R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory); |
| 1882 | |||
| 1883 | // Initialize the transfer memory. | ||
| 1884 | R_TRY(trmem->Initialize(address, size, map_perm)); | ||
| 1885 | |||
| 1886 | // Commit the reservation. | ||
| 1917 | trmem_reservation.Commit(); | 1887 | trmem_reservation.Commit(); |
| 1918 | 1888 | ||
| 1919 | *handle = *result; | 1889 | // Register the transfer memory. |
| 1890 | KTransferMemory::Register(kernel, trmem); | ||
| 1891 | |||
| 1892 | // Add the transfer memory to the handle table. | ||
| 1893 | R_TRY(handle_table.Add(out, trmem)); | ||
| 1894 | |||
| 1920 | return RESULT_SUCCESS; | 1895 | return RESULT_SUCCESS; |
| 1921 | } | 1896 | } |
| 1922 | 1897 | ||
| 1923 | static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, | 1898 | static ResultCode CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size, |
| 1924 | u32 permissions) { | 1899 | MemoryPermission map_perm) { |
| 1925 | return CreateTransferMemory(system, handle, addr, size, permissions); | 1900 | return CreateTransferMemory(system, out, address, size, map_perm); |
| 1926 | } | 1901 | } |
| 1927 | 1902 | ||
| 1928 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, | 1903 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, |
| @@ -1930,19 +1905,12 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, | |||
| 1930 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); | 1905 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); |
| 1931 | 1906 | ||
| 1932 | // Get the thread from its handle. | 1907 | // Get the thread from its handle. |
| 1933 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1908 | KScopedAutoObject thread = |
| 1934 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1909 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); |
| 1935 | if (!thread) { | 1910 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 1936 | LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle); | ||
| 1937 | return ResultInvalidHandle; | ||
| 1938 | } | ||
| 1939 | 1911 | ||
| 1940 | // Get the core mask. | 1912 | // Get the core mask. |
| 1941 | const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); | 1913 | R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); |
| 1942 | if (result.IsError()) { | ||
| 1943 | LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw); | ||
| 1944 | return result; | ||
| 1945 | } | ||
| 1946 | 1914 | ||
| 1947 | return RESULT_SUCCESS; | 1915 | return RESULT_SUCCESS; |
| 1948 | } | 1916 | } |
| @@ -1958,58 +1926,33 @@ static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle | |||
| 1958 | 1926 | ||
| 1959 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, | 1927 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, |
| 1960 | u64 affinity_mask) { | 1928 | u64 affinity_mask) { |
| 1961 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", | ||
| 1962 | thread_handle, core_id, affinity_mask); | ||
| 1963 | |||
| 1964 | const auto& current_process = *system.Kernel().CurrentProcess(); | ||
| 1965 | |||
| 1966 | // Determine the core id/affinity mask. | 1929 | // Determine the core id/affinity mask. |
| 1967 | if (core_id == Svc::IdealCoreUseProcessValue) { | 1930 | if (core_id == IdealCoreUseProcessValue) { |
| 1968 | core_id = current_process.GetIdealCoreId(); | 1931 | core_id = system.Kernel().CurrentProcess()->GetIdealCoreId(); |
| 1969 | affinity_mask = (1ULL << core_id); | 1932 | affinity_mask = (1ULL << core_id); |
| 1970 | } else { | 1933 | } else { |
| 1971 | // Validate the affinity mask. | 1934 | // Validate the affinity mask. |
| 1972 | const u64 process_core_mask = current_process.GetCoreMask(); | 1935 | const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask(); |
| 1973 | if ((affinity_mask | process_core_mask) != process_core_mask) { | 1936 | R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId); |
| 1974 | LOG_ERROR(Kernel_SVC, | 1937 | R_UNLESS(affinity_mask != 0, ResultInvalidCombination); |
| 1975 | "Affinity mask does match the process core mask (affinity mask={:016X}, core " | ||
| 1976 | "mask={:016X})", | ||
| 1977 | affinity_mask, process_core_mask); | ||
| 1978 | return ResultInvalidCoreId; | ||
| 1979 | } | ||
| 1980 | if (affinity_mask == 0) { | ||
| 1981 | LOG_ERROR(Kernel_SVC, "Affinity mask is zero."); | ||
| 1982 | return ResultInvalidCombination; | ||
| 1983 | } | ||
| 1984 | 1938 | ||
| 1985 | // Validate the core id. | 1939 | // Validate the core id. |
| 1986 | if (IsValidCoreId(core_id)) { | 1940 | if (IsValidVirtualCoreId(core_id)) { |
| 1987 | if (((1ULL << core_id) & affinity_mask) == 0) { | 1941 | R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination); |
| 1988 | LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); | ||
| 1989 | return ResultInvalidCombination; | ||
| 1990 | } | ||
| 1991 | } else { | 1942 | } else { |
| 1992 | if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { | 1943 | R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare, |
| 1993 | LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); | 1944 | ResultInvalidCoreId); |
| 1994 | return ResultInvalidCoreId; | ||
| 1995 | } | ||
| 1996 | } | 1945 | } |
| 1997 | } | 1946 | } |
| 1998 | 1947 | ||
| 1999 | // Get the thread from its handle. | 1948 | // Get the thread from its handle. |
| 2000 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1949 | KScopedAutoObject thread = |
| 2001 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1950 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); |
| 2002 | if (!thread) { | 1951 | R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); |
| 2003 | LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle); | ||
| 2004 | return ResultInvalidHandle; | ||
| 2005 | } | ||
| 2006 | 1952 | ||
| 2007 | // Set the core mask. | 1953 | // Set the core mask. |
| 2008 | const auto set_result = thread->SetCoreMask(core_id, affinity_mask); | 1954 | R_TRY(thread->SetCoreMask(core_id, affinity_mask)); |
| 2009 | if (set_result.IsError()) { | 1955 | |
| 2010 | LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw); | ||
| 2011 | return set_result; | ||
| 2012 | } | ||
| 2013 | return RESULT_SUCCESS; | 1956 | return RESULT_SUCCESS; |
| 2014 | } | 1957 | } |
| 2015 | 1958 | ||
| @@ -2022,27 +1965,12 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle | |||
| 2022 | static ResultCode SignalEvent(Core::System& system, Handle event_handle) { | 1965 | static ResultCode SignalEvent(Core::System& system, Handle event_handle) { |
| 2023 | LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); | 1966 | LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); |
| 2024 | 1967 | ||
| 2025 | auto& kernel = system.Kernel(); | ||
| 2026 | // Get the current handle table. | 1968 | // Get the current handle table. |
| 2027 | const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 1969 | const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 2028 | |||
| 2029 | // Reserve a new event from the process resource limit. | ||
| 2030 | KScopedResourceReservation event_reservation(kernel.CurrentProcess(), | ||
| 2031 | LimitableResource::Events); | ||
| 2032 | if (!event_reservation.Succeeded()) { | ||
| 2033 | LOG_ERROR(Kernel, "Could not reserve a new event"); | ||
| 2034 | return ResultResourceLimitedExceeded; | ||
| 2035 | } | ||
| 2036 | 1970 | ||
| 2037 | // Get the writable event. | 1971 | // Get the writable event. |
| 2038 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); | 1972 | KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle); |
| 2039 | if (!writable_event) { | 1973 | R_UNLESS(writable_event.IsNotNull(), ResultInvalidHandle); |
| 2040 | LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle); | ||
| 2041 | return ResultInvalidHandle; | ||
| 2042 | } | ||
| 2043 | |||
| 2044 | // Commit the successfuly reservation. | ||
| 2045 | event_reservation.Commit(); | ||
| 2046 | 1974 | ||
| 2047 | return writable_event->Signal(); | 1975 | return writable_event->Signal(); |
| 2048 | } | 1976 | } |
| @@ -2059,16 +1987,16 @@ static ResultCode ClearEvent(Core::System& system, Handle event_handle) { | |||
| 2059 | 1987 | ||
| 2060 | // Try to clear the writable event. | 1988 | // Try to clear the writable event. |
| 2061 | { | 1989 | { |
| 2062 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); | 1990 | KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle); |
| 2063 | if (writable_event) { | 1991 | if (writable_event.IsNotNull()) { |
| 2064 | return writable_event->Clear(); | 1992 | return writable_event->Clear(); |
| 2065 | } | 1993 | } |
| 2066 | } | 1994 | } |
| 2067 | 1995 | ||
| 2068 | // Try to clear the readable event. | 1996 | // Try to clear the readable event. |
| 2069 | { | 1997 | { |
| 2070 | auto readable_event = handle_table.Get<KReadableEvent>(event_handle); | 1998 | KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle); |
| 2071 | if (readable_event) { | 1999 | if (readable_event.IsNotNull()) { |
| 2072 | return readable_event->Clear(); | 2000 | return readable_event->Clear(); |
| 2073 | } | 2001 | } |
| 2074 | } | 2002 | } |
| @@ -2087,34 +2015,40 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o | |||
| 2087 | 2015 | ||
| 2088 | // Get the kernel reference and handle table. | 2016 | // Get the kernel reference and handle table. |
| 2089 | auto& kernel = system.Kernel(); | 2017 | auto& kernel = system.Kernel(); |
| 2090 | HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 2018 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 2019 | |||
| 2020 | // Reserve a new event from the process resource limit | ||
| 2021 | KScopedResourceReservation event_reservation(kernel.CurrentProcess(), | ||
| 2022 | LimitableResource::Events); | ||
| 2023 | R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); | ||
| 2091 | 2024 | ||
| 2092 | // Create a new event. | 2025 | // Create a new event. |
| 2093 | const auto event = KEvent::Create(kernel, "CreateEvent"); | 2026 | KEvent* event = KEvent::Create(kernel); |
| 2094 | if (!event) { | 2027 | R_UNLESS(event != nullptr, ResultOutOfResource); |
| 2095 | LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached."); | ||
| 2096 | return ResultOutOfResource; | ||
| 2097 | } | ||
| 2098 | 2028 | ||
| 2099 | // Initialize the event. | 2029 | // Initialize the event. |
| 2100 | event->Initialize(); | 2030 | event->Initialize("CreateEvent"); |
| 2031 | |||
| 2032 | // Commit the thread reservation. | ||
| 2033 | event_reservation.Commit(); | ||
| 2034 | |||
| 2035 | // Ensure that we clean up the event (and its only references are handle table) on function end. | ||
| 2036 | SCOPE_EXIT({ | ||
| 2037 | event->GetWritableEvent().Close(); | ||
| 2038 | event->GetReadableEvent().Close(); | ||
| 2039 | }); | ||
| 2040 | |||
| 2041 | // Register the event. | ||
| 2042 | KEvent::Register(kernel, event); | ||
| 2101 | 2043 | ||
| 2102 | // Add the writable event to the handle table. | 2044 | // Add the writable event to the handle table. |
| 2103 | const auto write_create_result = handle_table.Create(event->GetWritableEvent()); | 2045 | R_TRY(handle_table.Add(out_write, std::addressof(event->GetWritableEvent()))); |
| 2104 | if (write_create_result.Failed()) { | ||
| 2105 | return write_create_result.Code(); | ||
| 2106 | } | ||
| 2107 | *out_write = *write_create_result; | ||
| 2108 | 2046 | ||
| 2109 | // Add the writable event to the handle table. | 2047 | // Add the writable event to the handle table. |
| 2110 | auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); }); | 2048 | auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); }); |
| 2111 | 2049 | ||
| 2112 | // Add the readable event to the handle table. | 2050 | // Add the readable event to the handle table. |
| 2113 | const auto read_create_result = handle_table.Create(event->GetReadableEvent()); | 2051 | R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); |
| 2114 | if (read_create_result.Failed()) { | ||
| 2115 | return read_create_result.Code(); | ||
| 2116 | } | ||
| 2117 | *out_read = *read_create_result; | ||
| 2118 | 2052 | ||
| 2119 | // We succeeded. | 2053 | // We succeeded. |
| 2120 | handle_guard.Cancel(); | 2054 | handle_guard.Cancel(); |
| @@ -2134,8 +2068,8 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ | |||
| 2134 | }; | 2068 | }; |
| 2135 | 2069 | ||
| 2136 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 2070 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 2137 | const auto process = handle_table.Get<Process>(process_handle); | 2071 | KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); |
| 2138 | if (!process) { | 2072 | if (process.IsNull()) { |
| 2139 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | 2073 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", |
| 2140 | process_handle); | 2074 | process_handle); |
| 2141 | return ResultInvalidHandle; | 2075 | return ResultInvalidHandle; |
| @@ -2152,83 +2086,86 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ | |||
| 2152 | } | 2086 | } |
| 2153 | 2087 | ||
| 2154 | static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { | 2088 | static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { |
| 2155 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 2156 | LOG_DEBUG(Kernel_SVC, "called"); | 2089 | LOG_DEBUG(Kernel_SVC, "called"); |
| 2157 | 2090 | ||
| 2091 | // Create a new resource limit. | ||
| 2158 | auto& kernel = system.Kernel(); | 2092 | auto& kernel = system.Kernel(); |
| 2159 | auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming()); | 2093 | KResourceLimit* resource_limit = KResourceLimit::Create(kernel); |
| 2094 | R_UNLESS(resource_limit != nullptr, ResultOutOfResource); | ||
| 2160 | 2095 | ||
| 2161 | auto* const current_process = kernel.CurrentProcess(); | 2096 | // Ensure we don't leak a reference to the limit. |
| 2162 | ASSERT(current_process != nullptr); | 2097 | SCOPE_EXIT({ resource_limit->Close(); }); |
| 2163 | 2098 | ||
| 2164 | const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); | 2099 | // Initialize the resource limit. |
| 2165 | if (handle.Failed()) { | 2100 | resource_limit->Initialize(&system.CoreTiming()); |
| 2166 | return handle.Code(); | 2101 | |
| 2167 | } | 2102 | // Register the limit. |
| 2103 | KResourceLimit::Register(kernel, resource_limit); | ||
| 2104 | |||
| 2105 | // Add the limit to the handle table. | ||
| 2106 | R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit)); | ||
| 2168 | 2107 | ||
| 2169 | *out_handle = *handle; | ||
| 2170 | return RESULT_SUCCESS; | 2108 | return RESULT_SUCCESS; |
| 2171 | } | 2109 | } |
| 2172 | 2110 | ||
| 2173 | static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value, | 2111 | static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value, |
| 2174 | Handle resource_limit, u32 resource_type) { | 2112 | Handle resource_limit_handle, |
| 2175 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | 2113 | LimitableResource which) { |
| 2114 | LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, | ||
| 2115 | which); | ||
| 2176 | 2116 | ||
| 2177 | const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, | 2117 | // Validate the resource. |
| 2178 | ResourceLimitValueType::LimitValue); | 2118 | R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); |
| 2179 | if (limit_value.Failed()) { | 2119 | |
| 2180 | return limit_value.Code(); | 2120 | // Get the resource limit. |
| 2181 | } | 2121 | auto& kernel = system.Kernel(); |
| 2122 | KScopedAutoObject resource_limit = | ||
| 2123 | kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); | ||
| 2124 | R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); | ||
| 2125 | |||
| 2126 | // Get the limit value. | ||
| 2127 | *out_limit_value = resource_limit->GetLimitValue(which); | ||
| 2182 | 2128 | ||
| 2183 | *out_value = static_cast<u64>(*limit_value); | ||
| 2184 | return RESULT_SUCCESS; | 2129 | return RESULT_SUCCESS; |
| 2185 | } | 2130 | } |
| 2186 | 2131 | ||
| 2187 | static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value, | 2132 | static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value, |
| 2188 | Handle resource_limit, u32 resource_type) { | 2133 | Handle resource_limit_handle, |
| 2189 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | 2134 | LimitableResource which) { |
| 2135 | LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, | ||
| 2136 | which); | ||
| 2190 | 2137 | ||
| 2191 | const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, | 2138 | // Validate the resource. |
| 2192 | ResourceLimitValueType::CurrentValue); | 2139 | R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); |
| 2193 | if (current_value.Failed()) { | 2140 | |
| 2194 | return current_value.Code(); | 2141 | // Get the resource limit. |
| 2195 | } | 2142 | auto& kernel = system.Kernel(); |
| 2143 | KScopedAutoObject resource_limit = | ||
| 2144 | kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); | ||
| 2145 | R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); | ||
| 2146 | |||
| 2147 | // Get the current value. | ||
| 2148 | *out_current_value = resource_limit->GetCurrentValue(which); | ||
| 2196 | 2149 | ||
| 2197 | *out_value = static_cast<u64>(*current_value); | ||
| 2198 | return RESULT_SUCCESS; | 2150 | return RESULT_SUCCESS; |
| 2199 | } | 2151 | } |
| 2200 | 2152 | ||
| 2201 | static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit, | 2153 | static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, |
| 2202 | u32 resource_type, u64 value) { | 2154 | LimitableResource which, u64 limit_value) { |
| 2203 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, | 2155 | LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}", |
| 2204 | resource_type, value); | 2156 | resource_limit_handle, which, limit_value); |
| 2205 | 2157 | ||
| 2206 | const auto type = static_cast<LimitableResource>(resource_type); | 2158 | // Validate the resource. |
| 2207 | if (!IsValidResourceType(type)) { | 2159 | R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); |
| 2208 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 2209 | return ResultInvalidEnumValue; | ||
| 2210 | } | ||
| 2211 | |||
| 2212 | auto* const current_process = system.Kernel().CurrentProcess(); | ||
| 2213 | ASSERT(current_process != nullptr); | ||
| 2214 | 2160 | ||
| 2215 | auto resource_limit_object = | 2161 | // Get the resource limit. |
| 2216 | current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); | 2162 | auto& kernel = system.Kernel(); |
| 2217 | if (!resource_limit_object) { | 2163 | KScopedAutoObject resource_limit = |
| 2218 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | 2164 | kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); |
| 2219 | resource_limit); | 2165 | R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); |
| 2220 | return ResultInvalidHandle; | ||
| 2221 | } | ||
| 2222 | 2166 | ||
| 2223 | const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value)); | 2167 | // Set the limit value. |
| 2224 | if (set_result.IsError()) { | 2168 | R_TRY(resource_limit->SetLimitValue(which, limit_value)); |
| 2225 | LOG_ERROR(Kernel_SVC, | ||
| 2226 | "Attempted to lower resource limit ({}) for category '{}' below its current " | ||
| 2227 | "value ({})", | ||
| 2228 | resource_limit_object->GetLimitValue(type), resource_type, | ||
| 2229 | resource_limit_object->GetCurrentValue(type)); | ||
| 2230 | return set_result; | ||
| 2231 | } | ||
| 2232 | 2169 | ||
| 2233 | return RESULT_SUCCESS; | 2170 | return RESULT_SUCCESS; |
| 2234 | } | 2171 | } |
| @@ -2351,7 +2288,7 @@ static const FunctionDef SVC_Table_32[] = { | |||
| 2351 | {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, | 2288 | {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, |
| 2352 | {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, | 2289 | {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, |
| 2353 | {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, | 2290 | {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, |
| 2354 | {0x14, nullptr, "UnmapSharedMemory32"}, | 2291 | {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"}, |
| 2355 | {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, | 2292 | {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, |
| 2356 | {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, | 2293 | {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, |
| 2357 | {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, | 2294 | {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, |
| @@ -2546,7 +2483,7 @@ static const FunctionDef SVC_Table_64[] = { | |||
| 2546 | {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, | 2483 | {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, |
| 2547 | {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, | 2484 | {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, |
| 2548 | {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, | 2485 | {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, |
| 2549 | {0x14, nullptr, "UnmapSharedMemory"}, | 2486 | {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"}, |
| 2550 | {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, | 2487 | {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, |
| 2551 | {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, | 2488 | {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, |
| 2552 | {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, | 2489 | {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, |