summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp6
-rw-r--r--src/core/hle/kernel/k_interrupt_manager.cpp34
-rw-r--r--src/core/hle/kernel/k_interrupt_manager.h17
-rw-r--r--src/core/hle/kernel/k_process.cpp12
-rw-r--r--src/core/hle/kernel/k_process.h4
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp8
-rw-r--r--src/core/hle/kernel/k_thread.cpp44
-rw-r--r--src/core/hle/kernel/k_thread.h6
-rw-r--r--src/core/hle/kernel/svc.cpp21
10 files changed, 140 insertions, 14 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 698c4f912..b1a746727 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -187,6 +187,8 @@ add_library(core STATIC
187 hle/kernel/k_event.h 187 hle/kernel/k_event.h
188 hle/kernel/k_handle_table.cpp 188 hle/kernel/k_handle_table.cpp
189 hle/kernel/k_handle_table.h 189 hle/kernel/k_handle_table.h
190 hle/kernel/k_interrupt_manager.cpp
191 hle/kernel/k_interrupt_manager.h
190 hle/kernel/k_light_condition_variable.cpp 192 hle/kernel/k_light_condition_variable.cpp
191 hle/kernel/k_light_condition_variable.h 193 hle/kernel/k_light_condition_variable.h
192 hle/kernel/k_light_lock.cpp 194 hle/kernel/k_light_lock.cpp
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
index 4f4e338e3..baad2c5d6 100644
--- a/src/core/hle/kernel/global_scheduler_context.cpp
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -9,6 +9,7 @@
9#include "core/hle/kernel/global_scheduler_context.h" 9#include "core/hle/kernel/global_scheduler_context.h"
10#include "core/hle/kernel/k_scheduler.h" 10#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/physical_core.h"
12 13
13namespace Kernel { 14namespace Kernel {
14 15
@@ -42,6 +43,11 @@ void GlobalSchedulerContext::PreemptThreads() {
42 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { 43 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
43 const u32 priority = preemption_priorities[core_id]; 44 const u32 priority = preemption_priorities[core_id];
44 kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority); 45 kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority);
46
47 // Signal an interrupt occurred. For core 3, this is a certainty, as preemption will result
48 // in the rotator thread being scheduled. For cores 0-2, this is to simulate or system
49 // interrupts that may have occurred.
50 kernel.PhysicalCore(core_id).Interrupt();
45 } 51 }
46} 52}
47 53
diff --git a/src/core/hle/kernel/k_interrupt_manager.cpp b/src/core/hle/kernel/k_interrupt_manager.cpp
new file mode 100644
index 000000000..e5dd39751
--- /dev/null
+++ b/src/core/hle/kernel/k_interrupt_manager.cpp
@@ -0,0 +1,34 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_interrupt_manager.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_scheduler.h"
8#include "core/hle/kernel/k_thread.h"
9#include "core/hle/kernel/kernel.h"
10
11namespace Kernel::KInterruptManager {
12
13void HandleInterrupt(KernelCore& kernel, s32 core_id) {
14 auto* process = kernel.CurrentProcess();
15 if (!process) {
16 return;
17 }
18
19 auto& scheduler = kernel.Scheduler(core_id);
20 auto& current_thread = *scheduler.GetCurrentThread();
21
22 // If the user disable count is set, we may need to pin the current thread.
23 if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) {
24 KScopedSchedulerLock sl{kernel};
25
26 // Pin the current thread.
27 process->PinCurrentThread(core_id);
28
29 // Set the interrupt flag for the thread.
30 scheduler.GetCurrentThread()->SetInterruptFlag();
31 }
32}
33
34} // namespace Kernel::KInterruptManager
diff --git a/src/core/hle/kernel/k_interrupt_manager.h b/src/core/hle/kernel/k_interrupt_manager.h
new file mode 100644
index 000000000..05924801e
--- /dev/null
+++ b/src/core/hle/kernel/k_interrupt_manager.h
@@ -0,0 +1,17 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9namespace Kernel {
10
11class KernelCore;
12
13namespace KInterruptManager {
14void HandleInterrupt(KernelCore& kernel, s32 core_id);
15}
16
17} // namespace Kernel
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 73f8bc4fe..bf98a51e2 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -220,30 +220,28 @@ bool KProcess::ReleaseUserException(KThread* thread) {
220 } 220 }
221} 221}
222 222
223void KProcess::PinCurrentThread() { 223void KProcess::PinCurrentThread(s32 core_id) {
224 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 224 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
225 225
226 // Get the current thread. 226 // Get the current thread.
227 const s32 core_id = GetCurrentCoreId(kernel); 227 KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread();
228 KThread* cur_thread = GetCurrentThreadPointer(kernel);
229 228
230 // If the thread isn't terminated, pin it. 229 // If the thread isn't terminated, pin it.
231 if (!cur_thread->IsTerminationRequested()) { 230 if (!cur_thread->IsTerminationRequested()) {
232 // Pin it. 231 // Pin it.
233 PinThread(core_id, cur_thread); 232 PinThread(core_id, cur_thread);
234 cur_thread->Pin(); 233 cur_thread->Pin(core_id);
235 234
236 // An update is needed. 235 // An update is needed.
237 KScheduler::SetSchedulerUpdateNeeded(kernel); 236 KScheduler::SetSchedulerUpdateNeeded(kernel);
238 } 237 }
239} 238}
240 239
241void KProcess::UnpinCurrentThread() { 240void KProcess::UnpinCurrentThread(s32 core_id) {
242 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 241 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
243 242
244 // Get the current thread. 243 // Get the current thread.
245 const s32 core_id = GetCurrentCoreId(kernel); 244 KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread();
246 KThread* cur_thread = GetCurrentThreadPointer(kernel);
247 245
248 // Unpin it. 246 // Unpin it.
249 cur_thread->Unpin(); 247 cur_thread->Unpin();
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index cb93c7e24..e7c8b5838 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -345,8 +345,8 @@ public:
345 345
346 bool IsSignaled() const override; 346 bool IsSignaled() const override;
347 347
348 void PinCurrentThread(); 348 void PinCurrentThread(s32 core_id);
349 void UnpinCurrentThread(); 349 void UnpinCurrentThread(s32 core_id);
350 void UnpinThread(KThread* thread); 350 void UnpinThread(KThread* thread);
351 351
352 KLightLock& GetStateLock() { 352 KLightLock& GetStateLock() {
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 277201de4..31cec990e 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -15,6 +15,7 @@
15#include "core/core.h" 15#include "core/core.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/cpu_manager.h" 17#include "core/cpu_manager.h"
18#include "core/hle/kernel/k_interrupt_manager.h"
18#include "core/hle/kernel/k_process.h" 19#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_scheduler.h" 20#include "core/hle/kernel/k_scheduler.h"
20#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 21#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
@@ -53,6 +54,13 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
53 } 54 }
54 cores_pending_reschedule &= ~(1ULL << core); 55 cores_pending_reschedule &= ~(1ULL << core);
55 } 56 }
57
58 for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; ++core_id) {
59 if (kernel.PhysicalCore(core_id).IsInterrupted()) {
60 KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_id));
61 }
62 }
63
56 if (must_context_switch) { 64 if (must_context_switch) {
57 auto core_scheduler = kernel.CurrentScheduler(); 65 auto core_scheduler = kernel.CurrentScheduler();
58 kernel.ExitSVCProfile(); 66 kernel.ExitSVCProfile();
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index b8c993748..71e029a3f 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <atomic>
6#include <cinttypes> 7#include <cinttypes>
7#include <optional> 8#include <optional>
8#include <vector> 9#include <vector>
@@ -33,6 +34,7 @@
33#include "core/hle/kernel/svc_results.h" 34#include "core/hle/kernel/svc_results.h"
34#include "core/hle/kernel/time_manager.h" 35#include "core/hle/kernel/time_manager.h"
35#include "core/hle/result.h" 36#include "core/hle/result.h"
37#include "core/memory.h"
36 38
37#ifdef ARCHITECTURE_x86_64 39#ifdef ARCHITECTURE_x86_64
38#include "core/arm/dynarmic/arm_dynarmic_32.h" 40#include "core/arm/dynarmic/arm_dynarmic_32.h"
@@ -63,6 +65,13 @@ namespace Kernel {
63 65
64namespace { 66namespace {
65 67
68struct ThreadLocalRegion {
69 static constexpr std::size_t MessageBufferSize = 0x100;
70 std::array<u32, MessageBufferSize / sizeof(u32)> message_buffer;
71 std::atomic_uint16_t disable_count;
72 std::atomic_uint16_t interrupt_flag;
73};
74
66class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { 75class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait {
67public: 76public:
68 explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) 77 explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_)
@@ -346,7 +355,7 @@ void KThread::StartTermination() {
346 if (parent != nullptr) { 355 if (parent != nullptr) {
347 parent->ReleaseUserException(this); 356 parent->ReleaseUserException(this);
348 if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) { 357 if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) {
349 parent->UnpinCurrentThread(); 358 parent->UnpinCurrentThread(core_id);
350 } 359 }
351 } 360 }
352 361
@@ -372,7 +381,7 @@ void KThread::StartTermination() {
372 this->Close(); 381 this->Close();
373} 382}
374 383
375void KThread::Pin() { 384void KThread::Pin(s32 current_core) {
376 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 385 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
377 386
378 // Set ourselves as pinned. 387 // Set ourselves as pinned.
@@ -389,7 +398,6 @@ void KThread::Pin() {
389 398
390 // Bind ourselves to this core. 399 // Bind ourselves to this core.
391 const s32 active_core = GetActiveCore(); 400 const s32 active_core = GetActiveCore();
392 const s32 current_core = GetCurrentCoreId(kernel);
393 401
394 SetActiveCore(current_core); 402 SetActiveCore(current_core);
395 physical_ideal_core_id = current_core; 403 physical_ideal_core_id = current_core;
@@ -482,6 +490,36 @@ void KThread::Unpin() {
482 } 490 }
483} 491}
484 492
493u16 KThread::GetUserDisableCount() const {
494 if (!IsUserThread()) {
495 // We only emulate TLS for user threads
496 return {};
497 }
498
499 auto& memory = kernel.System().Memory();
500 return memory.Read16(tls_address + offsetof(ThreadLocalRegion, disable_count));
501}
502
503void KThread::SetInterruptFlag() {
504 if (!IsUserThread()) {
505 // We only emulate TLS for user threads
506 return;
507 }
508
509 auto& memory = kernel.System().Memory();
510 memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 1);
511}
512
513void KThread::ClearInterruptFlag() {
514 if (!IsUserThread()) {
515 // We only emulate TLS for user threads
516 return;
517 }
518
519 auto& memory = kernel.System().Memory();
520 memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 0);
521}
522
485ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) { 523ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
486 KScopedSchedulerLock sl{kernel}; 524 KScopedSchedulerLock sl{kernel};
487 525
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index c8a08bd71..83dfde69b 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -307,6 +307,10 @@ public:
307 return parent != nullptr; 307 return parent != nullptr;
308 } 308 }
309 309
310 u16 GetUserDisableCount() const;
311 void SetInterruptFlag();
312 void ClearInterruptFlag();
313
310 [[nodiscard]] KThread* GetLockOwner() const { 314 [[nodiscard]] KThread* GetLockOwner() const {
311 return lock_owner; 315 return lock_owner;
312 } 316 }
@@ -490,7 +494,7 @@ public:
490 this->GetStackParameters().disable_count--; 494 this->GetStackParameters().disable_count--;
491 } 495 }
492 496
493 void Pin(); 497 void Pin(s32 current_core);
494 498
495 void Unpin(); 499 void Unpin();
496 500
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 63e2dff19..250ef9042 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2027,6 +2027,25 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
2027 count); 2027 count);
2028} 2028}
2029 2029
2030static void SynchronizePreemptionState(Core::System& system) {
2031 auto& kernel = system.Kernel();
2032
2033 // Lock the scheduler.
2034 KScopedSchedulerLock sl{kernel};
2035
2036 // If the current thread is pinned, unpin it.
2037 KProcess* cur_process = system.Kernel().CurrentProcess();
2038 const auto core_id = GetCurrentCoreId(kernel);
2039
2040 if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) {
2041 // Clear the current thread's interrupt flag.
2042 GetCurrentThread(kernel).ClearInterruptFlag();
2043
2044 // Unpin the current thread.
2045 cur_process->UnpinCurrentThread(core_id);
2046 }
2047}
2048
2030static ResultCode SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type, 2049static ResultCode SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type,
2031 s32 value, s32 count) { 2050 s32 value, s32 count) {
2032 return SignalToAddress(system, address, signal_type, value, count); 2051 return SignalToAddress(system, address, signal_type, value, count);
@@ -2797,7 +2816,7 @@ static const FunctionDef SVC_Table_64[] = {
2797 {0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"}, 2816 {0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"},
2798 {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"}, 2817 {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"},
2799 {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"}, 2818 {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"},
2800 {0x36, nullptr, "SynchronizePreemptionState"}, 2819 {0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"},
2801 {0x37, nullptr, "Unknown"}, 2820 {0x37, nullptr, "Unknown"},
2802 {0x38, nullptr, "Unknown"}, 2821 {0x38, nullptr, "Unknown"},
2803 {0x39, nullptr, "Unknown"}, 2822 {0x39, nullptr, "Unknown"},