process_capability.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <bit>
  5. #include "common/bit_util.h"
  6. #include "common/logging/log.h"
  7. #include "core/hle/kernel/k_handle_table.h"
  8. #include "core/hle/kernel/k_page_table.h"
  9. #include "core/hle/kernel/process_capability.h"
  10. #include "core/hle/kernel/svc_results.h"
  11. namespace Kernel {
  12. namespace {
  13. // clang-format off
  14. // Shift offsets for kernel capability types.
  15. enum : u32 {
  16. CapabilityOffset_PriorityAndCoreNum = 3,
  17. CapabilityOffset_Syscall = 4,
  18. CapabilityOffset_MapPhysical = 6,
  19. CapabilityOffset_MapIO = 7,
  20. CapabilityOffset_MapRegion = 10,
  21. CapabilityOffset_Interrupt = 11,
  22. CapabilityOffset_ProgramType = 13,
  23. CapabilityOffset_KernelVersion = 14,
  24. CapabilityOffset_HandleTableSize = 15,
  25. CapabilityOffset_Debug = 16,
  26. };
  27. // Combined mask of all parameters that may be initialized only once.
  28. constexpr u32 InitializeOnceMask = (1U << CapabilityOffset_PriorityAndCoreNum) |
  29. (1U << CapabilityOffset_ProgramType) |
  30. (1U << CapabilityOffset_KernelVersion) |
  31. (1U << CapabilityOffset_HandleTableSize) |
  32. (1U << CapabilityOffset_Debug);
  33. // Packed kernel version indicating 10.4.0
  34. constexpr u32 PackedKernelVersion = 0x520000;
  35. // Indicates possible types of capabilities that can be specified.
  36. enum class CapabilityType : u32 {
  37. Unset = 0U,
  38. PriorityAndCoreNum = (1U << CapabilityOffset_PriorityAndCoreNum) - 1,
  39. Syscall = (1U << CapabilityOffset_Syscall) - 1,
  40. MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1,
  41. MapIO = (1U << CapabilityOffset_MapIO) - 1,
  42. MapRegion = (1U << CapabilityOffset_MapRegion) - 1,
  43. Interrupt = (1U << CapabilityOffset_Interrupt) - 1,
  44. ProgramType = (1U << CapabilityOffset_ProgramType) - 1,
  45. KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1,
  46. HandleTableSize = (1U << CapabilityOffset_HandleTableSize) - 1,
  47. Debug = (1U << CapabilityOffset_Debug) - 1,
  48. Ignorable = 0xFFFFFFFFU,
  49. };
  50. // clang-format on
  51. constexpr CapabilityType GetCapabilityType(u32 value) {
  52. return static_cast<CapabilityType>((~value & (value + 1)) - 1);
  53. }
  54. u32 GetFlagBitOffset(CapabilityType type) {
  55. const auto value = static_cast<u32>(type);
  56. return static_cast<u32>(Common::BitSize<u32>() - static_cast<u32>(std::countl_zero(value)));
  57. }
  58. } // Anonymous namespace
  59. ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabilities,
  60. std::size_t num_capabilities,
  61. KPageTable& page_table) {
  62. Clear();
  63. // Allow all cores and priorities.
  64. core_mask = 0xF;
  65. priority_mask = 0xFFFFFFFFFFFFFFFF;
  66. kernel_version = PackedKernelVersion;
  67. return ParseCapabilities(capabilities, num_capabilities, page_table);
  68. }
  69. ResultCode ProcessCapabilities::InitializeForUserProcess(const u32* capabilities,
  70. std::size_t num_capabilities,
  71. KPageTable& page_table) {
  72. Clear();
  73. return ParseCapabilities(capabilities, num_capabilities, page_table);
  74. }
  75. void ProcessCapabilities::InitializeForMetadatalessProcess() {
  76. // Allow all cores and priorities
  77. core_mask = 0xF;
  78. priority_mask = 0xFFFFFFFFFFFFFFFF;
  79. kernel_version = PackedKernelVersion;
  80. // Allow all system calls and interrupts.
  81. svc_capabilities.set();
  82. interrupt_capabilities.set();
  83. // Allow using the maximum possible amount of handles
  84. handle_table_size = static_cast<s32>(KHandleTable::MaxTableSize);
  85. // Allow all debugging capabilities.
  86. is_debuggable = true;
  87. can_force_debug = true;
  88. }
  89. ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities,
  90. std::size_t num_capabilities,
  91. KPageTable& page_table) {
  92. u32 set_flags = 0;
  93. u32 set_svc_bits = 0;
  94. for (std::size_t i = 0; i < num_capabilities; ++i) {
  95. const u32 descriptor = capabilities[i];
  96. const auto type = GetCapabilityType(descriptor);
  97. if (type == CapabilityType::MapPhysical) {
  98. i++;
  99. // The MapPhysical type uses two descriptor flags for its parameters.
  100. // If there's only one, then there's a problem.
  101. if (i >= num_capabilities) {
  102. LOG_ERROR(Kernel, "Invalid combination! i={}", i);
  103. return ResultInvalidCombination;
  104. }
  105. const auto size_flags = capabilities[i];
  106. if (GetCapabilityType(size_flags) != CapabilityType::MapPhysical) {
  107. LOG_ERROR(Kernel, "Invalid capability type! size_flags={}", size_flags);
  108. return ResultInvalidCombination;
  109. }
  110. const auto result = HandleMapPhysicalFlags(descriptor, size_flags, page_table);
  111. if (result.IsError()) {
  112. LOG_ERROR(Kernel, "Failed to map physical flags! descriptor={}, size_flags={}",
  113. descriptor, size_flags);
  114. return result;
  115. }
  116. } else {
  117. const auto result =
  118. ParseSingleFlagCapability(set_flags, set_svc_bits, descriptor, page_table);
  119. if (result.IsError()) {
  120. LOG_ERROR(
  121. Kernel,
  122. "Failed to parse capability flag! set_flags={}, set_svc_bits={}, descriptor={}",
  123. set_flags, set_svc_bits, descriptor);
  124. return result;
  125. }
  126. }
  127. }
  128. return RESULT_SUCCESS;
  129. }
  130. ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits,
  131. u32 flag, KPageTable& page_table) {
  132. const auto type = GetCapabilityType(flag);
  133. if (type == CapabilityType::Unset) {
  134. return ResultInvalidArgument;
  135. }
  136. // Bail early on ignorable entries, as one would expect,
  137. // ignorable descriptors can be ignored.
  138. if (type == CapabilityType::Ignorable) {
  139. return RESULT_SUCCESS;
  140. }
  141. // Ensure that the give flag hasn't already been initialized before.
  142. // If it has been, then bail.
  143. const u32 flag_length = GetFlagBitOffset(type);
  144. const u32 set_flag = 1U << flag_length;
  145. if ((set_flag & set_flags & InitializeOnceMask) != 0) {
  146. LOG_ERROR(Kernel,
  147. "Attempted to initialize flags that may only be initialized once. set_flags={}",
  148. set_flags);
  149. return ResultInvalidCombination;
  150. }
  151. set_flags |= set_flag;
  152. switch (type) {
  153. case CapabilityType::PriorityAndCoreNum:
  154. return HandlePriorityCoreNumFlags(flag);
  155. case CapabilityType::Syscall:
  156. return HandleSyscallFlags(set_svc_bits, flag);
  157. case CapabilityType::MapIO:
  158. return HandleMapIOFlags(flag, page_table);
  159. case CapabilityType::MapRegion:
  160. return HandleMapRegionFlags(flag, page_table);
  161. case CapabilityType::Interrupt:
  162. return HandleInterruptFlags(flag);
  163. case CapabilityType::ProgramType:
  164. return HandleProgramTypeFlags(flag);
  165. case CapabilityType::KernelVersion:
  166. return HandleKernelVersionFlags(flag);
  167. case CapabilityType::HandleTableSize:
  168. return HandleHandleTableFlags(flag);
  169. case CapabilityType::Debug:
  170. return HandleDebugFlags(flag);
  171. default:
  172. break;
  173. }
  174. LOG_ERROR(Kernel, "Invalid capability type! type={}", type);
  175. return ResultInvalidArgument;
  176. }
  177. void ProcessCapabilities::Clear() {
  178. svc_capabilities.reset();
  179. interrupt_capabilities.reset();
  180. core_mask = 0;
  181. priority_mask = 0;
  182. handle_table_size = 0;
  183. kernel_version = 0;
  184. program_type = ProgramType::SysModule;
  185. is_debuggable = false;
  186. can_force_debug = false;
  187. }
  188. ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
  189. if (priority_mask != 0 || core_mask != 0) {
  190. LOG_ERROR(Kernel, "Core or priority mask are not zero! priority_mask={}, core_mask={}",
  191. priority_mask, core_mask);
  192. return ResultInvalidArgument;
  193. }
  194. const u32 core_num_min = (flags >> 16) & 0xFF;
  195. const u32 core_num_max = (flags >> 24) & 0xFF;
  196. if (core_num_min > core_num_max) {
  197. LOG_ERROR(Kernel, "Core min is greater than core max! core_num_min={}, core_num_max={}",
  198. core_num_min, core_num_max);
  199. return ResultInvalidCombination;
  200. }
  201. const u32 priority_min = (flags >> 10) & 0x3F;
  202. const u32 priority_max = (flags >> 4) & 0x3F;
  203. if (priority_min > priority_max) {
  204. LOG_ERROR(Kernel,
  205. "Priority min is greater than priority max! priority_min={}, priority_max={}",
  206. core_num_min, priority_max);
  207. return ResultInvalidCombination;
  208. }
  209. // The switch only has 4 usable cores.
  210. if (core_num_max >= 4) {
  211. LOG_ERROR(Kernel, "Invalid max cores specified! core_num_max={}", core_num_max);
  212. return ResultInvalidCoreId;
  213. }
  214. const auto make_mask = [](u64 min, u64 max) {
  215. const u64 range = max - min + 1;
  216. const u64 mask = (1ULL << range) - 1;
  217. return mask << min;
  218. };
  219. core_mask = make_mask(core_num_min, core_num_max);
  220. priority_mask = make_mask(priority_min, priority_max);
  221. return RESULT_SUCCESS;
  222. }
  223. ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags) {
  224. const u32 index = flags >> 29;
  225. const u32 svc_bit = 1U << index;
  226. // If we've already set this svc before, bail.
  227. if ((set_svc_bits & svc_bit) != 0) {
  228. return ResultInvalidCombination;
  229. }
  230. set_svc_bits |= svc_bit;
  231. const u32 svc_mask = (flags >> 5) & 0xFFFFFF;
  232. for (u32 i = 0; i < 24; ++i) {
  233. const u32 svc_number = index * 24 + i;
  234. if ((svc_mask & (1U << i)) == 0) {
  235. continue;
  236. }
  237. svc_capabilities[svc_number] = true;
  238. }
  239. return RESULT_SUCCESS;
  240. }
  241. ResultCode ProcessCapabilities::HandleMapPhysicalFlags(u32 flags, u32 size_flags,
  242. KPageTable& page_table) {
  243. // TODO(Lioncache): Implement once the memory manager can handle this.
  244. return RESULT_SUCCESS;
  245. }
  246. ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, KPageTable& page_table) {
  247. // TODO(Lioncache): Implement once the memory manager can handle this.
  248. return RESULT_SUCCESS;
  249. }
  250. ResultCode ProcessCapabilities::HandleMapRegionFlags(u32 flags, KPageTable& page_table) {
  251. // TODO(Lioncache): Implement once the memory manager can handle this.
  252. return RESULT_SUCCESS;
  253. }
  254. ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) {
  255. constexpr u32 interrupt_ignore_value = 0x3FF;
  256. const u32 interrupt0 = (flags >> 12) & 0x3FF;
  257. const u32 interrupt1 = (flags >> 22) & 0x3FF;
  258. for (u32 interrupt : {interrupt0, interrupt1}) {
  259. if (interrupt == interrupt_ignore_value) {
  260. continue;
  261. }
  262. // NOTE:
  263. // This should be checking a generic interrupt controller value
  264. // as part of the calculation, however, given we don't currently
  265. // emulate that, it's sufficient to mark every interrupt as defined.
  266. if (interrupt >= interrupt_capabilities.size()) {
  267. LOG_ERROR(Kernel, "Process interrupt capability is out of range! svc_number={}",
  268. interrupt);
  269. return ResultOutOfRange;
  270. }
  271. interrupt_capabilities[interrupt] = true;
  272. }
  273. return RESULT_SUCCESS;
  274. }
  275. ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) {
  276. const u32 reserved = flags >> 17;
  277. if (reserved != 0) {
  278. LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
  279. return ResultReservedUsed;
  280. }
  281. program_type = static_cast<ProgramType>((flags >> 14) & 0b111);
  282. return RESULT_SUCCESS;
  283. }
  284. ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) {
  285. // Yes, the internal member variable is checked in the actual kernel here.
  286. // This might look odd for options that are only allowed to be initialized
  287. // just once, however the kernel has a separate initialization function for
  288. // kernel processes and userland processes. The kernel variant sets this
  289. // member variable ahead of time.
  290. const u32 major_version = kernel_version >> 19;
  291. if (major_version != 0 || flags < 0x80000) {
  292. LOG_ERROR(Kernel,
  293. "Kernel version is non zero or flags are too small! major_version={}, flags={}",
  294. major_version, flags);
  295. return ResultInvalidArgument;
  296. }
  297. kernel_version = flags;
  298. return RESULT_SUCCESS;
  299. }
  300. ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
  301. const u32 reserved = flags >> 26;
  302. if (reserved != 0) {
  303. LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
  304. return ResultReservedUsed;
  305. }
  306. handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF);
  307. return RESULT_SUCCESS;
  308. }
  309. ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) {
  310. const u32 reserved = flags >> 19;
  311. if (reserved != 0) {
  312. LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
  313. return ResultReservedUsed;
  314. }
  315. is_debuggable = (flags & 0x20000) != 0;
  316. can_force_debug = (flags & 0x40000) != 0;
  317. return RESULT_SUCCESS;
  318. }
  319. } // namespace Kernel