summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2023-03-03 14:42:00 -0800
committerGravatar GitHub2023-03-03 14:42:00 -0800
commit1f98634371838cc94d01613497660937f70ff78b (patch)
tree7760b21a8fe3a407d49b531994784e43fcd87894
parentci: Actually enable LTO on MSVC (#9887) (diff)
parentkernel: be more careful about kernel address keys (diff)
downloadyuzu-1f98634371838cc94d01613497660937f70ff78b.tar.gz
yuzu-1f98634371838cc94d01613497660937f70ff78b.tar.xz
yuzu-1f98634371838cc94d01613497660937f70ff78b.zip
Merge pull request #9855 from liamwhite/kern-16-support
kernel: support for 16.0.0
Diffstat (limited to '')
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp21
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp8
-rw-r--r--src/core/hle/kernel/k_address_arbiter.cpp8
-rw-r--r--src/core/hle/kernel/k_address_space_info.cpp79
-rw-r--r--src/core/hle/kernel/k_condition_variable.cpp50
-rw-r--r--src/core/hle/kernel/k_light_lock.cpp8
-rw-r--r--src/core/hle/kernel/k_process.cpp6
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h11
-rw-r--r--src/core/hle/kernel/k_thread.cpp271
-rw-r--r--src/core/hle/kernel/k_thread.h175
-rw-r--r--src/core/hle/kernel/kernel.cpp93
-rw-r--r--src/core/hle/kernel/kernel.h67
-rw-r--r--src/core/hle/kernel/svc_types.h1
13 files changed, 510 insertions, 288 deletions
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
index c10b7bf30..5b8a248c8 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -14,9 +14,12 @@ namespace Kernel::Board::Nintendo::Nx {
14 14
15namespace impl { 15namespace impl {
16 16
17constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024; 17using namespace Common::Literals;
18constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024; 18
19constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024; 19constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2280 * 4_KiB;
20constexpr const std::size_t RequiredNonSecureSystemMemorySizeViFatal = 0x200 * 4_KiB;
21constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x704 * 4_KiB;
22constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4_KiB;
20 23
21} // namespace impl 24} // namespace impl
22 25
@@ -24,6 +27,9 @@ constexpr const std::size_t RequiredNonSecureSystemMemorySize =
24 impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices + 27 impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
25 impl::RequiredNonSecureSystemMemorySizeMisc; 28 impl::RequiredNonSecureSystemMemorySizeMisc;
26 29
30constexpr const std::size_t RequiredNonSecureSystemMemorySizeWithFatal =
31 RequiredNonSecureSystemMemorySize + impl::RequiredNonSecureSystemMemorySizeViFatal;
32
27namespace { 33namespace {
28 34
29using namespace Common::Literals; 35using namespace Common::Literals;
@@ -120,10 +126,13 @@ size_t KSystemControl::Init::GetAppletPoolSize() {
120 126
121size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() { 127size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
122 // Verify that our minimum is at least as large as Nintendo's. 128 // Verify that our minimum is at least as large as Nintendo's.
123 constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize; 129 constexpr size_t MinimumSizeWithFatal = RequiredNonSecureSystemMemorySizeWithFatal;
124 static_assert(MinimumSize >= 0x29C8000); 130 static_assert(MinimumSizeWithFatal >= 0x2C04000);
131
132 constexpr size_t MinimumSizeWithoutFatal = RequiredNonSecureSystemMemorySize;
133 static_assert(MinimumSizeWithoutFatal >= 0x2A00000);
125 134
126 return MinimumSize; 135 return MinimumSizeWithFatal;
127} 136}
128 137
129namespace { 138namespace {
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index abdb5639f..5e4090e2b 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -33,6 +33,9 @@
33 33
34namespace Kernel::Init { 34namespace Kernel::Init {
35 35
36// For macro convenience.
37using KThreadLockInfo = KThread::LockWithPriorityInheritanceInfo;
38
36#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS 39#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS
37 40
38#define FOREACH_SLAB_TYPE(HANDLER, ...) \ 41#define FOREACH_SLAB_TYPE(HANDLER, ...) \
@@ -54,7 +57,8 @@ namespace Kernel::Init {
54 HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \ 57 HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \
55 HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ 58 HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
56 HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ 59 HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
57 HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) 60 HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \
61 HANDLER(KThreadLockInfo, (SLAB_COUNT(KThread)), ##__VA_ARGS__)
58 62
59namespace { 63namespace {
60 64
@@ -131,7 +135,7 @@ VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAd
131} 135}
132 136
133size_t CalculateSlabHeapGapSize() { 137size_t CalculateSlabHeapGapSize() {
134 constexpr size_t KernelSlabHeapGapSize = 2_MiB - 320_KiB; 138 constexpr size_t KernelSlabHeapGapSize = 2_MiB - 356_KiB;
135 static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax); 139 static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
136 return KernelSlabHeapGapSize; 140 return KernelSlabHeapGapSize;
137} 141}
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp
index a442a3b98..fb86451ea 100644
--- a/src/core/hle/kernel/k_address_arbiter.cpp
+++ b/src/core/hle/kernel/k_address_arbiter.cpp
@@ -29,7 +29,9 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
29 auto& monitor = system.Monitor(); 29 auto& monitor = system.Monitor();
30 const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); 30 const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
31 31
32 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. 32 // NOTE: If scheduler lock is not held here, interrupt disable is required.
33 // KScopedInterruptDisable di;
34
33 // TODO(bunnei): We should call CanAccessAtomic(..) here. 35 // TODO(bunnei): We should call CanAccessAtomic(..) here.
34 36
35 // Load the value from the address. 37 // Load the value from the address.
@@ -59,7 +61,9 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32
59 auto& monitor = system.Monitor(); 61 auto& monitor = system.Monitor();
60 const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); 62 const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
61 63
62 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. 64 // NOTE: If scheduler lock is not held here, interrupt disable is required.
65 // KScopedInterruptDisable di;
66
63 // TODO(bunnei): We should call CanAccessAtomic(..) here. 67 // TODO(bunnei): We should call CanAccessAtomic(..) here.
64 68
65 // Load the value from the address. 69 // Load the value from the address.
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp
index 3e612a207..97972ebae 100644
--- a/src/core/hle/kernel/k_address_space_info.cpp
+++ b/src/core/hle/kernel/k_address_space_info.cpp
@@ -23,86 +23,33 @@ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
23 { .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, }, 23 { .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, },
24 { .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, }, 24 { .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, },
25 { .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, }, 25 { .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
26 { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, }, 26 { .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
27 { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, }, 27 { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
28 { .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, }, 28 { .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
29 { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall }, 29 { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall },
30 { .bit_width = 39, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, }, 30 { .bit_width = 39, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
31 { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, }, 31 { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, },
32 { .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, }, 32 { .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, },
33}}; 33}};
34// clang-format on 34// clang-format on
35 35
36constexpr bool IsAllowedIndexForAddress(std::size_t index) { 36const KAddressSpaceInfo& GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
37 return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Size_Invalid; 37 for (auto& info : AddressSpaceInfos) {
38} 38 if (info.bit_width == width && info.type == type) {
39 39 return info;
40using IndexArray = 40 }
41 std::array<std::size_t, static_cast<std::size_t>(KAddressSpaceInfo::Type::Count)>; 41 }
42 42 UNREACHABLE_MSG("Could not find AddressSpaceInfo");
43constexpr IndexArray AddressSpaceIndices32Bit{
44 0, 1, 0, 2, 0, 3,
45};
46
47constexpr IndexArray AddressSpaceIndices36Bit{
48 4, 5, 4, 6, 4, 7,
49};
50
51constexpr IndexArray AddressSpaceIndices39Bit{
52 9, 8, 8, 10, 12, 11,
53};
54
55constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) {
56 return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
57 type != KAddressSpaceInfo::Type::Stack;
58}
59
60constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) {
61 return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
62 type != KAddressSpaceInfo::Type::Stack;
63}
64
65constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) {
66 return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::MapLarge;
67} 43}
68 44
69} // namespace 45} // namespace
70 46
71u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { 47uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
72 const std::size_t index{static_cast<std::size_t>(type)}; 48 return GetAddressSpaceInfo(width, type).address;
73 switch (width) {
74 case 32:
75 ASSERT(IsAllowed32BitType(type));
76 ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index]));
77 return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address;
78 case 36:
79 ASSERT(IsAllowed36BitType(type));
80 ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index]));
81 return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address;
82 case 39:
83 ASSERT(IsAllowed39BitType(type));
84 ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index]));
85 return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address;
86 }
87 ASSERT(false);
88 return 0;
89} 49}
90 50
91std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { 51size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
92 const std::size_t index{static_cast<std::size_t>(type)}; 52 return GetAddressSpaceInfo(width, type).size;
93 switch (width) {
94 case 32:
95 ASSERT(IsAllowed32BitType(type));
96 return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size;
97 case 36:
98 ASSERT(IsAllowed36BitType(type));
99 return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size;
100 case 39:
101 ASSERT(IsAllowed39BitType(type));
102 return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size;
103 }
104 ASSERT(false);
105 return 0;
106} 53}
107 54
108} // namespace Kernel 55} // namespace Kernel
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index 3f0be1c3f..f40cf92b1 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -111,36 +111,36 @@ Result KConditionVariable::SignalToAddress(VAddr addr) {
111 KScopedSchedulerLock sl(kernel); 111 KScopedSchedulerLock sl(kernel);
112 112
113 // Remove waiter thread. 113 // Remove waiter thread.
114 s32 num_waiters{}; 114 bool has_waiters{};
115 KThread* next_owner_thread = 115 KThread* const next_owner_thread =
116 owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); 116 owner_thread->RemoveUserWaiterByKey(std::addressof(has_waiters), addr);
117 117
118 // Determine the next tag. 118 // Determine the next tag.
119 u32 next_value{}; 119 u32 next_value{};
120 if (next_owner_thread != nullptr) { 120 if (next_owner_thread != nullptr) {
121 next_value = next_owner_thread->GetAddressKeyValue(); 121 next_value = next_owner_thread->GetAddressKeyValue();
122 if (num_waiters > 1) { 122 if (has_waiters) {
123 next_value |= Svc::HandleWaitMask; 123 next_value |= Svc::HandleWaitMask;
124 } 124 }
125 }
125 126
126 // Write the value to userspace. 127 // Synchronize memory before proceeding.
127 Result result{ResultSuccess}; 128 std::atomic_thread_fence(std::memory_order_seq_cst);
128 if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
129 result = ResultSuccess;
130 } else {
131 result = ResultInvalidCurrentMemory;
132 }
133 129
134 // Signal the next owner thread. 130 // Write the value to userspace.
135 next_owner_thread->EndWait(result); 131 Result result{ResultSuccess};
136 return result; 132 if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
133 result = ResultSuccess;
137 } else { 134 } else {
138 // Just write the value to userspace. 135 result = ResultInvalidCurrentMemory;
139 R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)), 136 }
140 ResultInvalidCurrentMemory);
141 137
142 return ResultSuccess; 138 // If necessary, signal the next owner thread.
139 if (next_owner_thread != nullptr) {
140 next_owner_thread->EndWait(result);
143 } 141 }
142
143 R_RETURN(result);
144 } 144 }
145} 145}
146 146
@@ -198,7 +198,9 @@ void KConditionVariable::SignalImpl(KThread* thread) {
198 u32 prev_tag{}; 198 u32 prev_tag{};
199 bool can_access{}; 199 bool can_access{};
200 { 200 {
201 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. 201 // NOTE: If scheduler lock is not held here, interrupt disable is required.
202 // KScopedInterruptDisable di;
203
202 // TODO(bunnei): We should call CanAccessAtomic(..) here. 204 // TODO(bunnei): We should call CanAccessAtomic(..) here.
203 can_access = true; 205 can_access = true;
204 if (can_access) [[likely]] { 206 if (can_access) [[likely]] {
@@ -245,9 +247,11 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
245 (it->GetConditionVariableKey() == cv_key)) { 247 (it->GetConditionVariableKey() == cv_key)) {
246 KThread* target_thread = std::addressof(*it); 248 KThread* target_thread = std::addressof(*it);
247 249
248 this->SignalImpl(target_thread);
249 it = thread_tree.erase(it); 250 it = thread_tree.erase(it);
250 target_thread->ClearConditionVariable(); 251 target_thread->ClearConditionVariable();
252
253 this->SignalImpl(target_thread);
254
251 ++num_waiters; 255 ++num_waiters;
252 } 256 }
253 257
@@ -277,16 +281,16 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
277 // Update the value and process for the next owner. 281 // Update the value and process for the next owner.
278 { 282 {
279 // Remove waiter thread. 283 // Remove waiter thread.
280 s32 num_waiters{}; 284 bool has_waiters{};
281 KThread* next_owner_thread = 285 KThread* next_owner_thread =
282 cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); 286 cur_thread->RemoveUserWaiterByKey(std::addressof(has_waiters), addr);
283 287
284 // Update for the next owner thread. 288 // Update for the next owner thread.
285 u32 next_value{}; 289 u32 next_value{};
286 if (next_owner_thread != nullptr) { 290 if (next_owner_thread != nullptr) {
287 // Get the next tag value. 291 // Get the next tag value.
288 next_value = next_owner_thread->GetAddressKeyValue(); 292 next_value = next_owner_thread->GetAddressKeyValue();
289 if (num_waiters > 1) { 293 if (has_waiters) {
290 next_value |= Svc::HandleWaitMask; 294 next_value |= Svc::HandleWaitMask;
291 } 295 }
292 296
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index d791acbe3..14cb615da 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -90,15 +90,15 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
90 KScopedSchedulerLock sl(kernel); 90 KScopedSchedulerLock sl(kernel);
91 91
92 // Get the next owner. 92 // Get the next owner.
93 s32 num_waiters; 93 bool has_waiters;
94 KThread* next_owner = owner_thread->RemoveWaiterByKey( 94 KThread* next_owner = owner_thread->RemoveKernelWaiterByKey(
95 std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag))); 95 std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag)));
96 96
97 // Pass the lock to the next owner. 97 // Pass the lock to the next owner.
98 uintptr_t next_tag = 0; 98 uintptr_t next_tag = 0;
99 if (next_owner != nullptr) { 99 if (next_owner != nullptr) {
100 next_tag = 100 next_tag =
101 reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1); 101 reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(has_waiters);
102 102
103 next_owner->EndWait(ResultSuccess); 103 next_owner->EndWait(ResultSuccess);
104 104
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index d9c1a0eb3..d44f6e921 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -156,9 +156,9 @@ bool KProcess::ReleaseUserException(KThread* thread) {
156 exception_thread = nullptr; 156 exception_thread = nullptr;
157 157
158 // Remove waiter thread. 158 // Remove waiter thread.
159 s32 num_waiters{}; 159 bool has_waiters{};
160 if (KThread* next = thread->RemoveWaiterByKey( 160 if (KThread* next = thread->RemoveKernelWaiterByKey(
161 std::addressof(num_waiters), 161 std::addressof(has_waiters),
162 reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); 162 reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
163 next != nullptr) { 163 next != nullptr) {
164 next->EndWait(ResultSuccess); 164 next->EndWait(ResultSuccess);
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 129d60472..13463717f 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -31,22 +31,23 @@ public:
31 } 31 }
32 32
33 if (IsLockedByCurrentThread()) { 33 if (IsLockedByCurrentThread()) {
34 // If we already own the lock, we can just increment the count. 34 // If we already own the lock, the lock count should be > 0.
35 // For debug, ensure this is true.
35 ASSERT(lock_count > 0); 36 ASSERT(lock_count > 0);
36 lock_count++;
37 } else { 37 } else {
38 // Otherwise, we want to disable scheduling and acquire the spinlock. 38 // Otherwise, we want to disable scheduling and acquire the spinlock.
39 SchedulerType::DisableScheduling(kernel); 39 SchedulerType::DisableScheduling(kernel);
40 spin_lock.Lock(); 40 spin_lock.Lock();
41 41
42 // For debug, ensure that our state is valid.
43 ASSERT(lock_count == 0); 42 ASSERT(lock_count == 0);
44 ASSERT(owner_thread == nullptr); 43 ASSERT(owner_thread == nullptr);
45 44
46 // Increment count, take ownership. 45 // Take ownership of the lock.
47 lock_count = 1;
48 owner_thread = GetCurrentThreadPointer(kernel); 46 owner_thread = GetCurrentThreadPointer(kernel);
49 } 47 }
48
49 // Increment the lock count.
50 lock_count++;
50 } 51 }
51 52
52 void Unlock() { 53 void Unlock() {
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 599d05947..8c403f5fd 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -191,7 +191,7 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
191 light_ipc_data = nullptr; 191 light_ipc_data = nullptr;
192 192
193 // We're not waiting for a lock, and we haven't disabled migration. 193 // We're not waiting for a lock, and we haven't disabled migration.
194 lock_owner = nullptr; 194 waiting_lock_info = nullptr;
195 num_core_migration_disables = 0; 195 num_core_migration_disables = 0;
196 196
197 // We have no waiters, but we do have an entrypoint. 197 // We have no waiters, but we do have an entrypoint.
@@ -341,25 +341,39 @@ void KThread::Finalize() {
341 341
342 // Release any waiters. 342 // Release any waiters.
343 { 343 {
344 ASSERT(lock_owner == nullptr); 344 ASSERT(waiting_lock_info == nullptr);
345 KScopedSchedulerLock sl{kernel}; 345 KScopedSchedulerLock sl{kernel};
346 346
347 auto it = waiter_list.begin(); 347 // Check that we have no kernel waiters.
348 while (it != waiter_list.end()) { 348 ASSERT(num_kernel_waiters == 0);
349 // Get the thread.
350 KThread* const waiter = std::addressof(*it);
351 349
352 // The thread shouldn't be a kernel waiter. 350 auto it = held_lock_info_list.begin();
353 ASSERT(!waiter->GetAddressKeyIsKernel()); 351 while (it != held_lock_info_list.end()) {
352 // Get the lock info.
353 auto* const lock_info = std::addressof(*it);
354 354
355 // Clear the lock owner. 355 // The lock shouldn't have a kernel waiter.
356 waiter->SetLockOwner(nullptr); 356 ASSERT(!lock_info->GetIsKernelAddressKey());
357 357
358 // Erase the waiter from our list. 358 // Remove all waiters.
359 it = waiter_list.erase(it); 359 while (lock_info->GetWaiterCount() != 0) {
360 // Get the front waiter.
361 KThread* const waiter = lock_info->GetHighestPriorityWaiter();
360 362
361 // Cancel the thread's wait. 363 // Remove it from the lock.
362 waiter->CancelWait(ResultInvalidState, true); 364 if (lock_info->RemoveWaiter(waiter)) {
365 ASSERT(lock_info->GetWaiterCount() == 0);
366 }
367
368 // Cancel the thread's wait.
369 waiter->CancelWait(ResultInvalidState, true);
370 }
371
372 // Remove the held lock from our list.
373 it = held_lock_info_list.erase(it);
374
375 // Free the lock info.
376 LockWithPriorityInheritanceInfo::Free(kernel, lock_info);
363 } 377 }
364 } 378 }
365 379
@@ -708,6 +722,24 @@ void KThread::SetBasePriority(s32 value) {
708 RestorePriority(kernel, this); 722 RestorePriority(kernel, this);
709} 723}
710 724
725KThread* KThread::GetLockOwner() const {
726 return waiting_lock_info != nullptr ? waiting_lock_info->GetOwner() : nullptr;
727}
728
729void KThread::IncreaseBasePriority(s32 priority_) {
730 ASSERT(Svc::HighestThreadPriority <= priority_ && priority_ <= Svc::LowestThreadPriority);
731 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
732 ASSERT(!this->GetStackParameters().is_pinned);
733
734 // Set our base priority.
735 if (base_priority > priority_) {
736 base_priority = priority_;
737
738 // Perform a priority restoration.
739 RestorePriority(kernel, this);
740 }
741}
742
711void KThread::RequestSuspend(SuspendType type) { 743void KThread::RequestSuspend(SuspendType type) {
712 KScopedSchedulerLock sl{kernel}; 744 KScopedSchedulerLock sl{kernel};
713 745
@@ -891,51 +923,89 @@ Result KThread::GetThreadContext3(std::vector<u8>& out) {
891 R_SUCCEED(); 923 R_SUCCEED();
892} 924}
893 925
894void KThread::AddWaiterImpl(KThread* thread) { 926void KThread::AddHeldLock(LockWithPriorityInheritanceInfo* lock_info) {
895 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 927 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
928
929 // Set ourselves as the lock's owner.
930 lock_info->SetOwner(this);
896 931
897 // Find the right spot to insert the waiter. 932 // Add the lock to our held list.
898 auto it = waiter_list.begin(); 933 held_lock_info_list.push_front(*lock_info);
899 while (it != waiter_list.end()) { 934}
900 if (it->GetPriority() > thread->GetPriority()) { 935
901 break; 936KThread::LockWithPriorityInheritanceInfo* KThread::FindHeldLock(VAddr address_key_,
937 bool is_kernel_address_key_) {
938 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
939
940 // Try to find an existing held lock.
941 for (auto& held_lock : held_lock_info_list) {
942 if (held_lock.GetAddressKey() == address_key_ &&
943 held_lock.GetIsKernelAddressKey() == is_kernel_address_key_) {
944 return std::addressof(held_lock);
902 } 945 }
903 it++;
904 } 946 }
905 947
948 return nullptr;
949}
950
951void KThread::AddWaiterImpl(KThread* thread) {
952 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
953 ASSERT(thread->GetConditionVariableTree() == nullptr);
954
955 // Get the thread's address key.
956 const auto address_key_ = thread->GetAddressKey();
957 const auto is_kernel_address_key_ = thread->GetIsKernelAddressKey();
958
906 // Keep track of how many kernel waiters we have. 959 // Keep track of how many kernel waiters we have.
907 if (thread->GetAddressKeyIsKernel()) { 960 if (is_kernel_address_key_) {
908 ASSERT((num_kernel_waiters++) >= 0); 961 ASSERT((num_kernel_waiters++) >= 0);
909 KScheduler::SetSchedulerUpdateNeeded(kernel); 962 KScheduler::SetSchedulerUpdateNeeded(kernel);
910 } 963 }
911 964
912 // Insert the waiter. 965 // Get the relevant lock info.
913 waiter_list.insert(it, *thread); 966 auto* lock_info = this->FindHeldLock(address_key_, is_kernel_address_key_);
914 thread->SetLockOwner(this); 967 if (lock_info == nullptr) {
968 // Create a new lock for the address key.
969 lock_info =
970 LockWithPriorityInheritanceInfo::Create(kernel, address_key_, is_kernel_address_key_);
971
972 // Add the new lock to our list.
973 this->AddHeldLock(lock_info);
974 }
975
976 // Add the thread as waiter to the lock info.
977 lock_info->AddWaiter(thread);
915} 978}
916 979
917void KThread::RemoveWaiterImpl(KThread* thread) { 980void KThread::RemoveWaiterImpl(KThread* thread) {
918 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 981 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
919 982
920 // Keep track of how many kernel waiters we have. 983 // Keep track of how many kernel waiters we have.
921 if (thread->GetAddressKeyIsKernel()) { 984 if (thread->GetIsKernelAddressKey()) {
922 ASSERT((num_kernel_waiters--) > 0); 985 ASSERT((num_kernel_waiters--) > 0);
923 KScheduler::SetSchedulerUpdateNeeded(kernel); 986 KScheduler::SetSchedulerUpdateNeeded(kernel);
924 } 987 }
925 988
989 // Get the info for the lock the thread is waiting on.
990 auto* lock_info = thread->GetWaitingLockInfo();
991 ASSERT(lock_info->GetOwner() == this);
992
926 // Remove the waiter. 993 // Remove the waiter.
927 waiter_list.erase(waiter_list.iterator_to(*thread)); 994 if (lock_info->RemoveWaiter(thread)) {
928 thread->SetLockOwner(nullptr); 995 held_lock_info_list.erase(held_lock_info_list.iterator_to(*lock_info));
996 LockWithPriorityInheritanceInfo::Free(kernel, lock_info);
997 }
929} 998}
930 999
931void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) { 1000void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
932 ASSERT(kernel_ctx.GlobalSchedulerContext().IsLocked()); 1001 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
933 1002
934 while (true) { 1003 while (thread != nullptr) {
935 // We want to inherit priority where possible. 1004 // We want to inherit priority where possible.
936 s32 new_priority = thread->GetBasePriority(); 1005 s32 new_priority = thread->GetBasePriority();
937 if (thread->HasWaiters()) { 1006 for (const auto& held_lock : thread->held_lock_info_list) {
938 new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority()); 1007 new_priority =
1008 std::min(new_priority, held_lock.GetHighestPriorityWaiter()->GetPriority());
939 } 1009 }
940 1010
941 // If the priority we would inherit is not different from ours, don't do anything. 1011 // If the priority we would inherit is not different from ours, don't do anything.
@@ -943,9 +1013,18 @@ void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) {
943 return; 1013 return;
944 } 1014 }
945 1015
1016 // Get the owner of whatever lock this thread is waiting on.
1017 KThread* const lock_owner = thread->GetLockOwner();
1018
1019 // If the thread is waiting on some lock, remove it as a waiter to prevent violating red
1020 // black tree invariants.
1021 if (lock_owner != nullptr) {
1022 lock_owner->RemoveWaiterImpl(thread);
1023 }
1024
946 // Ensure we don't violate condition variable red black tree invariants. 1025 // Ensure we don't violate condition variable red black tree invariants.
947 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { 1026 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
948 BeforeUpdatePriority(kernel_ctx, cv_tree, thread); 1027 BeforeUpdatePriority(kernel, cv_tree, thread);
949 } 1028 }
950 1029
951 // Change the priority. 1030 // Change the priority.
@@ -954,73 +1033,99 @@ void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) {
954 1033
955 // Restore the condition variable, if relevant. 1034 // Restore the condition variable, if relevant.
956 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { 1035 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
957 AfterUpdatePriority(kernel_ctx, cv_tree, thread); 1036 AfterUpdatePriority(kernel, cv_tree, thread);
958 } 1037 }
959 1038
960 // Update the scheduler. 1039 // If we removed the thread from some lock's waiting list, add it back.
961 KScheduler::OnThreadPriorityChanged(kernel_ctx, thread, old_priority); 1040 if (lock_owner != nullptr) {
962 1041 lock_owner->AddWaiterImpl(thread);
963 // Keep the lock owner up to date.
964 KThread* lock_owner = thread->GetLockOwner();
965 if (lock_owner == nullptr) {
966 return;
967 } 1042 }
968 1043
969 // Update the thread in the lock owner's sorted list, and continue inheriting. 1044 // Update the scheduler.
970 lock_owner->RemoveWaiterImpl(thread); 1045 KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority);
971 lock_owner->AddWaiterImpl(thread); 1046
1047 // Continue inheriting priority.
972 thread = lock_owner; 1048 thread = lock_owner;
973 } 1049 }
974} 1050}
975 1051
976void KThread::AddWaiter(KThread* thread) { 1052void KThread::AddWaiter(KThread* thread) {
977 AddWaiterImpl(thread); 1053 this->AddWaiterImpl(thread);
978 RestorePriority(kernel, this); 1054
1055 // If the thread has a higher priority than us, we should inherit.
1056 if (thread->GetPriority() < this->GetPriority()) {
1057 RestorePriority(kernel, this);
1058 }
979} 1059}
980 1060
981void KThread::RemoveWaiter(KThread* thread) { 1061void KThread::RemoveWaiter(KThread* thread) {
982 RemoveWaiterImpl(thread); 1062 this->RemoveWaiterImpl(thread);
983 RestorePriority(kernel, this); 1063
1064 // If our priority is the same as the thread's (and we've inherited), we may need to restore to
1065 // lower priority.
1066 if (this->GetPriority() == thread->GetPriority() &&
1067 this->GetPriority() < this->GetBasePriority()) {
1068 RestorePriority(kernel, this);
1069 }
984} 1070}
985 1071
986KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { 1072KThread* KThread::RemoveWaiterByKey(bool* out_has_waiters, VAddr key, bool is_kernel_address_key_) {
987 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 1073 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
988 1074
989 s32 num_waiters{}; 1075 // Get the relevant lock info.
990 KThread* next_lock_owner{}; 1076 auto* lock_info = this->FindHeldLock(key, is_kernel_address_key_);
991 auto it = waiter_list.begin(); 1077 if (lock_info == nullptr) {
992 while (it != waiter_list.end()) { 1078 *out_has_waiters = false;
993 if (it->GetAddressKey() == key) { 1079 return nullptr;
994 KThread* thread = std::addressof(*it); 1080 }
995
996 // Keep track of how many kernel waiters we have.
997 if (thread->GetAddressKeyIsKernel()) {
998 ASSERT((num_kernel_waiters--) > 0);
999 KScheduler::SetSchedulerUpdateNeeded(kernel);
1000 }
1001 it = waiter_list.erase(it);
1002 1081
1003 // Update the next lock owner. 1082 // Remove the lock info from our held list.
1004 if (next_lock_owner == nullptr) { 1083 held_lock_info_list.erase(held_lock_info_list.iterator_to(*lock_info));
1005 next_lock_owner = thread; 1084
1006 next_lock_owner->SetLockOwner(nullptr); 1085 // Keep track of how many kernel waiters we have.
1007 } else { 1086 if (lock_info->GetIsKernelAddressKey()) {
1008 next_lock_owner->AddWaiterImpl(thread); 1087 num_kernel_waiters -= lock_info->GetWaiterCount();
1009 } 1088 ASSERT(num_kernel_waiters >= 0);
1010 num_waiters++; 1089 KScheduler::SetSchedulerUpdateNeeded(kernel);
1011 } else { 1090 }
1012 it++; 1091
1092 ASSERT(lock_info->GetWaiterCount() > 0);
1093
1094 // Remove the highest priority waiter from the lock to be the next owner.
1095 KThread* next_lock_owner = lock_info->GetHighestPriorityWaiter();
1096 if (lock_info->RemoveWaiter(next_lock_owner)) {
1097 // The new owner was the only waiter.
1098 *out_has_waiters = false;
1099
1100 // Free the lock info, since it has no waiters.
1101 LockWithPriorityInheritanceInfo::Free(kernel, lock_info);
1102 } else {
1103 // There are additional waiters on the lock.
1104 *out_has_waiters = true;
1105
1106 // Add the lock to the new owner's held list.
1107 next_lock_owner->AddHeldLock(lock_info);
1108
1109 // Keep track of any kernel waiters for the new owner.
1110 if (lock_info->GetIsKernelAddressKey()) {
1111 next_lock_owner->num_kernel_waiters += lock_info->GetWaiterCount();
1112 ASSERT(next_lock_owner->num_kernel_waiters > 0);
1113
1114 // NOTE: No need to set scheduler update needed, because we will have already done so
1115 // when removing earlier.
1013 } 1116 }
1014 } 1117 }
1015 1118
1016 // Do priority updates, if we have a next owner. 1119 // If our priority is the same as the next owner's (and we've inherited), we may need to restore
1017 if (next_lock_owner) { 1120 // to lower priority.
1121 if (this->GetPriority() == next_lock_owner->GetPriority() &&
1122 this->GetPriority() < this->GetBasePriority()) {
1018 RestorePriority(kernel, this); 1123 RestorePriority(kernel, this);
1019 RestorePriority(kernel, next_lock_owner); 1124 // NOTE: No need to restore priority on the next lock owner, because it was already the
1125 // highest priority waiter on the lock.
1020 } 1126 }
1021 1127
1022 // Return output. 1128 // Return the next lock owner.
1023 *out_num_waiters = num_waiters;
1024 return next_lock_owner; 1129 return next_lock_owner;
1025} 1130}
1026 1131
@@ -1137,9 +1242,7 @@ ThreadState KThread::RequestTerminate() {
1137 } 1242 }
1138 1243
1139 // Change the thread's priority to be higher than any system thread's. 1244 // Change the thread's priority to be higher than any system thread's.
1140 if (this->GetBasePriority() >= Svc::SystemThreadPriorityHighest) { 1245 this->IncreaseBasePriority(TerminatingThreadPriority);
1141 this->SetBasePriority(TerminatingThreadPriority);
1142 }
1143 1246
1144 // If the thread is runnable, send a termination interrupt to other cores. 1247 // If the thread is runnable, send a termination interrupt to other cores.
1145 if (this->GetState() == ThreadState::Runnable) { 1248 if (this->GetState() == ThreadState::Runnable) {
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index a04de21bc..bd125f5f1 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -339,13 +339,7 @@ public:
339 void SetInterruptFlag(); 339 void SetInterruptFlag();
340 void ClearInterruptFlag(); 340 void ClearInterruptFlag();
341 341
342 [[nodiscard]] KThread* GetLockOwner() const { 342 KThread* GetLockOwner() const;
343 return lock_owner;
344 }
345
346 void SetLockOwner(KThread* owner) {
347 lock_owner = owner;
348 }
349 343
350 [[nodiscard]] const KAffinityMask& GetAffinityMask() const { 344 [[nodiscard]] const KAffinityMask& GetAffinityMask() const {
351 return physical_affinity_mask; 345 return physical_affinity_mask;
@@ -601,7 +595,13 @@ public:
601 595
602 [[nodiscard]] Result GetThreadContext3(std::vector<u8>& out); 596 [[nodiscard]] Result GetThreadContext3(std::vector<u8>& out);
603 597
604 [[nodiscard]] KThread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key); 598 [[nodiscard]] KThread* RemoveUserWaiterByKey(bool* out_has_waiters, VAddr key) {
599 return this->RemoveWaiterByKey(out_has_waiters, key, false);
600 }
601
602 [[nodiscard]] KThread* RemoveKernelWaiterByKey(bool* out_has_waiters, VAddr key) {
603 return this->RemoveWaiterByKey(out_has_waiters, key, true);
604 }
605 605
606 [[nodiscard]] VAddr GetAddressKey() const { 606 [[nodiscard]] VAddr GetAddressKey() const {
607 return address_key; 607 return address_key;
@@ -611,8 +611,8 @@ public:
611 return address_key_value; 611 return address_key_value;
612 } 612 }
613 613
614 [[nodiscard]] bool GetAddressKeyIsKernel() const { 614 [[nodiscard]] bool GetIsKernelAddressKey() const {
615 return address_key_is_kernel; 615 return is_kernel_address_key;
616 } 616 }
617 617
618 //! NB: intentional deviation from official kernel. 618 //! NB: intentional deviation from official kernel.
@@ -621,20 +621,17 @@ public:
621 // to cope with arbitrary host pointers making their way 621 // to cope with arbitrary host pointers making their way
622 // into things. 622 // into things.
623 623
624 void SetUserAddressKey(VAddr key) {
625 address_key = key;
626 address_key_is_kernel = false;
627 }
628
629 void SetUserAddressKey(VAddr key, u32 val) { 624 void SetUserAddressKey(VAddr key, u32 val) {
625 ASSERT(waiting_lock_info == nullptr);
630 address_key = key; 626 address_key = key;
631 address_key_value = val; 627 address_key_value = val;
632 address_key_is_kernel = false; 628 is_kernel_address_key = false;
633 } 629 }
634 630
635 void SetKernelAddressKey(VAddr key) { 631 void SetKernelAddressKey(VAddr key) {
632 ASSERT(waiting_lock_info == nullptr);
636 address_key = key; 633 address_key = key;
637 address_key_is_kernel = true; 634 is_kernel_address_key = true;
638 } 635 }
639 636
640 void ClearWaitQueue() { 637 void ClearWaitQueue() {
@@ -646,10 +643,6 @@ public:
646 void EndWait(Result wait_result_); 643 void EndWait(Result wait_result_);
647 void CancelWait(Result wait_result_, bool cancel_timer_task); 644 void CancelWait(Result wait_result_, bool cancel_timer_task);
648 645
649 [[nodiscard]] bool HasWaiters() const {
650 return !waiter_list.empty();
651 }
652
653 [[nodiscard]] s32 GetNumKernelWaiters() const { 646 [[nodiscard]] s32 GetNumKernelWaiters() const {
654 return num_kernel_waiters; 647 return num_kernel_waiters;
655 } 648 }
@@ -679,6 +672,9 @@ public:
679 } 672 }
680 673
681private: 674private:
675 [[nodiscard]] KThread* RemoveWaiterByKey(bool* out_has_waiters, VAddr key,
676 bool is_kernel_address_key);
677
682 static constexpr size_t PriorityInheritanceCountMax = 10; 678 static constexpr size_t PriorityInheritanceCountMax = 10;
683 union SyncObjectBuffer { 679 union SyncObjectBuffer {
684 std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{}; 680 std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{};
@@ -722,13 +718,14 @@ private:
722 }; 718 };
723 719
724 void AddWaiterImpl(KThread* thread); 720 void AddWaiterImpl(KThread* thread);
725
726 void RemoveWaiterImpl(KThread* thread); 721 void RemoveWaiterImpl(KThread* thread);
722 static void RestorePriority(KernelCore& kernel, KThread* thread);
727 723
728 void StartTermination(); 724 void StartTermination();
729
730 void FinishTermination(); 725 void FinishTermination();
731 726
727 void IncreaseBasePriority(s32 priority);
728
732 [[nodiscard]] Result Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, 729 [[nodiscard]] Result Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
733 s32 prio, s32 virt_core, KProcess* owner, ThreadType type); 730 s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
734 731
@@ -737,8 +734,6 @@ private:
737 s32 core, KProcess* owner, ThreadType type, 734 s32 core, KProcess* owner, ThreadType type,
738 std::function<void()>&& init_func); 735 std::function<void()>&& init_func);
739 736
740 static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
741
742 // For core KThread implementation 737 // For core KThread implementation
743 ThreadContext32 thread_context_32{}; 738 ThreadContext32 thread_context_32{};
744 ThreadContext64 thread_context_64{}; 739 ThreadContext64 thread_context_64{};
@@ -749,6 +744,127 @@ private:
749 &KThread::condvar_arbiter_tree_node>; 744 &KThread::condvar_arbiter_tree_node>;
750 using ConditionVariableThreadTree = 745 using ConditionVariableThreadTree =
751 ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>; 746 ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
747
748private:
749 struct LockWithPriorityInheritanceComparator {
750 struct RedBlackKeyType {
751 s32 m_priority;
752
753 constexpr s32 GetPriority() const {
754 return m_priority;
755 }
756 };
757
758 template <typename T>
759 requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
760 static constexpr int Compare(const T& lhs, const KThread& rhs) {
761 if (lhs.GetPriority() < rhs.GetPriority()) {
762 // Sort by priority.
763 return -1;
764 } else {
765 return 1;
766 }
767 }
768 };
769 static_assert(std::same_as<Common::RedBlackKeyType<LockWithPriorityInheritanceComparator, void>,
770 LockWithPriorityInheritanceComparator::RedBlackKeyType>);
771
772 using LockWithPriorityInheritanceThreadTreeTraits =
773 Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<
774 &KThread::condvar_arbiter_tree_node>;
775 using LockWithPriorityInheritanceThreadTree =
776 ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
777
778public:
779 class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>,
780 public boost::intrusive::list_base_hook<> {
781 public:
782 explicit LockWithPriorityInheritanceInfo(KernelCore&) {}
783
784 static LockWithPriorityInheritanceInfo* Create(KernelCore& kernel, VAddr address_key,
785 bool is_kernel_address_key) {
786 // Create a new lock info.
787 auto* new_lock = LockWithPriorityInheritanceInfo::Allocate(kernel);
788 ASSERT(new_lock != nullptr);
789
790 // Set the new lock's address key.
791 new_lock->m_address_key = address_key;
792 new_lock->m_is_kernel_address_key = is_kernel_address_key;
793
794 return new_lock;
795 }
796
797 void SetOwner(KThread* new_owner) {
798 // Set new owner.
799 m_owner = new_owner;
800 }
801
802 void AddWaiter(KThread* waiter) {
803 // Insert the waiter.
804 m_tree.insert(*waiter);
805 m_waiter_count++;
806
807 waiter->SetWaitingLockInfo(this);
808 }
809
810 [[nodiscard]] bool RemoveWaiter(KThread* waiter) {
811 m_tree.erase(m_tree.iterator_to(*waiter));
812
813 waiter->SetWaitingLockInfo(nullptr);
814
815 return (--m_waiter_count) == 0;
816 }
817
818 KThread* GetHighestPriorityWaiter() {
819 return std::addressof(m_tree.front());
820 }
821 const KThread* GetHighestPriorityWaiter() const {
822 return std::addressof(m_tree.front());
823 }
824
825 LockWithPriorityInheritanceThreadTree& GetThreadTree() {
826 return m_tree;
827 }
828 const LockWithPriorityInheritanceThreadTree& GetThreadTree() const {
829 return m_tree;
830 }
831
832 VAddr GetAddressKey() const {
833 return m_address_key;
834 }
835 bool GetIsKernelAddressKey() const {
836 return m_is_kernel_address_key;
837 }
838 KThread* GetOwner() const {
839 return m_owner;
840 }
841 u32 GetWaiterCount() const {
842 return m_waiter_count;
843 }
844
845 private:
846 LockWithPriorityInheritanceThreadTree m_tree{};
847 VAddr m_address_key{};
848 KThread* m_owner{};
849 u32 m_waiter_count{};
850 bool m_is_kernel_address_key{};
851 };
852
853 void SetWaitingLockInfo(LockWithPriorityInheritanceInfo* lock) {
854 waiting_lock_info = lock;
855 }
856
857 LockWithPriorityInheritanceInfo* GetWaitingLockInfo() {
858 return waiting_lock_info;
859 }
860
861 void AddHeldLock(LockWithPriorityInheritanceInfo* lock_info);
862 LockWithPriorityInheritanceInfo* FindHeldLock(VAddr address_key, bool is_kernel_address_key);
863
864private:
865 using LockWithPriorityInheritanceInfoList =
866 boost::intrusive::list<LockWithPriorityInheritanceInfo>;
867
752 ConditionVariableThreadTree* condvar_tree{}; 868 ConditionVariableThreadTree* condvar_tree{};
753 u64 condvar_key{}; 869 u64 condvar_key{};
754 u64 virtual_affinity_mask{}; 870 u64 virtual_affinity_mask{};
@@ -765,9 +881,9 @@ private:
765 s64 last_scheduled_tick{}; 881 s64 last_scheduled_tick{};
766 std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; 882 std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{};
767 KThreadQueue* wait_queue{}; 883 KThreadQueue* wait_queue{};
768 WaiterList waiter_list{}; 884 LockWithPriorityInheritanceInfoList held_lock_info_list{};
885 LockWithPriorityInheritanceInfo* waiting_lock_info{};
769 WaiterList pinned_waiter_list{}; 886 WaiterList pinned_waiter_list{};
770 KThread* lock_owner{};
771 u32 address_key_value{}; 887 u32 address_key_value{};
772 u32 suspend_request_flags{}; 888 u32 suspend_request_flags{};
773 u32 suspend_allowed_flags{}; 889 u32 suspend_allowed_flags{};
@@ -791,7 +907,7 @@ private:
791 bool debug_attached{}; 907 bool debug_attached{};
792 s8 priority_inheritance_count{}; 908 s8 priority_inheritance_count{};
793 bool resource_limit_release_hint{}; 909 bool resource_limit_release_hint{};
794 bool address_key_is_kernel{}; 910 bool is_kernel_address_key{};
795 StackParameters stack_parameters{}; 911 StackParameters stack_parameters{};
796 Common::SpinLock context_guard{}; 912 Common::SpinLock context_guard{};
797 913
@@ -814,10 +930,12 @@ public:
814 930
815 void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key, 931 void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key,
816 u32 value) { 932 u32 value) {
933 ASSERT(waiting_lock_info == nullptr);
817 condvar_tree = tree; 934 condvar_tree = tree;
818 condvar_key = cv_key; 935 condvar_key = cv_key;
819 address_key = address; 936 address_key = address;
820 address_key_value = value; 937 address_key_value = value;
938 is_kernel_address_key = false;
821 } 939 }
822 940
823 void ClearConditionVariable() { 941 void ClearConditionVariable() {
@@ -829,6 +947,7 @@ public:
829 } 947 }
830 948
831 void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) { 949 void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) {
950 ASSERT(waiting_lock_info == nullptr);
832 condvar_tree = tree; 951 condvar_tree = tree;
833 condvar_key = address; 952 condvar_key = address;
834 } 953 }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index ce94d3605..ef7057ff7 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1318,4 +1318,97 @@ const Core::System& KernelCore::System() const {
1318 return impl->system; 1318 return impl->system;
1319} 1319}
1320 1320
1321struct KernelCore::SlabHeapContainer {
1322 KSlabHeap<KClientSession> client_session;
1323 KSlabHeap<KEvent> event;
1324 KSlabHeap<KLinkedListNode> linked_list_node;
1325 KSlabHeap<KPort> port;
1326 KSlabHeap<KProcess> process;
1327 KSlabHeap<KResourceLimit> resource_limit;
1328 KSlabHeap<KSession> session;
1329 KSlabHeap<KSharedMemory> shared_memory;
1330 KSlabHeap<KSharedMemoryInfo> shared_memory_info;
1331 KSlabHeap<KThread> thread;
1332 KSlabHeap<KTransferMemory> transfer_memory;
1333 KSlabHeap<KCodeMemory> code_memory;
1334 KSlabHeap<KDeviceAddressSpace> device_address_space;
1335 KSlabHeap<KPageBuffer> page_buffer;
1336 KSlabHeap<KThreadLocalPage> thread_local_page;
1337 KSlabHeap<KObjectName> object_name;
1338 KSlabHeap<KSessionRequest> session_request;
1339 KSlabHeap<KSecureSystemResource> secure_system_resource;
1340 KSlabHeap<KThread::LockWithPriorityInheritanceInfo> lock_info;
1341 KSlabHeap<KEventInfo> event_info;
1342 KSlabHeap<KDebug> debug;
1343};
1344
1345template <typename T>
1346KSlabHeap<T>& KernelCore::SlabHeap() {
1347 if constexpr (std::is_same_v<T, KClientSession>) {
1348 return slab_heap_container->client_session;
1349 } else if constexpr (std::is_same_v<T, KEvent>) {
1350 return slab_heap_container->event;
1351 } else if constexpr (std::is_same_v<T, KLinkedListNode>) {
1352 return slab_heap_container->linked_list_node;
1353 } else if constexpr (std::is_same_v<T, KPort>) {
1354 return slab_heap_container->port;
1355 } else if constexpr (std::is_same_v<T, KProcess>) {
1356 return slab_heap_container->process;
1357 } else if constexpr (std::is_same_v<T, KResourceLimit>) {
1358 return slab_heap_container->resource_limit;
1359 } else if constexpr (std::is_same_v<T, KSession>) {
1360 return slab_heap_container->session;
1361 } else if constexpr (std::is_same_v<T, KSharedMemory>) {
1362 return slab_heap_container->shared_memory;
1363 } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) {
1364 return slab_heap_container->shared_memory_info;
1365 } else if constexpr (std::is_same_v<T, KThread>) {
1366 return slab_heap_container->thread;
1367 } else if constexpr (std::is_same_v<T, KTransferMemory>) {
1368 return slab_heap_container->transfer_memory;
1369 } else if constexpr (std::is_same_v<T, KCodeMemory>) {
1370 return slab_heap_container->code_memory;
1371 } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) {
1372 return slab_heap_container->device_address_space;
1373 } else if constexpr (std::is_same_v<T, KPageBuffer>) {
1374 return slab_heap_container->page_buffer;
1375 } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
1376 return slab_heap_container->thread_local_page;
1377 } else if constexpr (std::is_same_v<T, KObjectName>) {
1378 return slab_heap_container->object_name;
1379 } else if constexpr (std::is_same_v<T, KSessionRequest>) {
1380 return slab_heap_container->session_request;
1381 } else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
1382 return slab_heap_container->secure_system_resource;
1383 } else if constexpr (std::is_same_v<T, KThread::LockWithPriorityInheritanceInfo>) {
1384 return slab_heap_container->lock_info;
1385 } else if constexpr (std::is_same_v<T, KEventInfo>) {
1386 return slab_heap_container->event_info;
1387 } else if constexpr (std::is_same_v<T, KDebug>) {
1388 return slab_heap_container->debug;
1389 }
1390}
1391
1392template KSlabHeap<KClientSession>& KernelCore::SlabHeap();
1393template KSlabHeap<KEvent>& KernelCore::SlabHeap();
1394template KSlabHeap<KLinkedListNode>& KernelCore::SlabHeap();
1395template KSlabHeap<KPort>& KernelCore::SlabHeap();
1396template KSlabHeap<KProcess>& KernelCore::SlabHeap();
1397template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap();
1398template KSlabHeap<KSession>& KernelCore::SlabHeap();
1399template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap();
1400template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap();
1401template KSlabHeap<KThread>& KernelCore::SlabHeap();
1402template KSlabHeap<KTransferMemory>& KernelCore::SlabHeap();
1403template KSlabHeap<KCodeMemory>& KernelCore::SlabHeap();
1404template KSlabHeap<KDeviceAddressSpace>& KernelCore::SlabHeap();
1405template KSlabHeap<KPageBuffer>& KernelCore::SlabHeap();
1406template KSlabHeap<KThreadLocalPage>& KernelCore::SlabHeap();
1407template KSlabHeap<KObjectName>& KernelCore::SlabHeap();
1408template KSlabHeap<KSessionRequest>& KernelCore::SlabHeap();
1409template KSlabHeap<KSecureSystemResource>& KernelCore::SlabHeap();
1410template KSlabHeap<KThread::LockWithPriorityInheritanceInfo>& KernelCore::SlabHeap();
1411template KSlabHeap<KEventInfo>& KernelCore::SlabHeap();
1412template KSlabHeap<KDebug>& KernelCore::SlabHeap();
1413
1321} // namespace Kernel 1414} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4449f6949..1b380a07b 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -305,49 +305,7 @@ public:
305 305
306 /// Gets the slab heap for the specified kernel object type. 306 /// Gets the slab heap for the specified kernel object type.
307 template <typename T> 307 template <typename T>
308 KSlabHeap<T>& SlabHeap() { 308 KSlabHeap<T>& SlabHeap();
309 if constexpr (std::is_same_v<T, KClientSession>) {
310 return slab_heap_container->client_session;
311 } else if constexpr (std::is_same_v<T, KEvent>) {
312 return slab_heap_container->event;
313 } else if constexpr (std::is_same_v<T, KLinkedListNode>) {
314 return slab_heap_container->linked_list_node;
315 } else if constexpr (std::is_same_v<T, KPort>) {
316 return slab_heap_container->port;
317 } else if constexpr (std::is_same_v<T, KProcess>) {
318 return slab_heap_container->process;
319 } else if constexpr (std::is_same_v<T, KResourceLimit>) {
320 return slab_heap_container->resource_limit;
321 } else if constexpr (std::is_same_v<T, KSession>) {
322 return slab_heap_container->session;
323 } else if constexpr (std::is_same_v<T, KSharedMemory>) {
324 return slab_heap_container->shared_memory;
325 } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) {
326 return slab_heap_container->shared_memory_info;
327 } else if constexpr (std::is_same_v<T, KThread>) {
328 return slab_heap_container->thread;
329 } else if constexpr (std::is_same_v<T, KTransferMemory>) {
330 return slab_heap_container->transfer_memory;
331 } else if constexpr (std::is_same_v<T, KCodeMemory>) {
332 return slab_heap_container->code_memory;
333 } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) {
334 return slab_heap_container->device_address_space;
335 } else if constexpr (std::is_same_v<T, KPageBuffer>) {
336 return slab_heap_container->page_buffer;
337 } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
338 return slab_heap_container->thread_local_page;
339 } else if constexpr (std::is_same_v<T, KObjectName>) {
340 return slab_heap_container->object_name;
341 } else if constexpr (std::is_same_v<T, KSessionRequest>) {
342 return slab_heap_container->session_request;
343 } else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
344 return slab_heap_container->secure_system_resource;
345 } else if constexpr (std::is_same_v<T, KEventInfo>) {
346 return slab_heap_container->event_info;
347 } else if constexpr (std::is_same_v<T, KDebug>) {
348 return slab_heap_container->debug;
349 }
350 }
351 309
352 /// Gets the current slab resource counts. 310 /// Gets the current slab resource counts.
353 Init::KSlabResourceCounts& SlabResourceCounts(); 311 Init::KSlabResourceCounts& SlabResourceCounts();
@@ -393,28 +351,7 @@ private:
393 351
394private: 352private:
395 /// Helper to encapsulate all slab heaps in a single heap allocated container 353 /// Helper to encapsulate all slab heaps in a single heap allocated container
396 struct SlabHeapContainer { 354 struct SlabHeapContainer;
397 KSlabHeap<KClientSession> client_session;
398 KSlabHeap<KEvent> event;
399 KSlabHeap<KLinkedListNode> linked_list_node;
400 KSlabHeap<KPort> port;
401 KSlabHeap<KProcess> process;
402 KSlabHeap<KResourceLimit> resource_limit;
403 KSlabHeap<KSession> session;
404 KSlabHeap<KSharedMemory> shared_memory;
405 KSlabHeap<KSharedMemoryInfo> shared_memory_info;
406 KSlabHeap<KThread> thread;
407 KSlabHeap<KTransferMemory> transfer_memory;
408 KSlabHeap<KCodeMemory> code_memory;
409 KSlabHeap<KDeviceAddressSpace> device_address_space;
410 KSlabHeap<KPageBuffer> page_buffer;
411 KSlabHeap<KThreadLocalPage> thread_local_page;
412 KSlabHeap<KObjectName> object_name;
413 KSlabHeap<KSessionRequest> session_request;
414 KSlabHeap<KSecureSystemResource> secure_system_resource;
415 KSlabHeap<KEventInfo> event_info;
416 KSlabHeap<KDebug> debug;
417 };
418 355
419 std::unique_ptr<SlabHeapContainer> slab_heap_container; 356 std::unique_ptr<SlabHeapContainer> slab_heap_container;
420}; 357};
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 542c13461..39355d9c4 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -151,6 +151,7 @@ enum class InfoType : u32 {
151 FreeThreadCount = 24, 151 FreeThreadCount = 24,
152 ThreadTickCount = 25, 152 ThreadTickCount = 25,
153 IsSvcPermitted = 26, 153 IsSvcPermitted = 26,
154 IoRegionHint = 27,
154 155
155 MesosphereMeta = 65000, 156 MesosphereMeta = 65000,
156 MesosphereCurrentProcess = 65001, 157 MesosphereCurrentProcess = 65001,