k_capabilities.cpp 13 KB

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