summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/k_thread_local_page.cpp65
-rw-r--r--src/core/hle/kernel/k_thread_local_page.h112
3 files changed, 179 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 43be5e652..6a83d5ceb 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -245,6 +245,8 @@ add_library(core STATIC
245 hle/kernel/k_system_control.h 245 hle/kernel/k_system_control.h
246 hle/kernel/k_thread.cpp 246 hle/kernel/k_thread.cpp
247 hle/kernel/k_thread.h 247 hle/kernel/k_thread.h
248 hle/kernel/k_thread_local_page.cpp
249 hle/kernel/k_thread_local_page.h
248 hle/kernel/k_thread_queue.cpp 250 hle/kernel/k_thread_queue.cpp
249 hle/kernel/k_thread_queue.h 251 hle/kernel/k_thread_queue.h
250 hle/kernel/k_trace.h 252 hle/kernel/k_trace.h
diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp
new file mode 100644
index 000000000..4653c29f6
--- /dev/null
+++ b/src/core/hle/kernel/k_thread_local_page.cpp
@@ -0,0 +1,65 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/scope_exit.h"
6#include "core/hle/kernel/k_memory_block.h"
7#include "core/hle/kernel/k_page_table.h"
8#include "core/hle/kernel/k_process.h"
9#include "core/hle/kernel/k_thread_local_page.h"
10#include "core/hle/kernel/kernel.h"
11
12namespace Kernel {
13
14ResultCode KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
15 // Set that this process owns us.
16 m_owner = process;
17 m_kernel = &kernel;
18
19 // Allocate a new page.
20 KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
21 R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
22 auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); });
23
24 // Map the address in.
25 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
26 R_TRY(m_owner->PageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr,
27 KMemoryState::ThreadLocal,
28 KMemoryPermission::UserReadWrite));
29
30 // We succeeded.
31 page_buf_guard.Cancel();
32
33 return ResultSuccess;
34}
35
36ResultCode KThreadLocalPage::Finalize() {
37 // Get the physical address of the page.
38 const PAddr phys_addr = m_owner->PageTable().GetPhysicalAddr(m_virt_addr);
39 ASSERT(phys_addr);
40
41 // Unmap the page.
42 R_TRY(m_owner->PageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal));
43
44 // Free the page.
45 KPageBuffer::Free(*m_kernel, KPageBuffer::FromPhysicalAddress(m_kernel->System(), phys_addr));
46
47 return ResultSuccess;
48}
49
50VAddr KThreadLocalPage::Reserve() {
51 for (size_t i = 0; i < m_is_region_free.size(); i++) {
52 if (m_is_region_free[i]) {
53 m_is_region_free[i] = false;
54 return this->GetRegionAddress(i);
55 }
56 }
57
58 return 0;
59}
60
61void KThreadLocalPage::Release(VAddr addr) {
62 m_is_region_free[this->GetRegionIndex(addr)] = true;
63}
64
65} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h
new file mode 100644
index 000000000..658c67e94
--- /dev/null
+++ b/src/core/hle/kernel/k_thread_local_page.h
@@ -0,0 +1,112 @@
1// Copyright 2022 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 <algorithm>
8#include <array>
9
10#include "common/alignment.h"
11#include "common/assert.h"
12#include "common/common_types.h"
13#include "common/intrusive_red_black_tree.h"
14#include "core/hle/kernel/k_page_buffer.h"
15#include "core/hle/kernel/memory_types.h"
16#include "core/hle/kernel/slab_helpers.h"
17#include "core/hle/result.h"
18
19namespace Kernel {
20
21class KernelCore;
22class KProcess;
23
24class KThreadLocalPage final : public Common::IntrusiveRedBlackTreeBaseNode<KThreadLocalPage>,
25 public KSlabAllocated<KThreadLocalPage> {
26public:
27 static constexpr size_t RegionsPerPage = PageSize / Svc::ThreadLocalRegionSize;
28 static_assert(RegionsPerPage > 0);
29
30public:
31 constexpr explicit KThreadLocalPage(VAddr addr = {}) : m_virt_addr(addr) {
32 m_is_region_free.fill(true);
33 }
34
35 constexpr VAddr GetAddress() const {
36 return m_virt_addr;
37 }
38
39 ResultCode Initialize(KernelCore& kernel, KProcess* process);
40 ResultCode Finalize();
41
42 VAddr Reserve();
43 void Release(VAddr addr);
44
45 bool IsAllUsed() const {
46 return std::ranges::all_of(m_is_region_free.begin(), m_is_region_free.end(),
47 [](bool is_free) { return !is_free; });
48 }
49
50 bool IsAllFree() const {
51 return std::ranges::all_of(m_is_region_free.begin(), m_is_region_free.end(),
52 [](bool is_free) { return is_free; });
53 }
54
55 bool IsAnyUsed() const {
56 return !this->IsAllFree();
57 }
58
59 bool IsAnyFree() const {
60 return !this->IsAllUsed();
61 }
62
63public:
64 using RedBlackKeyType = VAddr;
65
66 static constexpr RedBlackKeyType GetRedBlackKey(const RedBlackKeyType& v) {
67 return v;
68 }
69 static constexpr RedBlackKeyType GetRedBlackKey(const KThreadLocalPage& v) {
70 return v.GetAddress();
71 }
72
73 template <typename T>
74 requires(std::same_as<T, KThreadLocalPage> ||
75 std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
76 const KThreadLocalPage&
77 rhs) {
78 const VAddr lval = GetRedBlackKey(lhs);
79 const VAddr rval = GetRedBlackKey(rhs);
80
81 if (lval < rval) {
82 return -1;
83 } else if (lval == rval) {
84 return 0;
85 } else {
86 return 1;
87 }
88 }
89
90private:
91 constexpr VAddr GetRegionAddress(size_t i) const {
92 return this->GetAddress() + i * Svc::ThreadLocalRegionSize;
93 }
94
95 constexpr bool Contains(VAddr addr) const {
96 return this->GetAddress() <= addr && addr < this->GetAddress() + PageSize;
97 }
98
99 constexpr size_t GetRegionIndex(VAddr addr) const {
100 ASSERT(Common::IsAligned(addr, Svc::ThreadLocalRegionSize));
101 ASSERT(this->Contains(addr));
102 return (addr - this->GetAddress()) / Svc::ThreadLocalRegionSize;
103 }
104
105private:
106 VAddr m_virt_addr{};
107 KProcess* m_owner{};
108 KernelCore* m_kernel{};
109 std::array<bool, RegionsPerPage> m_is_region_free{};
110};
111
112} // namespace Kernel