k_page_table.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <memory>
  5. #include "common/common_funcs.h"
  6. #include "common/common_types.h"
  7. #include "common/page_table.h"
  8. #include "core/file_sys/program_metadata.h"
  9. #include "core/hle/kernel/k_dynamic_resource_manager.h"
  10. #include "core/hle/kernel/k_light_lock.h"
  11. #include "core/hle/kernel/k_memory_block.h"
  12. #include "core/hle/kernel/k_memory_block_manager.h"
  13. #include "core/hle/kernel/k_memory_layout.h"
  14. #include "core/hle/kernel/k_memory_manager.h"
  15. #include "core/hle/result.h"
  16. #include "core/memory.h"
  17. namespace Core {
  18. class System;
  19. }
  20. namespace Kernel {
  21. class KBlockInfoManager;
  22. class KMemoryBlockManager;
  23. class KResourceLimit;
  24. class KSystemResource;
  25. class KPageTable final {
  26. public:
  27. enum class ICacheInvalidationStrategy : u32 { InvalidateRange, InvalidateAll };
  28. YUZU_NON_COPYABLE(KPageTable);
  29. YUZU_NON_MOVEABLE(KPageTable);
  30. explicit KPageTable(Core::System& system_);
  31. ~KPageTable();
  32. Result InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
  33. bool enable_das_merge, bool from_back, KMemoryManager::Pool pool,
  34. VAddr code_addr, size_t code_size, KSystemResource* system_resource,
  35. KResourceLimit* resource_limit);
  36. void Finalize();
  37. Result MapProcessCode(VAddr addr, size_t pages_count, KMemoryState state,
  38. KMemoryPermission perm);
  39. Result MapCodeMemory(VAddr dst_address, VAddr src_address, size_t size);
  40. Result UnmapCodeMemory(VAddr dst_address, VAddr src_address, size_t size,
  41. ICacheInvalidationStrategy icache_invalidation_strategy);
  42. Result UnmapProcessMemory(VAddr dst_addr, size_t size, KPageTable& src_page_table,
  43. VAddr src_addr);
  44. Result MapPhysicalMemory(VAddr addr, size_t size);
  45. Result UnmapPhysicalMemory(VAddr addr, size_t size);
  46. Result MapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
  47. Result UnmapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
  48. Result MapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state,
  49. KMemoryPermission perm);
  50. Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
  51. KMemoryState state, KMemoryPermission perm) {
  52. R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
  53. this->GetRegionAddress(state),
  54. this->GetRegionSize(state) / PageSize, state, perm));
  55. }
  56. Result UnmapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state);
  57. Result UnmapPages(VAddr address, size_t num_pages, KMemoryState state);
  58. Result SetProcessMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm);
  59. KMemoryInfo QueryInfo(VAddr addr);
  60. Result SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission perm);
  61. Result SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr);
  62. Result SetMaxHeapSize(size_t size);
  63. Result SetHeapSize(VAddr* out, size_t size);
  64. ResultVal<VAddr> AllocateAndMapMemory(size_t needed_num_pages, size_t align, bool is_map_only,
  65. VAddr region_start, size_t region_num_pages,
  66. KMemoryState state, KMemoryPermission perm,
  67. PAddr map_addr = 0);
  68. Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
  69. KMemoryPermission perm, bool is_aligned, bool check_heap);
  70. Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap);
  71. Result UnlockForDeviceAddressSpace(VAddr addr, size_t size);
  72. Result LockForIpcUserBuffer(PAddr* out, VAddr address, size_t size);
  73. Result UnlockForIpcUserBuffer(VAddr address, size_t size);
  74. Result SetupForIpc(VAddr* out_dst_addr, size_t size, VAddr src_addr, KPageTable& src_page_table,
  75. KMemoryPermission test_perm, KMemoryState dst_state, bool send);
  76. Result CleanupForIpcServer(VAddr address, size_t size, KMemoryState dst_state);
  77. Result CleanupForIpcClient(VAddr address, size_t size, KMemoryState dst_state);
  78. Result LockForCodeMemory(KPageGroup* out, VAddr addr, size_t size);
  79. Result UnlockForCodeMemory(VAddr addr, size_t size, const KPageGroup& pg);
  80. Result MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t num_pages,
  81. KMemoryState state_mask, KMemoryState state,
  82. KMemoryPermission perm_mask, KMemoryPermission perm,
  83. KMemoryAttribute attr_mask, KMemoryAttribute attr);
  84. Common::PageTable& PageTableImpl() {
  85. return *m_page_table_impl;
  86. }
  87. const Common::PageTable& PageTableImpl() const {
  88. return *m_page_table_impl;
  89. }
  90. KBlockInfoManager* GetBlockInfoManager() {
  91. return m_block_info_manager;
  92. }
  93. bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
  94. protected:
  95. struct PageLinkedList {
  96. private:
  97. struct Node {
  98. Node* m_next;
  99. std::array<u8, PageSize - sizeof(Node*)> m_buffer;
  100. };
  101. public:
  102. constexpr PageLinkedList() = default;
  103. void Push(Node* n) {
  104. ASSERT(Common::IsAligned(reinterpret_cast<uintptr_t>(n), PageSize));
  105. n->m_next = m_root;
  106. m_root = n;
  107. }
  108. void Push(Core::Memory::Memory& memory, VAddr addr) {
  109. this->Push(memory.GetPointer<Node>(addr));
  110. }
  111. Node* Peek() const {
  112. return m_root;
  113. }
  114. Node* Pop() {
  115. Node* const r = m_root;
  116. m_root = r->m_next;
  117. r->m_next = nullptr;
  118. return r;
  119. }
  120. private:
  121. Node* m_root{};
  122. };
  123. static_assert(std::is_trivially_destructible<PageLinkedList>::value);
  124. private:
  125. enum class OperationType : u32 {
  126. Map = 0,
  127. MapFirst = 1,
  128. MapGroup = 2,
  129. Unmap = 3,
  130. ChangePermissions = 4,
  131. ChangePermissionsAndRefresh = 5,
  132. Separate = 6,
  133. };
  134. static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
  135. KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared;
  136. Result MapPages(VAddr addr, const KPageGroup& page_linked_list, KMemoryPermission perm);
  137. Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
  138. bool is_pa_valid, VAddr region_start, size_t region_num_pages,
  139. KMemoryState state, KMemoryPermission perm);
  140. Result UnmapPages(VAddr addr, const KPageGroup& page_linked_list);
  141. bool IsRegionContiguous(VAddr addr, u64 size) const;
  142. void AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list);
  143. KMemoryInfo QueryInfoImpl(VAddr addr);
  144. VAddr AllocateVirtualMemory(VAddr start, size_t region_num_pages, u64 needed_num_pages,
  145. size_t align);
  146. Result Operate(VAddr addr, size_t num_pages, const KPageGroup& page_group,
  147. OperationType operation);
  148. Result Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, OperationType operation,
  149. PAddr map_addr = 0);
  150. void FinalizeUpdate(PageLinkedList* page_list);
  151. VAddr GetRegionAddress(KMemoryState state) const;
  152. size_t GetRegionSize(KMemoryState state) const;
  153. VAddr FindFreeArea(VAddr region_start, size_t region_num_pages, size_t num_pages,
  154. size_t alignment, size_t offset, size_t guard_pages);
  155. Result CheckMemoryStateContiguous(size_t* out_blocks_needed, VAddr addr, size_t size,
  156. KMemoryState state_mask, KMemoryState state,
  157. KMemoryPermission perm_mask, KMemoryPermission perm,
  158. KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
  159. Result CheckMemoryStateContiguous(VAddr addr, size_t size, KMemoryState state_mask,
  160. KMemoryState state, KMemoryPermission perm_mask,
  161. KMemoryPermission perm, KMemoryAttribute attr_mask,
  162. KMemoryAttribute attr) const {
  163. R_RETURN(this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask,
  164. perm, attr_mask, attr));
  165. }
  166. Result CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, KMemoryState state,
  167. KMemoryPermission perm_mask, KMemoryPermission perm,
  168. KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
  169. Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
  170. KMemoryAttribute* out_attr, size_t* out_blocks_needed, VAddr addr,
  171. size_t size, KMemoryState state_mask, KMemoryState state,
  172. KMemoryPermission perm_mask, KMemoryPermission perm,
  173. KMemoryAttribute attr_mask, KMemoryAttribute attr,
  174. KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
  175. Result CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
  176. KMemoryState state_mask, KMemoryState state,
  177. KMemoryPermission perm_mask, KMemoryPermission perm,
  178. KMemoryAttribute attr_mask, KMemoryAttribute attr,
  179. KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
  180. R_RETURN(CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size,
  181. state_mask, state, perm_mask, perm, attr_mask, attr,
  182. ignore_attr));
  183. }
  184. Result CheckMemoryState(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
  185. KMemoryPermission perm_mask, KMemoryPermission perm,
  186. KMemoryAttribute attr_mask, KMemoryAttribute attr,
  187. KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
  188. R_RETURN(this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm,
  189. attr_mask, attr, ignore_attr));
  190. }
  191. Result LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
  192. KMemoryState state_mask, KMemoryState state,
  193. KMemoryPermission perm_mask, KMemoryPermission perm,
  194. KMemoryAttribute attr_mask, KMemoryAttribute attr,
  195. KMemoryPermission new_perm, KMemoryAttribute lock_attr);
  196. Result UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
  197. KMemoryPermission perm_mask, KMemoryPermission perm,
  198. KMemoryAttribute attr_mask, KMemoryAttribute attr,
  199. KMemoryPermission new_perm, KMemoryAttribute lock_attr,
  200. const KPageGroup* pg);
  201. Result MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages);
  202. bool IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages);
  203. bool IsLockedByCurrentThread() const {
  204. return m_general_lock.IsLockedByCurrentThread();
  205. }
  206. bool IsHeapPhysicalAddress(const KMemoryLayout& layout, PAddr phys_addr) {
  207. ASSERT(this->IsLockedByCurrentThread());
  208. return layout.IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr);
  209. }
  210. bool GetPhysicalAddressLocked(PAddr* out, VAddr virt_addr) const {
  211. ASSERT(this->IsLockedByCurrentThread());
  212. *out = GetPhysicalAddr(virt_addr);
  213. return *out != 0;
  214. }
  215. Result SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed, VAddr address,
  216. size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
  217. Result SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_addr,
  218. KMemoryPermission test_perm, KMemoryState dst_state,
  219. KPageTable& src_page_table, bool send);
  220. void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
  221. size_t size, KMemoryPermission prot_perm);
  222. mutable KLightLock m_general_lock;
  223. mutable KLightLock m_map_physical_memory_lock;
  224. public:
  225. constexpr VAddr GetAddressSpaceStart() const {
  226. return m_address_space_start;
  227. }
  228. constexpr VAddr GetAddressSpaceEnd() const {
  229. return m_address_space_end;
  230. }
  231. constexpr size_t GetAddressSpaceSize() const {
  232. return m_address_space_end - m_address_space_start;
  233. }
  234. constexpr VAddr GetHeapRegionStart() const {
  235. return m_heap_region_start;
  236. }
  237. constexpr VAddr GetHeapRegionEnd() const {
  238. return m_heap_region_end;
  239. }
  240. constexpr size_t GetHeapRegionSize() const {
  241. return m_heap_region_end - m_heap_region_start;
  242. }
  243. constexpr VAddr GetAliasRegionStart() const {
  244. return m_alias_region_start;
  245. }
  246. constexpr VAddr GetAliasRegionEnd() const {
  247. return m_alias_region_end;
  248. }
  249. constexpr size_t GetAliasRegionSize() const {
  250. return m_alias_region_end - m_alias_region_start;
  251. }
  252. constexpr VAddr GetStackRegionStart() const {
  253. return m_stack_region_start;
  254. }
  255. constexpr VAddr GetStackRegionEnd() const {
  256. return m_stack_region_end;
  257. }
  258. constexpr size_t GetStackRegionSize() const {
  259. return m_stack_region_end - m_stack_region_start;
  260. }
  261. constexpr VAddr GetKernelMapRegionStart() const {
  262. return m_kernel_map_region_start;
  263. }
  264. constexpr VAddr GetKernelMapRegionEnd() const {
  265. return m_kernel_map_region_end;
  266. }
  267. constexpr VAddr GetCodeRegionStart() const {
  268. return m_code_region_start;
  269. }
  270. constexpr VAddr GetCodeRegionEnd() const {
  271. return m_code_region_end;
  272. }
  273. constexpr VAddr GetAliasCodeRegionStart() const {
  274. return m_alias_code_region_start;
  275. }
  276. constexpr VAddr GetAliasCodeRegionEnd() const {
  277. return m_alias_code_region_end;
  278. }
  279. constexpr VAddr GetAliasCodeRegionSize() const {
  280. return m_alias_code_region_end - m_alias_code_region_start;
  281. }
  282. size_t GetNormalMemorySize() {
  283. KScopedLightLock lk(m_general_lock);
  284. return GetHeapSize() + m_mapped_physical_memory_size;
  285. }
  286. constexpr size_t GetAddressSpaceWidth() const {
  287. return m_address_space_width;
  288. }
  289. constexpr size_t GetHeapSize() const {
  290. return m_current_heap_end - m_heap_region_start;
  291. }
  292. constexpr bool IsInsideAddressSpace(VAddr address, size_t size) const {
  293. return m_address_space_start <= address && address + size - 1 <= m_address_space_end - 1;
  294. }
  295. constexpr bool IsOutsideAliasRegion(VAddr address, size_t size) const {
  296. return m_alias_region_start > address || address + size - 1 > m_alias_region_end - 1;
  297. }
  298. constexpr bool IsOutsideStackRegion(VAddr address, size_t size) const {
  299. return m_stack_region_start > address || address + size - 1 > m_stack_region_end - 1;
  300. }
  301. constexpr bool IsInvalidRegion(VAddr address, size_t size) const {
  302. return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1;
  303. }
  304. constexpr bool IsInsideHeapRegion(VAddr address, size_t size) const {
  305. return address + size > m_heap_region_start && m_heap_region_end > address;
  306. }
  307. constexpr bool IsInsideAliasRegion(VAddr address, size_t size) const {
  308. return address + size > m_alias_region_start && m_alias_region_end > address;
  309. }
  310. constexpr bool IsOutsideASLRRegion(VAddr address, size_t size) const {
  311. if (IsInvalidRegion(address, size)) {
  312. return true;
  313. }
  314. if (IsInsideHeapRegion(address, size)) {
  315. return true;
  316. }
  317. if (IsInsideAliasRegion(address, size)) {
  318. return true;
  319. }
  320. return {};
  321. }
  322. constexpr bool IsInsideASLRRegion(VAddr address, size_t size) const {
  323. return !IsOutsideASLRRegion(address, size);
  324. }
  325. constexpr size_t GetNumGuardPages() const {
  326. return IsKernel() ? 1 : 4;
  327. }
  328. PAddr GetPhysicalAddr(VAddr addr) const {
  329. const auto backing_addr = m_page_table_impl->backing_addr[addr >> PageBits];
  330. ASSERT(backing_addr);
  331. return backing_addr + addr;
  332. }
  333. constexpr bool Contains(VAddr addr) const {
  334. return m_address_space_start <= addr && addr <= m_address_space_end - 1;
  335. }
  336. constexpr bool Contains(VAddr addr, size_t size) const {
  337. return m_address_space_start <= addr && addr < addr + size &&
  338. addr + size - 1 <= m_address_space_end - 1;
  339. }
  340. public:
  341. static VAddr GetLinearMappedVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
  342. return layout.GetLinearVirtualAddress(addr);
  343. }
  344. static PAddr GetLinearMappedPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
  345. return layout.GetLinearPhysicalAddress(addr);
  346. }
  347. static VAddr GetHeapVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
  348. return GetLinearMappedVirtualAddress(layout, addr);
  349. }
  350. static PAddr GetHeapPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
  351. return GetLinearMappedPhysicalAddress(layout, addr);
  352. }
  353. static VAddr GetPageTableVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
  354. return GetLinearMappedVirtualAddress(layout, addr);
  355. }
  356. static PAddr GetPageTablePhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
  357. return GetLinearMappedPhysicalAddress(layout, addr);
  358. }
  359. private:
  360. constexpr bool IsKernel() const {
  361. return m_is_kernel;
  362. }
  363. constexpr bool IsAslrEnabled() const {
  364. return m_enable_aslr;
  365. }
  366. constexpr bool ContainsPages(VAddr addr, size_t num_pages) const {
  367. return (m_address_space_start <= addr) &&
  368. (num_pages <= (m_address_space_end - m_address_space_start) / PageSize) &&
  369. (addr + num_pages * PageSize - 1 <= m_address_space_end - 1);
  370. }
  371. private:
  372. class KScopedPageTableUpdater {
  373. private:
  374. KPageTable* m_pt{};
  375. PageLinkedList m_ll;
  376. public:
  377. explicit KScopedPageTableUpdater(KPageTable* pt) : m_pt(pt) {}
  378. explicit KScopedPageTableUpdater(KPageTable& pt) : KScopedPageTableUpdater(&pt) {}
  379. ~KScopedPageTableUpdater() {
  380. m_pt->FinalizeUpdate(this->GetPageList());
  381. }
  382. PageLinkedList* GetPageList() {
  383. return &m_ll;
  384. }
  385. };
  386. private:
  387. VAddr m_address_space_start{};
  388. VAddr m_address_space_end{};
  389. VAddr m_heap_region_start{};
  390. VAddr m_heap_region_end{};
  391. VAddr m_current_heap_end{};
  392. VAddr m_alias_region_start{};
  393. VAddr m_alias_region_end{};
  394. VAddr m_stack_region_start{};
  395. VAddr m_stack_region_end{};
  396. VAddr m_kernel_map_region_start{};
  397. VAddr m_kernel_map_region_end{};
  398. VAddr m_code_region_start{};
  399. VAddr m_code_region_end{};
  400. VAddr m_alias_code_region_start{};
  401. VAddr m_alias_code_region_end{};
  402. size_t m_max_heap_size{};
  403. size_t m_mapped_physical_memory_size{};
  404. size_t m_mapped_unsafe_physical_memory{};
  405. size_t m_mapped_insecure_memory{};
  406. size_t m_mapped_ipc_server_memory{};
  407. size_t m_address_space_width{};
  408. KMemoryBlockManager m_memory_block_manager;
  409. u32 m_allocate_option{};
  410. bool m_is_kernel{};
  411. bool m_enable_aslr{};
  412. bool m_enable_device_address_space_merge{};
  413. KMemoryBlockSlabManager* m_memory_block_slab_manager{};
  414. KBlockInfoManager* m_block_info_manager{};
  415. KResourceLimit* m_resource_limit{};
  416. u32 m_heap_fill_value{};
  417. u32 m_ipc_fill_value{};
  418. u32 m_stack_fill_value{};
  419. const KMemoryRegion* m_cached_physical_heap_region{};
  420. KMemoryManager::Pool m_memory_pool{KMemoryManager::Pool::Application};
  421. KMemoryManager::Direction m_allocation_option{KMemoryManager::Direction::FromFront};
  422. std::unique_ptr<Common::PageTable> m_page_table_impl;
  423. Core::System& m_system;
  424. KernelCore& m_kernel;
  425. };
  426. } // namespace Kernel