early-access version 2359
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 2358. | ||||
| This is the source code for early-access 2359. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
| @@ -187,6 +187,8 @@ add_library(core STATIC | ||||
|     hle/kernel/k_event.h | ||||
|     hle/kernel/k_handle_table.cpp | ||||
|     hle/kernel/k_handle_table.h | ||||
|     hle/kernel/k_interrupt_manager.cpp | ||||
|     hle/kernel/k_interrupt_manager.h | ||||
|     hle/kernel/k_light_condition_variable.cpp | ||||
|     hle/kernel/k_light_condition_variable.h | ||||
|     hle/kernel/k_light_lock.cpp | ||||
|   | ||||
| @@ -45,26 +45,26 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb | ||||
|         // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld | ||||
|         if (parameters.allow_pro_controller) { | ||||
|             controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | ||||
|             controller->Connect(); | ||||
|             controller->Connect(true); | ||||
|         } else if (parameters.allow_dual_joycons) { | ||||
|             controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); | ||||
|             controller->Connect(); | ||||
|             controller->Connect(true); | ||||
|         } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { | ||||
|             // Assign left joycons to even player indices and right joycons to odd player indices. | ||||
|             // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and | ||||
|             // a right Joycon for Player 2 in 2 Player Assist mode. | ||||
|             if (index % 2 == 0) { | ||||
|                 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); | ||||
|                 controller->Connect(); | ||||
|                 controller->Connect(true); | ||||
|             } else { | ||||
|                 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); | ||||
|                 controller->Connect(); | ||||
|                 controller->Connect(true); | ||||
|             } | ||||
|         } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && | ||||
|                    !Settings::values.use_docked_mode.GetValue()) { | ||||
|             // We should *never* reach here under any normal circumstances. | ||||
|             controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | ||||
|             controller->Connect(); | ||||
|             controller->Connect(true); | ||||
|         } else { | ||||
|             UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); | ||||
|         } | ||||
|   | ||||
| @@ -908,8 +908,9 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool EmulatedController::IsControllerSupported() const { | ||||
|     switch (npad_type) { | ||||
| bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { | ||||
|     const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|     switch (type) { | ||||
|     case NpadStyleIndex::ProController: | ||||
|         return supported_style_tag.fullkey; | ||||
|     case NpadStyleIndex::Handheld: | ||||
| @@ -937,9 +938,10 @@ bool EmulatedController::IsControllerSupported() const { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmulatedController::Connect() { | ||||
|     if (!IsControllerSupported()) { | ||||
|         LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type); | ||||
| void EmulatedController::Connect(bool use_temporary_value) { | ||||
|     if (!IsControllerSupported(use_temporary_value)) { | ||||
|         const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|         LOG_ERROR(Service_HID, "Controller type {} is not supported", type); | ||||
|         return; | ||||
|     } | ||||
|     { | ||||
|   | ||||
| @@ -169,8 +169,11 @@ public: | ||||
|      */ | ||||
|     void SetSupportedNpadStyleTag(NpadStyleTag supported_styles); | ||||
|  | ||||
|     /// Sets the connected status to true | ||||
|     void Connect(); | ||||
|     /** | ||||
|      * Sets the connected status to true | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      */ | ||||
|     void Connect(bool use_temporary_value = false); | ||||
|  | ||||
|     /// Sets the connected status to false | ||||
|     void Disconnect(); | ||||
| @@ -336,9 +339,10 @@ private: | ||||
|  | ||||
|     /** | ||||
|      * Checks the current controller type against the supported_style_tag | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      * @return true if the controller is supported | ||||
|      */ | ||||
|     bool IsControllerSupported() const; | ||||
|     bool IsControllerSupported(bool use_temporary_value = false) const; | ||||
|  | ||||
|     /** | ||||
|      * Updates the button status of the controller | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "core/hle/kernel/global_scheduler_context.h" | ||||
| #include "core/hle/kernel/k_scheduler.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/physical_core.h" | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| @@ -42,6 +43,11 @@ void GlobalSchedulerContext::PreemptThreads() { | ||||
|     for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | ||||
|         const u32 priority = preemption_priorities[core_id]; | ||||
|         kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority); | ||||
|  | ||||
|         // Signal an interrupt occurred. For core 3, this is a certainty, as preemption will result | ||||
|         // in the rotator thread being scheduled. For cores 0-2, this is to simulate or system | ||||
|         // interrupts that may have occurred. | ||||
|         kernel.PhysicalCore(core_id).Interrupt(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										34
									
								
								src/core/hle/kernel/k_interrupt_manager.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										34
									
								
								src/core/hle/kernel/k_interrupt_manager.cpp
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // Copyright 2021 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "core/hle/kernel/k_interrupt_manager.h" | ||||
| #include "core/hle/kernel/k_process.h" | ||||
| #include "core/hle/kernel/k_scheduler.h" | ||||
| #include "core/hle/kernel/k_thread.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
|  | ||||
| namespace Kernel::KInterruptManager { | ||||
|  | ||||
| void HandleInterrupt(KernelCore& kernel, s32 core_id) { | ||||
|     auto* process = kernel.CurrentProcess(); | ||||
|     if (!process) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto& scheduler = kernel.Scheduler(core_id); | ||||
|     auto& current_thread = *scheduler.GetCurrentThread(); | ||||
|  | ||||
|     // If the user disable count is set, we may need to pin the current thread. | ||||
|     if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) { | ||||
|         KScopedSchedulerLock sl{kernel}; | ||||
|  | ||||
|         // Pin the current thread. | ||||
|         process->PinCurrentThread(core_id); | ||||
|  | ||||
|         // Set the interrupt flag for the thread. | ||||
|         scheduler.GetCurrentThread()->SetInterruptFlag(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // namespace Kernel::KInterruptManager | ||||
							
								
								
									
										17
									
								
								src/core/hle/kernel/k_interrupt_manager.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								src/core/hle/kernel/k_interrupt_manager.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| // Copyright 2021 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| class KernelCore; | ||||
|  | ||||
| namespace KInterruptManager { | ||||
| void HandleInterrupt(KernelCore& kernel, s32 core_id); | ||||
| } | ||||
|  | ||||
| } // namespace Kernel | ||||
| @@ -220,30 +220,28 @@ bool KProcess::ReleaseUserException(KThread* thread) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void KProcess::PinCurrentThread() { | ||||
| void KProcess::PinCurrentThread(s32 core_id) { | ||||
|     ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||||
|  | ||||
|     // Get the current thread. | ||||
|     const s32 core_id = GetCurrentCoreId(kernel); | ||||
|     KThread* cur_thread = GetCurrentThreadPointer(kernel); | ||||
|     KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread(); | ||||
|  | ||||
|     // If the thread isn't terminated, pin it. | ||||
|     if (!cur_thread->IsTerminationRequested()) { | ||||
|         // Pin it. | ||||
|         PinThread(core_id, cur_thread); | ||||
|         cur_thread->Pin(); | ||||
|         cur_thread->Pin(core_id); | ||||
|  | ||||
|         // An update is needed. | ||||
|         KScheduler::SetSchedulerUpdateNeeded(kernel); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void KProcess::UnpinCurrentThread() { | ||||
| void KProcess::UnpinCurrentThread(s32 core_id) { | ||||
|     ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||||
|  | ||||
|     // Get the current thread. | ||||
|     const s32 core_id = GetCurrentCoreId(kernel); | ||||
|     KThread* cur_thread = GetCurrentThreadPointer(kernel); | ||||
|     KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread(); | ||||
|  | ||||
|     // Unpin it. | ||||
|     cur_thread->Unpin(); | ||||
|   | ||||
| @@ -345,8 +345,8 @@ public: | ||||
|  | ||||
|     bool IsSignaled() const override; | ||||
|  | ||||
|     void PinCurrentThread(); | ||||
|     void UnpinCurrentThread(); | ||||
|     void PinCurrentThread(s32 core_id); | ||||
|     void UnpinCurrentThread(s32 core_id); | ||||
|     void UnpinThread(KThread* thread); | ||||
|  | ||||
|     KLightLock& GetStateLock() { | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/cpu_manager.h" | ||||
| #include "core/hle/kernel/k_interrupt_manager.h" | ||||
| #include "core/hle/kernel/k_process.h" | ||||
| #include "core/hle/kernel/k_scheduler.h" | ||||
| #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||||
| @@ -53,6 +54,13 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul | ||||
|         } | ||||
|         cores_pending_reschedule &= ~(1ULL << core); | ||||
|     } | ||||
|  | ||||
|     for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; ++core_id) { | ||||
|         if (kernel.PhysicalCore(core_id).IsInterrupted()) { | ||||
|             KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_id)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (must_context_switch) { | ||||
|         auto core_scheduler = kernel.CurrentScheduler(); | ||||
|         kernel.ExitSVCProfile(); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <atomic> | ||||
| #include <cinttypes> | ||||
| #include <optional> | ||||
| #include <vector> | ||||
| @@ -33,6 +34,7 @@ | ||||
| #include "core/hle/kernel/svc_results.h" | ||||
| #include "core/hle/kernel/time_manager.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/memory.h" | ||||
|  | ||||
| #ifdef ARCHITECTURE_x86_64 | ||||
| #include "core/arm/dynarmic/arm_dynarmic_32.h" | ||||
| @@ -63,6 +65,13 @@ namespace Kernel { | ||||
|  | ||||
| namespace { | ||||
|  | ||||
| struct ThreadLocalRegion { | ||||
|     static constexpr std::size_t MessageBufferSize = 0x100; | ||||
|     std::array<u32, MessageBufferSize / sizeof(u32)> message_buffer; | ||||
|     std::atomic_uint16_t disable_count; | ||||
|     std::atomic_uint16_t interrupt_flag; | ||||
| }; | ||||
|  | ||||
| class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { | ||||
| public: | ||||
|     explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) | ||||
| @@ -346,7 +355,7 @@ void KThread::StartTermination() { | ||||
|     if (parent != nullptr) { | ||||
|         parent->ReleaseUserException(this); | ||||
|         if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) { | ||||
|             parent->UnpinCurrentThread(); | ||||
|             parent->UnpinCurrentThread(core_id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -372,7 +381,7 @@ void KThread::StartTermination() { | ||||
|     this->Close(); | ||||
| } | ||||
|  | ||||
| void KThread::Pin() { | ||||
| void KThread::Pin(s32 current_core) { | ||||
|     ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||||
|  | ||||
|     // Set ourselves as pinned. | ||||
| @@ -389,7 +398,6 @@ void KThread::Pin() { | ||||
|  | ||||
|         // Bind ourselves to this core. | ||||
|         const s32 active_core = GetActiveCore(); | ||||
|         const s32 current_core = GetCurrentCoreId(kernel); | ||||
|  | ||||
|         SetActiveCore(current_core); | ||||
|         physical_ideal_core_id = current_core; | ||||
| @@ -482,6 +490,36 @@ void KThread::Unpin() { | ||||
|     } | ||||
| } | ||||
|  | ||||
| u16 KThread::GetUserDisableCount() const { | ||||
|     if (!IsUserThread()) { | ||||
|         // We only emulate TLS for user threads | ||||
|         return {}; | ||||
|     } | ||||
|  | ||||
|     auto& memory = kernel.System().Memory(); | ||||
|     return memory.Read16(tls_address + offsetof(ThreadLocalRegion, disable_count)); | ||||
| } | ||||
|  | ||||
| void KThread::SetInterruptFlag() { | ||||
|     if (!IsUserThread()) { | ||||
|         // We only emulate TLS for user threads | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto& memory = kernel.System().Memory(); | ||||
|     memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 1); | ||||
| } | ||||
|  | ||||
| void KThread::ClearInterruptFlag() { | ||||
|     if (!IsUserThread()) { | ||||
|         // We only emulate TLS for user threads | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto& memory = kernel.System().Memory(); | ||||
|     memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 0); | ||||
| } | ||||
|  | ||||
| ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) { | ||||
|     KScopedSchedulerLock sl{kernel}; | ||||
|  | ||||
|   | ||||
| @@ -307,6 +307,10 @@ public: | ||||
|         return parent != nullptr; | ||||
|     } | ||||
|  | ||||
|     u16 GetUserDisableCount() const; | ||||
|     void SetInterruptFlag(); | ||||
|     void ClearInterruptFlag(); | ||||
|  | ||||
|     [[nodiscard]] KThread* GetLockOwner() const { | ||||
|         return lock_owner; | ||||
|     } | ||||
| @@ -490,7 +494,7 @@ public: | ||||
|         this->GetStackParameters().disable_count--; | ||||
|     } | ||||
|  | ||||
|     void Pin(); | ||||
|     void Pin(s32 current_core); | ||||
|  | ||||
|     void Unpin(); | ||||
|  | ||||
|   | ||||
| @@ -2027,6 +2027,25 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign | ||||
|                                                                   count); | ||||
| } | ||||
|  | ||||
| static void SynchronizePreemptionState(Core::System& system) { | ||||
|     auto& kernel = system.Kernel(); | ||||
|  | ||||
|     // Lock the scheduler. | ||||
|     KScopedSchedulerLock sl{kernel}; | ||||
|  | ||||
|     // If the current thread is pinned, unpin it. | ||||
|     KProcess* cur_process = system.Kernel().CurrentProcess(); | ||||
|     const auto core_id = GetCurrentCoreId(kernel); | ||||
|  | ||||
|     if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) { | ||||
|         // Clear the current thread's interrupt flag. | ||||
|         GetCurrentThread(kernel).ClearInterruptFlag(); | ||||
|  | ||||
|         // Unpin the current thread. | ||||
|         cur_process->UnpinCurrentThread(core_id); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static ResultCode SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type, | ||||
|                                     s32 value, s32 count) { | ||||
|     return SignalToAddress(system, address, signal_type, value, count); | ||||
| @@ -2797,7 +2816,7 @@ static const FunctionDef SVC_Table_64[] = { | ||||
|     {0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"}, | ||||
|     {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"}, | ||||
|     {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"}, | ||||
|     {0x36, nullptr, "SynchronizePreemptionState"}, | ||||
|     {0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"}, | ||||
|     {0x37, nullptr, "Unknown"}, | ||||
|     {0x38, nullptr, "Unknown"}, | ||||
|     {0x39, nullptr, "Unknown"}, | ||||
|   | ||||
| @@ -33,7 +33,7 @@ void UpdateController(Core::HID::EmulatedController* controller, | ||||
|     } | ||||
|     controller->SetNpadStyleIndex(controller_type); | ||||
|     if (connected) { | ||||
|         controller->Connect(); | ||||
|         controller->Connect(true); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -599,11 +599,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                     if (is_connected) { | ||||
|                         if (type == Core::HID::NpadStyleIndex::Handheld) { | ||||
|                             emulated_controller_p1->Disconnect(); | ||||
|                             emulated_controller_handheld->Connect(); | ||||
|                             emulated_controller_handheld->Connect(true); | ||||
|                             emulated_controller = emulated_controller_handheld; | ||||
|                         } else { | ||||
|                             emulated_controller_handheld->Disconnect(); | ||||
|                             emulated_controller_p1->Connect(); | ||||
|                             emulated_controller_p1->Connect(true); | ||||
|                             emulated_controller = emulated_controller_p1; | ||||
|                         } | ||||
|                     } | ||||
| @@ -718,7 +718,7 @@ void ConfigureInputPlayer::LoadConfiguration() { | ||||
| void ConfigureInputPlayer::ConnectPlayer(bool connected) { | ||||
|     ui->groupConnectedController->setChecked(connected); | ||||
|     if (connected) { | ||||
|         emulated_controller->Connect(); | ||||
|         emulated_controller->Connect(true); | ||||
|     } else { | ||||
|         emulated_controller->Disconnect(); | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user