summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Lioncash2018-12-19 12:57:47 -0500
committerGravatar Lioncash2018-12-21 07:05:31 -0500
commit6ff5135521a59cd510ba3ecc8d5ff5d56cdbf08e (patch)
treef2b45468a65f650c03e47fe3a494cf1d27c1fab3 /src
parentcommon: Add basic bit manipulation utility function to Common (diff)
downloadyuzu-6ff5135521a59cd510ba3ecc8d5ff5d56cdbf08e.tar.gz
yuzu-6ff5135521a59cd510ba3ecc8d5ff5d56cdbf08e.tar.xz
yuzu-6ff5135521a59cd510ba3ecc8d5ff5d56cdbf08e.zip
kernel/process: Introduce process capability parsing skeleton
We've had the old kernel capability parser from Citra, however, this is unused code and doesn't actually map to how the kernel on the Switch does it. This introduces the basic functional skeleton for parsing process capabilities.
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