diff options
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 171 |
1 files changed, 97 insertions, 74 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 72b5c05f2..1ae530c90 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -401,8 +401,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | |||
| 401 | 401 | ||
| 402 | /// Get which CPU core is executing the current thread | 402 | /// Get which CPU core is executing the current thread |
| 403 | static u32 GetCurrentProcessorNumber() { | 403 | static u32 GetCurrentProcessorNumber() { |
| 404 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, defaulting to processor 0"); | 404 | NGLOG_TRACE(Kernel_SVC, "called"); |
| 405 | return 0; | 405 | return GetCurrentThread()->processor_id; |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, | 408 | static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, |
| @@ -485,22 +485,28 @@ static void ExitProcess() { | |||
| 485 | 485 | ||
| 486 | Core::CurrentProcess()->status = ProcessStatus::Exited; | 486 | Core::CurrentProcess()->status = ProcessStatus::Exited; |
| 487 | 487 | ||
| 488 | // Stop all the process threads that are currently waiting for objects. | 488 | auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) { |
| 489 | auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); | 489 | for (auto& thread : thread_list) { |
| 490 | for (auto& thread : thread_list) { | 490 | if (thread->owner_process != Core::CurrentProcess()) |
| 491 | if (thread->owner_process != Core::CurrentProcess()) | 491 | continue; |
| 492 | continue; | ||
| 493 | 492 | ||
| 494 | if (thread == GetCurrentThread()) | 493 | if (thread == GetCurrentThread()) |
| 495 | continue; | 494 | continue; |
| 496 | 495 | ||
| 497 | // TODO(Subv): When are the other running/ready threads terminated? | 496 | // TODO(Subv): When are the other running/ready threads terminated? |
| 498 | ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || | 497 | ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || |
| 499 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL, | 498 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL, |
| 500 | "Exiting processes with non-waiting threads is currently unimplemented"); | 499 | "Exiting processes with non-waiting threads is currently unimplemented"); |
| 501 | 500 | ||
| 502 | thread->Stop(); | 501 | thread->Stop(); |
| 503 | } | 502 | } |
| 503 | }; | ||
| 504 | |||
| 505 | auto& system = Core::System::GetInstance(); | ||
| 506 | stop_threads(system.Scheduler(0)->GetThreadList()); | ||
| 507 | stop_threads(system.Scheduler(1)->GetThreadList()); | ||
| 508 | stop_threads(system.Scheduler(2)->GetThreadList()); | ||
| 509 | stop_threads(system.Scheduler(3)->GetThreadList()); | ||
| 504 | 510 | ||
| 505 | // Kill the current thread | 511 | // Kill the current thread |
| 506 | GetCurrentThread()->Stop(); | 512 | GetCurrentThread()->Stop(); |
| @@ -530,14 +536,9 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 530 | 536 | ||
| 531 | switch (processor_id) { | 537 | switch (processor_id) { |
| 532 | case THREADPROCESSORID_0: | 538 | case THREADPROCESSORID_0: |
| 533 | break; | ||
| 534 | case THREADPROCESSORID_1: | 539 | case THREADPROCESSORID_1: |
| 535 | case THREADPROCESSORID_2: | 540 | case THREADPROCESSORID_2: |
| 536 | case THREADPROCESSORID_3: | 541 | case THREADPROCESSORID_3: |
| 537 | // TODO(bunnei): Implement support for other processor IDs | ||
| 538 | NGLOG_ERROR(Kernel_SVC, | ||
| 539 | "Newly created thread must run in another thread ({}), unimplemented.", | ||
| 540 | processor_id); | ||
| 541 | break; | 542 | break; |
| 542 | default: | 543 | default: |
| 543 | ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); | 544 | ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); |
| @@ -576,7 +577,7 @@ static ResultCode StartThread(Handle thread_handle) { | |||
| 576 | 577 | ||
| 577 | /// Called when a thread exits | 578 | /// Called when a thread exits |
| 578 | static void ExitThread() { | 579 | static void ExitThread() { |
| 579 | NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC()); | 580 | NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC()); |
| 580 | 581 | ||
| 581 | ExitCurrentThread(); | 582 | ExitCurrentThread(); |
| 582 | Core::System::GetInstance().PrepareReschedule(); | 583 | Core::System::GetInstance().PrepareReschedule(); |
| @@ -588,7 +589,7 @@ static void SleepThread(s64 nanoseconds) { | |||
| 588 | 589 | ||
| 589 | // Don't attempt to yield execution if there are no available threads to run, | 590 | // Don't attempt to yield execution if there are no available threads to run, |
| 590 | // this way we avoid a useless reschedule to the idle thread. | 591 | // this way we avoid a useless reschedule to the idle thread. |
| 591 | if (nanoseconds == 0 && !Core::System::GetInstance().Scheduler().HaveReadyThreads()) | 592 | if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads()) |
| 592 | return; | 593 | return; |
| 593 | 594 | ||
| 594 | // Sleep current thread and check for next thread to schedule | 595 | // Sleep current thread and check for next thread to schedule |
| @@ -624,7 +625,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var | |||
| 624 | 625 | ||
| 625 | // Note: Deliberately don't attempt to inherit the lock owner's priority. | 626 | // Note: Deliberately don't attempt to inherit the lock owner's priority. |
| 626 | 627 | ||
| 627 | Core::System::GetInstance().PrepareReschedule(); | 628 | Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); |
| 628 | return RESULT_SUCCESS; | 629 | return RESULT_SUCCESS; |
| 629 | } | 630 | } |
| 630 | 631 | ||
| @@ -634,53 +635,60 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target | |||
| 634 | condition_variable_addr, target); | 635 | condition_variable_addr, target); |
| 635 | 636 | ||
| 636 | u32 processed = 0; | 637 | u32 processed = 0; |
| 637 | auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); | ||
| 638 | |||
| 639 | for (auto& thread : thread_list) { | ||
| 640 | if (thread->condvar_wait_address != condition_variable_addr) | ||
| 641 | continue; | ||
| 642 | |||
| 643 | // Only process up to 'target' threads, unless 'target' is -1, in which case process | ||
| 644 | // them all. | ||
| 645 | if (target != -1 && processed >= target) | ||
| 646 | break; | ||
| 647 | |||
| 648 | // If the mutex is not yet acquired, acquire it. | ||
| 649 | u32 mutex_val = Memory::Read32(thread->mutex_wait_address); | ||
| 650 | |||
| 651 | if (mutex_val == 0) { | ||
| 652 | // We were able to acquire the mutex, resume this thread. | ||
| 653 | Memory::Write32(thread->mutex_wait_address, thread->wait_handle); | ||
| 654 | ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX); | ||
| 655 | thread->ResumeFromWait(); | ||
| 656 | |||
| 657 | auto lock_owner = thread->lock_owner; | ||
| 658 | if (lock_owner) | ||
| 659 | lock_owner->RemoveMutexWaiter(thread); | ||
| 660 | |||
| 661 | thread->lock_owner = nullptr; | ||
| 662 | thread->mutex_wait_address = 0; | ||
| 663 | thread->condvar_wait_address = 0; | ||
| 664 | thread->wait_handle = 0; | ||
| 665 | } else { | ||
| 666 | // Couldn't acquire the mutex, block the thread. | ||
| 667 | Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); | ||
| 668 | auto owner = g_handle_table.Get<Thread>(owner_handle); | ||
| 669 | ASSERT(owner); | ||
| 670 | ASSERT(thread->status != THREADSTATUS_RUNNING); | ||
| 671 | thread->status = THREADSTATUS_WAIT_MUTEX; | ||
| 672 | thread->wakeup_callback = nullptr; | ||
| 673 | 638 | ||
| 674 | // Signal that the mutex now has a waiting thread. | 639 | auto signal_process_wide_key = [&](size_t core_index) { |
| 675 | Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag); | 640 | const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); |
| 676 | 641 | for (auto& thread : scheduler->GetThreadList()) { | |
| 677 | owner->AddMutexWaiter(thread); | 642 | if (thread->condvar_wait_address != condition_variable_addr) |
| 678 | 643 | continue; | |
| 679 | Core::System::GetInstance().PrepareReschedule(); | 644 | |
| 645 | // Only process up to 'target' threads, unless 'target' is -1, in which case process | ||
| 646 | // them all. | ||
| 647 | if (target != -1 && processed >= target) | ||
| 648 | break; | ||
| 649 | |||
| 650 | // If the mutex is not yet acquired, acquire it. | ||
| 651 | u32 mutex_val = Memory::Read32(thread->mutex_wait_address); | ||
| 652 | |||
| 653 | if (mutex_val == 0) { | ||
| 654 | // We were able to acquire the mutex, resume this thread. | ||
| 655 | Memory::Write32(thread->mutex_wait_address, thread->wait_handle); | ||
| 656 | ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX); | ||
| 657 | thread->ResumeFromWait(); | ||
| 658 | |||
| 659 | auto lock_owner = thread->lock_owner; | ||
| 660 | if (lock_owner) | ||
| 661 | lock_owner->RemoveMutexWaiter(thread); | ||
| 662 | |||
| 663 | thread->lock_owner = nullptr; | ||
| 664 | thread->mutex_wait_address = 0; | ||
| 665 | thread->condvar_wait_address = 0; | ||
| 666 | thread->wait_handle = 0; | ||
| 667 | } else { | ||
| 668 | // Couldn't acquire the mutex, block the thread. | ||
| 669 | Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); | ||
| 670 | auto owner = g_handle_table.Get<Thread>(owner_handle); | ||
| 671 | ASSERT(owner); | ||
| 672 | ASSERT(thread->status != THREADSTATUS_RUNNING); | ||
| 673 | thread->status = THREADSTATUS_WAIT_MUTEX; | ||
| 674 | thread->wakeup_callback = nullptr; | ||
| 675 | |||
| 676 | // Signal that the mutex now has a waiting thread. | ||
| 677 | Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag); | ||
| 678 | |||
| 679 | owner->AddMutexWaiter(thread); | ||
| 680 | |||
| 681 | Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); | ||
| 682 | } | ||
| 683 | |||
| 684 | ++processed; | ||
| 680 | } | 685 | } |
| 686 | }; | ||
| 681 | 687 | ||
| 682 | ++processed; | 688 | signal_process_wide_key(0); |
| 683 | } | 689 | signal_process_wide_key(1); |
| 690 | signal_process_wide_key(2); | ||
| 691 | signal_process_wide_key(3); | ||
| 684 | 692 | ||
| 685 | return RESULT_SUCCESS; | 693 | return RESULT_SUCCESS; |
| 686 | } | 694 | } |
| @@ -718,16 +726,31 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 | |||
| 718 | return RESULT_SUCCESS; | 726 | return RESULT_SUCCESS; |
| 719 | } | 727 | } |
| 720 | 728 | ||
| 721 | static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) { | 729 | static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) { |
| 722 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}", handle); | 730 | NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); |
| 723 | *mask = 0x0; | 731 | |
| 724 | *unknown = 0xf; | 732 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 733 | if (!thread) { | ||
| 734 | return ERR_INVALID_HANDLE; | ||
| 735 | } | ||
| 736 | |||
| 737 | *core = thread->ideal_core; | ||
| 738 | *mask = thread->affinity_mask; | ||
| 739 | |||
| 725 | return RESULT_SUCCESS; | 740 | return RESULT_SUCCESS; |
| 726 | } | 741 | } |
| 727 | 742 | ||
| 728 | static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) { | 743 | static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { |
| 729 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, mask=0x{:08X}, unknown=0x{:X}", | 744 | NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:08X}, core=0x{:X}", thread_handle, |
| 730 | handle, mask, unknown); | 745 | mask, core); |
| 746 | |||
| 747 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); | ||
| 748 | if (!thread) { | ||
| 749 | return ERR_INVALID_HANDLE; | ||
| 750 | } | ||
| 751 | |||
| 752 | thread->ChangeCore(core, mask); | ||
| 753 | |||
| 731 | return RESULT_SUCCESS; | 754 | return RESULT_SUCCESS; |
| 732 | } | 755 | } |
| 733 | 756 | ||