k_capabilities.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/hardware_properties.h"
  4. #include "core/hle/kernel/k_capabilities.h"
  5. #include "core/hle/kernel/k_memory_layout.h"
  6. #include "core/hle/kernel/k_process_page_table.h"
  7. #include "core/hle/kernel/k_trace.h"
  8. #include "core/hle/kernel/kernel.h"
  9. #include "core/hle/kernel/svc_results.h"
  10. #include "core/hle/kernel/svc_version.h"
  11. namespace Kernel {
  12. Result KCapabilities::InitializeForKip(std::span<const u32> kern_caps,
  13. KProcessPageTable* page_table) {
  14. // We're initializing an initial process.
  15. m_svc_access_flags.reset();
  16. m_irq_access_flags.reset();
  17. m_debug_capabilities = 0;
  18. m_handle_table_size = 0;
  19. m_intended_kernel_version = 0;
  20. m_program_type = 0;
  21. // Initial processes may run on all cores.
  22. constexpr u64 VirtMask = Core::Hardware::VirtualCoreMask;
  23. constexpr u64 PhysMask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(VirtMask);
  24. m_core_mask = VirtMask;
  25. m_phys_core_mask = PhysMask;
  26. // Initial processes may use any user priority they like.
  27. m_priority_mask = ~0xFULL;
  28. // Here, Nintendo sets the kernel version to the current kernel version.
  29. // We will follow suit and set the version to the highest supported kernel version.
  30. KernelVersion intended_kernel_version{};
  31. intended_kernel_version.major_version.Assign(Svc::SupportedKernelMajorVersion);
  32. intended_kernel_version.minor_version.Assign(Svc::SupportedKernelMinorVersion);
  33. m_intended_kernel_version = intended_kernel_version.raw;
  34. // Parse the capabilities array.
  35. R_RETURN(this->SetCapabilities(kern_caps, page_table));
  36. }
  37. Result KCapabilities::InitializeForUser(std::span<const u32> user_caps,
  38. KProcessPageTable* page_table) {
  39. // We're initializing a user process.
  40. m_svc_access_flags.reset();
  41. m_irq_access_flags.reset();
  42. m_debug_capabilities = 0;
  43. m_handle_table_size = 0;
  44. m_intended_kernel_version = 0;
  45. m_program_type = 0;
  46. // User processes must specify what cores/priorities they can use.
  47. m_core_mask = 0;
  48. m_priority_mask = 0;
  49. // Parse the user capabilities array.
  50. R_RETURN(this->SetCapabilities(user_caps, page_table));
  51. }
  52. Result KCapabilities::SetCorePriorityCapability(const u32 cap) {
  53. // We can't set core/priority if we've already set them.
  54. R_UNLESS(m_core_mask == 0, ResultInvalidArgument);
  55. R_UNLESS(m_priority_mask == 0, ResultInvalidArgument);
  56. // Validate the core/priority.
  57. CorePriority pack{cap};
  58. const u32 min_core = pack.minimum_core_id;
  59. const u32 max_core = pack.maximum_core_id;
  60. const u32 max_prio = pack.lowest_thread_priority;
  61. const u32 min_prio = pack.highest_thread_priority;
  62. R_UNLESS(min_core <= max_core, ResultInvalidCombination);
  63. R_UNLESS(min_prio <= max_prio, ResultInvalidCombination);
  64. R_UNLESS(max_core < Core::Hardware::NumVirtualCores, ResultInvalidCoreId);
  65. ASSERT(max_prio < Common::BitSize<u64>());
  66. // Set core mask.
  67. for (auto core_id = min_core; core_id <= max_core; core_id++) {
  68. m_core_mask |= (1ULL << core_id);
  69. }
  70. ASSERT((m_core_mask & Core::Hardware::VirtualCoreMask) == m_core_mask);
  71. // Set physical core mask.
  72. m_phys_core_mask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(m_core_mask);
  73. // Set priority mask.
  74. for (auto prio = min_prio; prio <= max_prio; prio++) {
  75. m_priority_mask |= (1ULL << prio);
  76. }
  77. // We must have some core/priority we can use.
  78. R_UNLESS(m_core_mask != 0, ResultInvalidArgument);
  79. R_UNLESS(m_priority_mask != 0, ResultInvalidArgument);
  80. // Processes must not have access to kernel thread priorities.
  81. R_UNLESS((m_priority_mask & 0xF) == 0, ResultInvalidArgument);
  82. R_SUCCEED();
  83. }
  84. Result KCapabilities::SetSyscallMaskCapability(const u32 cap, u32& set_svc) {
  85. // Validate the index.
  86. SyscallMask pack{cap};
  87. const u32 mask = pack.mask;
  88. const u32 index = pack.index;
  89. const u32 index_flag = (1U << index);
  90. R_UNLESS((set_svc & index_flag) == 0, ResultInvalidCombination);
  91. set_svc |= index_flag;
  92. // Set SVCs.
  93. for (size_t i = 0; i < decltype(SyscallMask::mask)::bits; i++) {
  94. const u32 svc_id = static_cast<u32>(decltype(SyscallMask::mask)::bits * index + i);
  95. if (mask & (1U << i)) {
  96. R_UNLESS(this->SetSvcAllowed(svc_id), ResultOutOfRange);
  97. }
  98. }
  99. R_SUCCEED();
  100. }
  101. Result KCapabilities::MapRange_(const u32 cap, const u32 size_cap, KProcessPageTable* page_table) {
  102. const auto range_pack = MapRange{cap};
  103. const auto size_pack = MapRangeSize{size_cap};
  104. // Get/validate address/size
  105. const u64 phys_addr = range_pack.address.Value() * PageSize;
  106. // Validate reserved bits are unused.
  107. R_UNLESS(size_pack.reserved.Value() == 0, ResultOutOfRange);
  108. const size_t num_pages = size_pack.pages;
  109. const size_t size = num_pages * PageSize;
  110. R_UNLESS(num_pages != 0, ResultInvalidSize);
  111. R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
  112. R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
  113. // Do the mapping.
  114. [[maybe_unused]] const KMemoryPermission perm = range_pack.read_only.Value()
  115. ? KMemoryPermission::UserRead
  116. : KMemoryPermission::UserReadWrite;
  117. if (MapRangeSize{size_cap}.normal) {
  118. R_RETURN(page_table->MapStatic(phys_addr, size, perm));
  119. } else {
  120. R_RETURN(page_table->MapIo(phys_addr, size, perm));
  121. }
  122. }
  123. Result KCapabilities::MapIoPage_(const u32 cap, KProcessPageTable* page_table) {
  124. // Get/validate address/size
  125. const u64 phys_addr = MapIoPage{cap}.address.Value() * PageSize;
  126. const size_t num_pages = 1;
  127. const size_t size = num_pages * PageSize;
  128. R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
  129. R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
  130. // Do the mapping.
  131. R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission::UserReadWrite));
  132. }
  133. template <typename F>
  134. Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
  135. // Define the allowed memory regions.
  136. constexpr std::array<KMemoryRegionType, 4> MemoryRegions{
  137. KMemoryRegionType_None,
  138. KMemoryRegionType_KernelTraceBuffer,
  139. KMemoryRegionType_OnMemoryBootImage,
  140. KMemoryRegionType_DTB,
  141. };
  142. // Extract regions/read only.
  143. const MapRegion pack{cap};
  144. const std::array<RegionType, 3> types{pack.region0, pack.region1, pack.region2};
  145. const std::array<u32, 3> ro{pack.read_only0, pack.read_only1, pack.read_only2};
  146. for (size_t i = 0; i < types.size(); i++) {
  147. const auto type = types[i];
  148. const auto perm = ro[i] ? KMemoryPermission::UserRead : KMemoryPermission::UserReadWrite;
  149. switch (type) {
  150. case RegionType::NoMapping:
  151. break;
  152. case RegionType::KernelTraceBuffer:
  153. case RegionType::OnMemoryBootImage:
  154. case RegionType::DTB:
  155. R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
  156. break;
  157. default:
  158. R_THROW(ResultNotFound);
  159. }
  160. }
  161. R_SUCCEED();
  162. }
  163. Result KCapabilities::MapRegion_(const u32 cap, KProcessPageTable* page_table) {
  164. // Map each region into the process's page table.
  165. return ProcessMapRegionCapability(
  166. cap, [page_table](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
  167. R_RETURN(page_table->MapRegion(region_type, perm));
  168. });
  169. }
  170. Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) {
  171. // Check that each region has a physical backing store.
  172. return ProcessMapRegionCapability(
  173. cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
  174. R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(
  175. region_type) != nullptr,
  176. ResultOutOfRange);
  177. R_SUCCEED();
  178. });
  179. }
  180. Result KCapabilities::SetInterruptPairCapability(const u32 cap) {
  181. // Extract interrupts.
  182. const InterruptPair pack{cap};
  183. const std::array<u32, 2> ids{pack.interrupt_id0, pack.interrupt_id1};
  184. for (size_t i = 0; i < ids.size(); i++) {
  185. if (ids[i] != PaddingInterruptId) {
  186. UNIMPLEMENTED();
  187. // R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(ids[i]), ResultOutOfRange);
  188. // R_UNLESS(this->SetInterruptPermitted(ids[i]), ResultOutOfRange);
  189. }
  190. }
  191. R_SUCCEED();
  192. }
  193. Result KCapabilities::SetProgramTypeCapability(const u32 cap) {
  194. // Validate.
  195. const ProgramType pack{cap};
  196. R_UNLESS(pack.reserved == 0, ResultReservedUsed);
  197. m_program_type = pack.type;
  198. R_SUCCEED();
  199. }
  200. Result KCapabilities::SetKernelVersionCapability(const u32 cap) {
  201. // Ensure we haven't set our version before.
  202. R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version == 0, ResultInvalidArgument);
  203. // Set, ensure that we set a valid version.
  204. m_intended_kernel_version = cap;
  205. R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version != 0, ResultInvalidArgument);
  206. R_SUCCEED();
  207. }
  208. Result KCapabilities::SetHandleTableCapability(const u32 cap) {
  209. // Validate.
  210. const HandleTable pack{cap};
  211. R_UNLESS(pack.reserved == 0, ResultReservedUsed);
  212. m_handle_table_size = pack.size;
  213. R_SUCCEED();
  214. }
  215. Result KCapabilities::SetDebugFlagsCapability(const u32 cap) {
  216. // Validate.
  217. const DebugFlags pack{cap};
  218. R_UNLESS(pack.reserved == 0, ResultReservedUsed);
  219. DebugFlags debug_capabilities{m_debug_capabilities};
  220. debug_capabilities.allow_debug.Assign(pack.allow_debug);
  221. debug_capabilities.force_debug.Assign(pack.force_debug);
  222. m_debug_capabilities = debug_capabilities.raw;
  223. R_SUCCEED();
  224. }
  225. Result KCapabilities::SetCapability(const u32 cap, u32& set_flags, u32& set_svc,
  226. KProcessPageTable* page_table) {
  227. // Validate this is a capability we can act on.
  228. const auto type = GetCapabilityType(cap);
  229. R_UNLESS(type != CapabilityType::Invalid, ResultInvalidArgument);
  230. // If the type is padding, we have no work to do.
  231. R_SUCCEED_IF(type == CapabilityType::Padding);
  232. // Check that we haven't already processed this capability.
  233. const auto flag = GetCapabilityFlag(type);
  234. R_UNLESS(((set_flags & InitializeOnceFlags) & flag) == 0, ResultInvalidCombination);
  235. set_flags |= flag;
  236. // Process the capability.
  237. switch (type) {
  238. case CapabilityType::CorePriority:
  239. R_RETURN(this->SetCorePriorityCapability(cap));
  240. case CapabilityType::SyscallMask:
  241. R_RETURN(this->SetSyscallMaskCapability(cap, set_svc));
  242. case CapabilityType::MapIoPage:
  243. R_RETURN(this->MapIoPage_(cap, page_table));
  244. case CapabilityType::MapRegion:
  245. R_RETURN(this->MapRegion_(cap, page_table));
  246. case CapabilityType::InterruptPair:
  247. R_RETURN(this->SetInterruptPairCapability(cap));
  248. case CapabilityType::ProgramType:
  249. R_RETURN(this->SetProgramTypeCapability(cap));
  250. case CapabilityType::KernelVersion:
  251. R_RETURN(this->SetKernelVersionCapability(cap));
  252. case CapabilityType::HandleTable:
  253. R_RETURN(this->SetHandleTableCapability(cap));
  254. case CapabilityType::DebugFlags:
  255. R_RETURN(this->SetDebugFlagsCapability(cap));
  256. default:
  257. R_THROW(ResultInvalidArgument);
  258. }
  259. }
  260. Result KCapabilities::SetCapabilities(std::span<const u32> caps, KProcessPageTable* page_table) {
  261. u32 set_flags = 0, set_svc = 0;
  262. for (size_t i = 0; i < caps.size(); i++) {
  263. const u32 cap{caps[i]};
  264. if (GetCapabilityType(cap) == CapabilityType::MapRange) {
  265. // Check that the pair cap exists.
  266. R_UNLESS((++i) < caps.size(), ResultInvalidCombination);
  267. // Check the pair cap is a map range cap.
  268. const u32 size_cap{caps[i]};
  269. R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange,
  270. ResultInvalidCombination);
  271. // Map the range.
  272. R_TRY(this->MapRange_(cap, size_cap, page_table));
  273. } else if (GetCapabilityType(cap) == CapabilityType::MapRegion && !IsKTraceEnabled) {
  274. continue;
  275. } else {
  276. R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
  277. }
  278. }
  279. R_SUCCEED();
  280. }
  281. Result KCapabilities::CheckCapabilities(KernelCore& kernel, std::span<const u32> caps) {
  282. for (auto cap : caps) {
  283. // Check the capability refers to a valid region.
  284. if (GetCapabilityType(cap) == CapabilityType::MapRegion) {
  285. R_TRY(CheckMapRegion(kernel, cap));
  286. }
  287. }
  288. R_SUCCEED();
  289. }
  290. } // namespace Kernel