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/errors.h1
-rw-r--r--src/core/hle/kernel/handle_table.h6
-rw-r--r--src/core/hle/kernel/process_capability.cpp253
-rw-r--r--src/core/hle/kernel/process_capability.h209
5 files changed, 468 insertions, 3 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 882c9ab59..a7d5e4431 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -113,6 +113,8 @@ add_library(core STATIC
113 hle/kernel/object.h 113 hle/kernel/object.h
114 hle/kernel/process.cpp 114 hle/kernel/process.cpp
115 hle/kernel/process.h 115 hle/kernel/process.h
116 hle/kernel/process_capability.cpp
117 hle/kernel/process_capability.h
116 hle/kernel/readable_event.cpp 118 hle/kernel/readable_event.cpp
117 hle/kernel/readable_event.h 119 hle/kernel/readable_event.h
118 hle/kernel/resource_limit.cpp 120 hle/kernel/resource_limit.cpp
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 8b58d701d..a3d725866 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -11,6 +11,7 @@ namespace Kernel {
11// Confirmed Switch kernel error codes 11// Confirmed Switch kernel error codes
12 12
13constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; 13constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
14constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
14constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; 15constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
15constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; 16constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
16constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105}; 17constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index 6b7927fd8..89a3bc740 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -43,6 +43,9 @@ enum KernelHandle : Handle {
43 */ 43 */
44class HandleTable final : NonCopyable { 44class HandleTable final : NonCopyable {
45public: 45public:
46 /// This is the maximum limit of handles allowed per process in Horizon
47 static constexpr std::size_t MAX_COUNT = 1024;
48
46 HandleTable(); 49 HandleTable();
47 ~HandleTable(); 50 ~HandleTable();
48 51
@@ -91,9 +94,6 @@ public:
91 void Clear(); 94 void Clear();
92 95
93private: 96private:
94 /// This is the maximum limit of handles allowed per process in Horizon
95 static constexpr std::size_t MAX_COUNT = 1024;
96
97 /// Stores the Object referenced by the handle or null if the slot is empty. 97 /// Stores the Object referenced by the handle or null if the slot is empty.
98 std::array<SharedPtr<Object>, MAX_COUNT> objects; 98 std::array<SharedPtr<Object>, MAX_COUNT> objects;
99 99
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp
new file mode 100644
index 000000000..8d787547b
--- /dev/null
+++ b/src/core/hle/kernel/process_capability.cpp
@@ -0,0 +1,253 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/bit_util.h"
6#include "core/hle/kernel/errors.h"
7#include "core/hle/kernel/handle_table.h"
8#include "core/hle/kernel/process_capability.h"
9#include "core/hle/kernel/vm_manager.h"
10
11namespace Kernel {
12namespace {
13
14// clang-format off
15
16// Shift offsets for kernel capability types.
17enum : u32 {
18 CapabilityOffset_PriorityAndCoreNum = 3,
19 CapabilityOffset_Syscall = 4,
20 CapabilityOffset_MapPhysical = 6,
21 CapabilityOffset_MapIO = 7,
22 CapabilityOffset_Interrupt = 11,
23 CapabilityOffset_ProgramType = 13,
24 CapabilityOffset_KernelVersion = 14,
25 CapabilityOffset_HandleTableSize = 15,
26 CapabilityOffset_Debug = 16,
27};
28
29// Combined mask of all parameters that may be initialized only once.
30constexpr u32 InitializeOnceMask = (1U << CapabilityOffset_PriorityAndCoreNum) |
31 (1U << CapabilityOffset_ProgramType) |
32 (1U << CapabilityOffset_KernelVersion) |
33 (1U << CapabilityOffset_HandleTableSize) |
34 (1U << CapabilityOffset_Debug);
35
36// Packed kernel version indicating 10.4.0
37constexpr u32 PackedKernelVersion = 0x520000;
38
39// Indicates possible types of capabilities that can be specified.
40enum class CapabilityType : u32 {
41 Unset = 0U,
42 PriorityAndCoreNum = (1U << CapabilityOffset_PriorityAndCoreNum) - 1,
43 Syscall = (1U << CapabilityOffset_Syscall) - 1,
44 MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1,
45 MapIO = (1U << CapabilityOffset_MapIO) - 1,
46 Interrupt = (1U << CapabilityOffset_Interrupt) - 1,
47 ProgramType = (1U << CapabilityOffset_ProgramType) - 1,
48 KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1,
49 HandleTableSize = (1U << CapabilityOffset_HandleTableSize) - 1,
50 Debug = (1U << CapabilityOffset_Debug) - 1,
51 Ignorable = 0xFFFFFFFFU,
52};
53
54// clang-format on
55
56constexpr CapabilityType GetCapabilityType(u32 value) {
57 return static_cast<CapabilityType>((~value & (value + 1)) - 1);
58}
59
60u32 GetFlagBitOffset(CapabilityType type) {
61 const auto value = static_cast<u32>(type);
62 return static_cast<u32>(Common::BitSize<u32>() - Common::CountLeadingZeroes32(value));
63}
64
65} // Anonymous namespace
66
67ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabilities,
68 std::size_t num_capabilities,
69 VMManager& vm_manager) {
70 Clear();
71
72 // Allow all cores and priorities.
73 core_mask = 0xF;
74 priority_mask = 0xFFFFFFFFFFFFFFFF;
75 kernel_version = PackedKernelVersion;
76
77 return ParseCapabilities(capabilities, num_capabilities, vm_manager);
78}
79
80ResultCode ProcessCapabilities::InitializeForUserProcess(const u32* capabilities,
81 std::size_t num_capabilities,
82 VMManager& vm_manager) {
83 Clear();
84
85 return ParseCapabilities(capabilities, num_capabilities, vm_manager);
86}
87
88void ProcessCapabilities::InitializeForMetadatalessProcess() {
89 // Allow all cores and priorities
90 core_mask = 0xF;
91 priority_mask = 0xFFFFFFFFFFFFFFFF;
92 kernel_version = PackedKernelVersion;
93
94 // Allow all system calls and interrupts.
95 svc_capabilities.set();
96 interrupt_capabilities.set();
97
98 // Allow using the maximum possible amount of handles
99 handle_table_size = static_cast<u32>(HandleTable::MAX_COUNT);
100
101 // Allow all debugging capabilities.
102 is_debuggable = true;
103 can_force_debug = true;
104}
105
106ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities,
107 std::size_t num_capabilities,
108 VMManager& vm_manager) {
109 u32 set_flags = 0;
110 u32 set_svc_bits = 0;
111
112 for (std::size_t i = 0; i < num_capabilities; ++i) {
113 const u32 descriptor = capabilities[i];
114 const auto type = GetCapabilityType(descriptor);
115
116 if (type == CapabilityType::MapPhysical) {
117 i++;
118
119 // The MapPhysical type uses two descriptor flags for its parameters.
120 // If there's only one, then there's a problem.
121 if (i >= num_capabilities) {
122 return ERR_INVALID_COMBINATION;
123 }
124
125 const auto size_flags = capabilities[i];
126 if (GetCapabilityType(size_flags) != CapabilityType::MapPhysical) {
127 return ERR_INVALID_COMBINATION;
128 }
129
130 const auto result = HandleMapPhysicalFlags(descriptor, size_flags, vm_manager);
131 if (result.IsError()) {
132 return result;
133 }
134 } else {
135 const auto result =
136 ParseSingleFlagCapability(set_flags, set_svc_bits, descriptor, vm_manager);
137 if (result.IsError()) {
138 return result;
139 }
140 }
141 }
142
143 return RESULT_SUCCESS;
144}
145
146ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits,
147 u32 flag, VMManager& vm_manager) {
148 const auto type = GetCapabilityType(flag);
149
150 if (type == CapabilityType::Unset) {
151 return ERR_INVALID_CAPABILITY_DESCRIPTOR;
152 }
153
154 // Bail early on ignorable entries, as one would expect,
155 // ignorable descriptors can be ignored.
156 if (type == CapabilityType::Ignorable) {
157 return RESULT_SUCCESS;
158 }
159
160 // Ensure that the give flag hasn't already been initialized before.
161 // If it has been, then bail.
162 const u32 flag_length = GetFlagBitOffset(type);
163 const u32 set_flag = 1U << flag_length;
164 if ((set_flag & set_flags & InitializeOnceMask) != 0) {
165 return ERR_INVALID_COMBINATION;
166 }
167 set_flags |= set_flag;
168
169 switch (type) {
170 case CapabilityType::PriorityAndCoreNum:
171 return HandlePriorityCoreNumFlags(flag);
172 case CapabilityType::Syscall:
173 return HandleSyscallFlags(set_svc_bits, flag);
174 case CapabilityType::MapIO:
175 return HandleMapIOFlags(flag, vm_manager);
176 case CapabilityType::Interrupt:
177 return HandleInterruptFlags(flag);
178 case CapabilityType::ProgramType:
179 return HandleProgramTypeFlags(flag);
180 case CapabilityType::KernelVersion:
181 return HandleKernelVersionFlags(flag);
182 case CapabilityType::HandleTableSize:
183 return HandleHandleTableFlags(flag);
184 case CapabilityType::Debug:
185 return HandleDebugFlags(flag);
186 default:
187 break;
188 }
189
190 return ERR_INVALID_CAPABILITY_DESCRIPTOR;
191}
192
193void ProcessCapabilities::Clear() {
194 svc_capabilities.reset();
195 interrupt_capabilities.reset();
196
197 core_mask = 0;
198 priority_mask = 0;
199
200 handle_table_size = 0;
201 kernel_version = 0;
202
203 is_debuggable = false;
204 can_force_debug = false;
205}
206
207ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
208 // TODO: Implement
209 return RESULT_SUCCESS;
210}
211
212ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags) {
213 // TODO: Implement
214 return RESULT_SUCCESS;
215}
216
217ResultCode ProcessCapabilities::HandleMapPhysicalFlags(u32 flags, u32 size_flags,
218 VMManager& vm_manager) {
219 // TODO(Lioncache): Implement once the memory manager can handle this.
220 return RESULT_SUCCESS;
221}
222
223ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, VMManager& vm_manager) {
224 // TODO(Lioncache): Implement once the memory manager can handle this.
225 return RESULT_SUCCESS;
226}
227
228ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) {
229 // TODO: Implement
230 return RESULT_SUCCESS;
231}
232
233ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) {
234 // TODO: Implement
235 return RESULT_SUCCESS;
236}
237
238ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) {
239 // TODO: Implement
240 return RESULT_SUCCESS;
241}
242
243ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
244 // TODO: Implement
245 return RESULT_SUCCESS;
246}
247
248ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) {
249 // TODO: Implement
250 return RESULT_SUCCESS;
251}
252
253} // namespace Kernel
diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h
new file mode 100644
index 000000000..5cff10476
--- /dev/null
+++ b/src/core/hle/kernel/process_capability.h
@@ -0,0 +1,209 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <bitset>
8
9#include "common/common_types.h"
10
11union ResultCode;
12
13namespace Kernel {
14
15class VMManager;
16
17/// Handles kernel capability descriptors that are provided by
18/// application metadata. These descriptors provide information
19/// that alters certain parameters for kernel process instance
20/// that will run said application (or applet).
21///
22/// Capabilities are a sequence of flag descriptors, that indicate various
23/// configurations and constraints for a particular process.
24///
25/// Flag types are indicated by a sequence of set low bits. E.g. the
26/// types are indicated with the low bits as follows (where x indicates "don't care"):
27///
28/// - Priority and core mask : 0bxxxxxxxxxxxx0111
29/// - Allowed service call mask: 0bxxxxxxxxxxx01111
30/// - Map physical memory : 0bxxxxxxxxx0111111
31/// - Map IO memory : 0bxxxxxxxx01111111
32/// - Interrupts : 0bxxxx011111111111
33/// - Application type : 0bxx01111111111111
34/// - Kernel version : 0bx011111111111111
35/// - Handle table size : 0b0111111111111111
36/// - Debugger flags : 0b1111111111111111
37///
38/// These are essentially a bit offset subtracted by 1 to create a mask.
39/// e.g. The first entry in the above list is simply bit 3 (value 8 -> 0b1000)
40/// subtracted by one (7 -> 0b0111)
41///
42/// An example of a bit layout (using the map physical layout):
43/// <example>
44/// The MapPhysical type indicates a sequence entry pair of:
45///
46/// [initial, memory_flags], where:
47///
48/// initial:
49/// bits:
50/// 7-24: Starting page to map memory at.
51/// 25 : Indicates if the memory should be mapped as read only.
52///
53/// memory_flags:
54/// bits:
55/// 7-20 : Number of pages to map
56/// 21-25: Seems to be reserved (still checked against though)
57/// 26 : Whether or not the memory being mapped is IO memory, or physical memory
58/// </example>
59///
60class ProcessCapabilities {
61public:
62 using InterruptCapabilities = std::bitset<1024>;
63 using SyscallCapabilities = std::bitset<128>;
64
65 ProcessCapabilities() = default;
66 ProcessCapabilities(const ProcessCapabilities&) = delete;
67 ProcessCapabilities(ProcessCapabilities&&) = default;
68
69 ProcessCapabilities& operator=(const ProcessCapabilities&) = delete;
70 ProcessCapabilities& operator=(ProcessCapabilities&&) = default;
71
72 /// Initializes this process capabilities instance for a kernel process.
73 ///
74 /// @param capabilities The capabilities to parse
75 /// @param num_capabilities The number of capabilities to parse.
76 /// @param vm_manager The memory manager to use for handling any mapping-related
77 /// operations (such as mapping IO memory, etc).
78 ///
79 /// @returns RESULT_SUCCESS if this capabilities instance was able to be initialized,
80 /// otherwise, an error code upon failure.
81 ///
82 ResultCode InitializeForKernelProcess(const u32* capabilities, std::size_t num_capabilities,
83 VMManager& vm_manager);
84
85 /// Initializes this process capabilities instance for a userland process.
86 ///
87 /// @param capabilities The capabilities to parse.
88 /// @param num_capabilities The total number of capabilities to parse.
89 /// @param vm_manager The memory manager to use for handling any mapping-related
90 /// operations (such as mapping IO memory, etc).
91 ///
92 /// @returns RESULT_SUCCESS if this capabilities instance was able to be initialized,
93 /// otherwise, an error code upon failure.
94 ///
95 ResultCode InitializeForUserProcess(const u32* capabilities, std::size_t num_capabilities,
96 VMManager& vm_manager);
97
98 /// Initializes this process capabilities instance for a process that does not
99 /// have any metadata to parse.
100 ///
101 /// This is necessary, as we allow running raw executables, and the internal
102 /// kernel process capabilities also determine what CPU cores the process is
103 /// allowed to run on, and what priorities are allowed for threads. It also
104 /// determines the max handle table size, what the program type is, whether or
105 /// not the process can be debugged, or whether it's possible for a process to
106 /// forcibly debug another process.
107 ///
108 /// Given the above, this essentially enables all capabilities across the board
109 /// for the process. It allows the process to:
110 ///
111 /// - Run on any core
112 /// - Use any thread priority
113 /// - Use the maximum amount of handles a process is allowed to.
114 /// - Be debuggable
115 /// - Forcibly debug other processes.
116 ///
117 /// Note that this is not a behavior that the kernel allows a process to do via
118 /// a single function like this. This is yuzu-specific behavior to handle
119 /// executables with no capability descriptors whatsoever to derive behavior from.
120 /// It being yuzu-specific is why this is also not the default behavior and not
121 /// done by default in the constructor.
122 ///
123 void InitializeForMetadatalessProcess();
124
125private:
126 /// Attempts to parse a given sequence of capability descriptors.
127 ///
128 /// @param capabilities The sequence of capability descriptors to parse.
129 /// @param num_capabilities The number of descriptors within the given sequence.
130 /// @param vm_manager The memory manager that will perform any memory
131 /// mapping if necessary.
132 ///
133 /// @return RESULT_SUCCESS if no errors occur, otherwise an error code.
134 ///
135 ResultCode ParseCapabilities(const u32* capabilities, std::size_t num_capabilities,
136 VMManager& vm_manager);
137
138 /// Attempts to parse a capability descriptor that is only represented by a
139 /// single flag set.
140 ///
141 /// @param set_flags Running set of flags that are used to catch
142 /// flags being initialized more than once when they shouldn't be.
143 /// @param set_svc_bits Running set of bits representing the allowed supervisor calls mask.
144 /// @param flag The flag to attempt to parse.
145 /// @param vm_manager The memory manager that will perform any memory
146 /// mapping if necessary.
147 ///
148 /// @return RESULT_SUCCESS if no errors occurred, otherwise an error code.
149 ///
150 ResultCode ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits, u32 flag,
151 VMManager& vm_manager);
152
153 /// Clears the internal state of this process capability instance. Necessary,
154 /// to have a sane starting point due to us allowing running executables without
155 /// configuration metadata. We assume a process is not going to have metadata,
156 /// and if it turns out that the process does, in fact, have metadata, then
157 /// we attempt to parse it. Thus, we need this to reset data members back to
158 /// a good state.
159 ///
160 /// DO NOT ever make this a public member function. This isn't an invariant
161 /// anything external should depend upon (and if anything comes to rely on it,
162 /// you should immediately be questioning the design of that thing, not this
163 /// class. If the kernel itself can run without depending on behavior like that,
164 /// then so can yuzu).
165 ///
166 void Clear();
167
168 /// Handles flags related to the priority and core number capability flags.
169 ResultCode HandlePriorityCoreNumFlags(u32 flags);
170
171 /// Handles flags related to determining the allowable SVC mask.
172 ResultCode HandleSyscallFlags(u32& set_svc_bits, u32 flags);
173
174 /// Handles flags related to mapping physical memory pages.
175 ResultCode HandleMapPhysicalFlags(u32 flags, u32 size_flags, VMManager& vm_manager);
176
177 /// Handles flags related to mapping IO pages.
178 ResultCode HandleMapIOFlags(u32 flags, VMManager& vm_manager);
179
180 /// Handles flags related to the interrupt capability flags.
181 ResultCode HandleInterruptFlags(u32 flags);
182
183 /// Handles flags related to the program type.
184 ResultCode HandleProgramTypeFlags(u32 flags);
185
186 /// Handles flags related to the handle table size.
187 ResultCode HandleHandleTableFlags(u32 flags);
188
189 /// Handles flags related to the kernel version capability flags.
190 ResultCode HandleKernelVersionFlags(u32 flags);
191
192 /// Handles flags related to debug-specific capabilities.
193 ResultCode HandleDebugFlags(u32 flags);
194
195 SyscallCapabilities svc_capabilities;
196 InterruptCapabilities interrupt_capabilities;
197
198 u64 core_mask = 0;
199 u64 priority_mask = 0;
200
201 u32 handle_table_size = 0;
202 u32 kernel_version = 0;
203 u32 program_type = 0;
204
205 bool is_debuggable = false;
206 bool can_force_debug = false;
207};
208
209} // namespace Kernel