k_page_table.cpp 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/alignment.h"
  4. #include "common/assert.h"
  5. #include "common/literals.h"
  6. #include "common/scope_exit.h"
  7. #include "core/core.h"
  8. #include "core/hle/kernel/k_address_space_info.h"
  9. #include "core/hle/kernel/k_memory_block.h"
  10. #include "core/hle/kernel/k_memory_block_manager.h"
  11. #include "core/hle/kernel/k_page_linked_list.h"
  12. #include "core/hle/kernel/k_page_table.h"
  13. #include "core/hle/kernel/k_process.h"
  14. #include "core/hle/kernel/k_resource_limit.h"
  15. #include "core/hle/kernel/k_scoped_resource_reservation.h"
  16. #include "core/hle/kernel/k_system_control.h"
  17. #include "core/hle/kernel/kernel.h"
  18. #include "core/hle/kernel/svc_results.h"
  19. #include "core/memory.h"
  20. namespace Kernel {
  21. namespace {
  22. using namespace Common::Literals;
  23. constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType as_type) {
  24. switch (as_type) {
  25. case FileSys::ProgramAddressSpaceType::Is32Bit:
  26. case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
  27. return 32;
  28. case FileSys::ProgramAddressSpaceType::Is36Bit:
  29. return 36;
  30. case FileSys::ProgramAddressSpaceType::Is39Bit:
  31. return 39;
  32. default:
  33. ASSERT(false);
  34. return {};
  35. }
  36. }
  37. } // namespace
  38. KPageTable::KPageTable(Core::System& system_)
  39. : general_lock{system_.Kernel()}, map_physical_memory_lock{system_.Kernel()}, system{system_} {}
  40. KPageTable::~KPageTable() = default;
  41. ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
  42. bool enable_aslr, VAddr code_addr,
  43. std::size_t code_size, KMemoryManager::Pool pool) {
  44. const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) {
  45. return KAddressSpaceInfo::GetAddressSpaceStart(address_space_width, type);
  46. };
  47. const auto GetSpaceSize = [this](KAddressSpaceInfo::Type type) {
  48. return KAddressSpaceInfo::GetAddressSpaceSize(address_space_width, type);
  49. };
  50. // Set our width and heap/alias sizes
  51. address_space_width = GetAddressSpaceWidthFromType(as_type);
  52. const VAddr start = 0;
  53. const VAddr end{1ULL << address_space_width};
  54. std::size_t alias_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Alias)};
  55. std::size_t heap_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Heap)};
  56. ASSERT(code_addr < code_addr + code_size);
  57. ASSERT(code_addr + code_size - 1 <= end - 1);
  58. // Adjust heap/alias size if we don't have an alias region
  59. if (as_type == FileSys::ProgramAddressSpaceType::Is32BitNoMap) {
  60. heap_region_size += alias_region_size;
  61. alias_region_size = 0;
  62. }
  63. // Set code regions and determine remaining
  64. constexpr std::size_t RegionAlignment{2_MiB};
  65. VAddr process_code_start{};
  66. VAddr process_code_end{};
  67. std::size_t stack_region_size{};
  68. std::size_t kernel_map_region_size{};
  69. if (address_space_width == 39) {
  70. alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Alias);
  71. heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap);
  72. stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack);
  73. kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
  74. code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit);
  75. code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit);
  76. alias_code_region_start = code_region_start;
  77. alias_code_region_end = code_region_end;
  78. process_code_start = Common::AlignDown(code_addr, RegionAlignment);
  79. process_code_end = Common::AlignUp(code_addr + code_size, RegionAlignment);
  80. } else {
  81. stack_region_size = 0;
  82. kernel_map_region_size = 0;
  83. code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::MapSmall);
  84. code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
  85. stack_region_start = code_region_start;
  86. alias_code_region_start = code_region_start;
  87. alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type::MapLarge) +
  88. GetSpaceSize(KAddressSpaceInfo::Type::MapLarge);
  89. stack_region_end = code_region_end;
  90. kernel_map_region_start = code_region_start;
  91. kernel_map_region_end = code_region_end;
  92. process_code_start = code_region_start;
  93. process_code_end = code_region_end;
  94. }
  95. // Set other basic fields
  96. is_aslr_enabled = enable_aslr;
  97. address_space_start = start;
  98. address_space_end = end;
  99. is_kernel = false;
  100. // Determine the region we can place our undetermineds in
  101. VAddr alloc_start{};
  102. std::size_t alloc_size{};
  103. if ((process_code_start - code_region_start) >= (end - process_code_end)) {
  104. alloc_start = code_region_start;
  105. alloc_size = process_code_start - code_region_start;
  106. } else {
  107. alloc_start = process_code_end;
  108. alloc_size = end - process_code_end;
  109. }
  110. const std::size_t needed_size{
  111. (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)};
  112. if (alloc_size < needed_size) {
  113. ASSERT(false);
  114. return ResultOutOfMemory;
  115. }
  116. const std::size_t remaining_size{alloc_size - needed_size};
  117. // Determine random placements for each region
  118. std::size_t alias_rnd{}, heap_rnd{}, stack_rnd{}, kmap_rnd{};
  119. if (enable_aslr) {
  120. alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  121. RegionAlignment;
  122. heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  123. RegionAlignment;
  124. stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  125. RegionAlignment;
  126. kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  127. RegionAlignment;
  128. }
  129. // Setup heap and alias regions
  130. alias_region_start = alloc_start + alias_rnd;
  131. alias_region_end = alias_region_start + alias_region_size;
  132. heap_region_start = alloc_start + heap_rnd;
  133. heap_region_end = heap_region_start + heap_region_size;
  134. if (alias_rnd <= heap_rnd) {
  135. heap_region_start += alias_region_size;
  136. heap_region_end += alias_region_size;
  137. } else {
  138. alias_region_start += heap_region_size;
  139. alias_region_end += heap_region_size;
  140. }
  141. // Setup stack region
  142. if (stack_region_size) {
  143. stack_region_start = alloc_start + stack_rnd;
  144. stack_region_end = stack_region_start + stack_region_size;
  145. if (alias_rnd < stack_rnd) {
  146. stack_region_start += alias_region_size;
  147. stack_region_end += alias_region_size;
  148. } else {
  149. alias_region_start += stack_region_size;
  150. alias_region_end += stack_region_size;
  151. }
  152. if (heap_rnd < stack_rnd) {
  153. stack_region_start += heap_region_size;
  154. stack_region_end += heap_region_size;
  155. } else {
  156. heap_region_start += stack_region_size;
  157. heap_region_end += stack_region_size;
  158. }
  159. }
  160. // Setup kernel map region
  161. if (kernel_map_region_size) {
  162. kernel_map_region_start = alloc_start + kmap_rnd;
  163. kernel_map_region_end = kernel_map_region_start + kernel_map_region_size;
  164. if (alias_rnd < kmap_rnd) {
  165. kernel_map_region_start += alias_region_size;
  166. kernel_map_region_end += alias_region_size;
  167. } else {
  168. alias_region_start += kernel_map_region_size;
  169. alias_region_end += kernel_map_region_size;
  170. }
  171. if (heap_rnd < kmap_rnd) {
  172. kernel_map_region_start += heap_region_size;
  173. kernel_map_region_end += heap_region_size;
  174. } else {
  175. heap_region_start += kernel_map_region_size;
  176. heap_region_end += kernel_map_region_size;
  177. }
  178. if (stack_region_size) {
  179. if (stack_rnd < kmap_rnd) {
  180. kernel_map_region_start += stack_region_size;
  181. kernel_map_region_end += stack_region_size;
  182. } else {
  183. stack_region_start += kernel_map_region_size;
  184. stack_region_end += kernel_map_region_size;
  185. }
  186. }
  187. }
  188. // Set heap members
  189. current_heap_end = heap_region_start;
  190. max_heap_size = 0;
  191. max_physical_memory_size = 0;
  192. // Ensure that we regions inside our address space
  193. auto IsInAddressSpace = [&](VAddr addr) {
  194. return address_space_start <= addr && addr <= address_space_end;
  195. };
  196. ASSERT(IsInAddressSpace(alias_region_start));
  197. ASSERT(IsInAddressSpace(alias_region_end));
  198. ASSERT(IsInAddressSpace(heap_region_start));
  199. ASSERT(IsInAddressSpace(heap_region_end));
  200. ASSERT(IsInAddressSpace(stack_region_start));
  201. ASSERT(IsInAddressSpace(stack_region_end));
  202. ASSERT(IsInAddressSpace(kernel_map_region_start));
  203. ASSERT(IsInAddressSpace(kernel_map_region_end));
  204. // Ensure that we selected regions that don't overlap
  205. const VAddr alias_start{alias_region_start};
  206. const VAddr alias_last{alias_region_end - 1};
  207. const VAddr heap_start{heap_region_start};
  208. const VAddr heap_last{heap_region_end - 1};
  209. const VAddr stack_start{stack_region_start};
  210. const VAddr stack_last{stack_region_end - 1};
  211. const VAddr kmap_start{kernel_map_region_start};
  212. const VAddr kmap_last{kernel_map_region_end - 1};
  213. ASSERT(alias_last < heap_start || heap_last < alias_start);
  214. ASSERT(alias_last < stack_start || stack_last < alias_start);
  215. ASSERT(alias_last < kmap_start || kmap_last < alias_start);
  216. ASSERT(heap_last < stack_start || stack_last < heap_start);
  217. ASSERT(heap_last < kmap_start || kmap_last < heap_start);
  218. current_heap_end = heap_region_start;
  219. max_heap_size = 0;
  220. mapped_physical_memory_size = 0;
  221. memory_pool = pool;
  222. page_table_impl.Resize(address_space_width, PageBits);
  223. return InitializeMemoryLayout(start, end);
  224. }
  225. ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state,
  226. KMemoryPermission perm) {
  227. const u64 size{num_pages * PageSize};
  228. // Validate the mapping request.
  229. R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
  230. // Lock the table.
  231. KScopedLightLock lk(general_lock);
  232. // Verify that the destination memory is unmapped.
  233. R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, KMemoryState::Free,
  234. KMemoryPermission::None, KMemoryPermission::None,
  235. KMemoryAttribute::None, KMemoryAttribute::None));
  236. KPageLinkedList pg;
  237. R_TRY(system.Kernel().MemoryManager().AllocateAndOpen(
  238. &pg, num_pages,
  239. KMemoryManager::EncodeOption(KMemoryManager::Pool::Application, allocation_option)));
  240. R_TRY(Operate(addr, num_pages, pg, OperationType::MapGroup));
  241. block_manager->Update(addr, num_pages, state, perm);
  242. return ResultSuccess;
  243. }
  244. ResultCode KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size) {
  245. // Validate the mapping request.
  246. R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
  247. ResultInvalidMemoryRegion);
  248. // Lock the table.
  249. KScopedLightLock lk(general_lock);
  250. // Verify that the source memory is normal heap.
  251. KMemoryState src_state{};
  252. KMemoryPermission src_perm{};
  253. std::size_t num_src_allocator_blocks{};
  254. R_TRY(this->CheckMemoryState(&src_state, &src_perm, nullptr, &num_src_allocator_blocks,
  255. src_address, size, KMemoryState::All, KMemoryState::Normal,
  256. KMemoryPermission::All, KMemoryPermission::UserReadWrite,
  257. KMemoryAttribute::All, KMemoryAttribute::None));
  258. // Verify that the destination memory is unmapped.
  259. std::size_t num_dst_allocator_blocks{};
  260. R_TRY(this->CheckMemoryState(&num_dst_allocator_blocks, dst_address, size, KMemoryState::All,
  261. KMemoryState::Free, KMemoryPermission::None,
  262. KMemoryPermission::None, KMemoryAttribute::None,
  263. KMemoryAttribute::None));
  264. // Map the code memory.
  265. {
  266. // Determine the number of pages being operated on.
  267. const std::size_t num_pages = size / PageSize;
  268. // Create page groups for the memory being mapped.
  269. KPageLinkedList pg;
  270. AddRegionToPages(src_address, num_pages, pg);
  271. // Reprotect the source as kernel-read/not mapped.
  272. const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead |
  273. KMemoryPermission::NotMapped);
  274. R_TRY(Operate(src_address, num_pages, new_perm, OperationType::ChangePermissions));
  275. // Ensure that we unprotect the source pages on failure.
  276. auto unprot_guard = SCOPE_GUARD({
  277. ASSERT(this->Operate(src_address, num_pages, src_perm, OperationType::ChangePermissions)
  278. .IsSuccess());
  279. });
  280. // Map the alias pages.
  281. R_TRY(MapPages(dst_address, pg, new_perm));
  282. // We successfully mapped the alias pages, so we don't need to unprotect the src pages on
  283. // failure.
  284. unprot_guard.Cancel();
  285. // Apply the memory block updates.
  286. block_manager->Update(src_address, num_pages, src_state, new_perm,
  287. KMemoryAttribute::Locked);
  288. block_manager->Update(dst_address, num_pages, KMemoryState::AliasCode, new_perm,
  289. KMemoryAttribute::None);
  290. }
  291. return ResultSuccess;
  292. }
  293. ResultCode KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size,
  294. ICacheInvalidationStrategy icache_invalidation_strategy) {
  295. // Validate the mapping request.
  296. R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
  297. ResultInvalidMemoryRegion);
  298. // Lock the table.
  299. KScopedLightLock lk(general_lock);
  300. // Verify that the source memory is locked normal heap.
  301. std::size_t num_src_allocator_blocks{};
  302. R_TRY(this->CheckMemoryState(std::addressof(num_src_allocator_blocks), src_address, size,
  303. KMemoryState::All, KMemoryState::Normal, KMemoryPermission::None,
  304. KMemoryPermission::None, KMemoryAttribute::All,
  305. KMemoryAttribute::Locked));
  306. // Verify that the destination memory is aliasable code.
  307. std::size_t num_dst_allocator_blocks{};
  308. R_TRY(this->CheckMemoryStateContiguous(
  309. std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState::FlagCanCodeAlias,
  310. KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
  311. KMemoryAttribute::All, KMemoryAttribute::None));
  312. // Determine whether any pages being unmapped are code.
  313. bool any_code_pages = false;
  314. {
  315. KMemoryBlockManager::const_iterator it = block_manager->FindIterator(dst_address);
  316. while (true) {
  317. // Get the memory info.
  318. const KMemoryInfo info = it->GetMemoryInfo();
  319. // Check if the memory has code flag.
  320. if ((info.GetState() & KMemoryState::FlagCode) != KMemoryState::None) {
  321. any_code_pages = true;
  322. break;
  323. }
  324. // Check if we're done.
  325. if (dst_address + size - 1 <= info.GetLastAddress()) {
  326. break;
  327. }
  328. // Advance.
  329. ++it;
  330. }
  331. }
  332. // Ensure that we maintain the instruction cache.
  333. bool reprotected_pages = false;
  334. SCOPE_EXIT({
  335. if (reprotected_pages && any_code_pages) {
  336. if (icache_invalidation_strategy == ICacheInvalidationStrategy::InvalidateRange) {
  337. system.InvalidateCpuInstructionCacheRange(dst_address, size);
  338. } else {
  339. system.InvalidateCpuInstructionCaches();
  340. }
  341. }
  342. });
  343. // Unmap.
  344. {
  345. // Determine the number of pages being operated on.
  346. const std::size_t num_pages = size / PageSize;
  347. // Unmap the aliased copy of the pages.
  348. R_TRY(Operate(dst_address, num_pages, KMemoryPermission::None, OperationType::Unmap));
  349. // Try to set the permissions for the source pages back to what they should be.
  350. R_TRY(Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
  351. OperationType::ChangePermissions));
  352. // Apply the memory block updates.
  353. block_manager->Update(dst_address, num_pages, KMemoryState::None);
  354. block_manager->Update(src_address, num_pages, KMemoryState::Normal,
  355. KMemoryPermission::UserReadWrite);
  356. // Note that we reprotected pages.
  357. reprotected_pages = true;
  358. }
  359. return ResultSuccess;
  360. }
  361. VAddr KPageTable::FindFreeArea(VAddr region_start, std::size_t region_num_pages,
  362. std::size_t num_pages, std::size_t alignment, std::size_t offset,
  363. std::size_t guard_pages) {
  364. VAddr address = 0;
  365. if (num_pages <= region_num_pages) {
  366. if (this->IsAslrEnabled()) {
  367. // Try to directly find a free area up to 8 times.
  368. for (std::size_t i = 0; i < 8; i++) {
  369. const std::size_t random_offset =
  370. KSystemControl::GenerateRandomRange(
  371. 0, (region_num_pages - num_pages - guard_pages) * PageSize / alignment) *
  372. alignment;
  373. const VAddr candidate =
  374. Common::AlignDown((region_start + random_offset), alignment) + offset;
  375. KMemoryInfo info = this->QueryInfoImpl(candidate);
  376. if (info.state != KMemoryState::Free) {
  377. continue;
  378. }
  379. if (region_start > candidate) {
  380. continue;
  381. }
  382. if (info.GetAddress() + guard_pages * PageSize > candidate) {
  383. continue;
  384. }
  385. const VAddr candidate_end = candidate + (num_pages + guard_pages) * PageSize - 1;
  386. if (candidate_end > info.GetLastAddress()) {
  387. continue;
  388. }
  389. if (candidate_end > region_start + region_num_pages * PageSize - 1) {
  390. continue;
  391. }
  392. address = candidate;
  393. break;
  394. }
  395. // Fall back to finding the first free area with a random offset.
  396. if (address == 0) {
  397. // NOTE: Nintendo does not account for guard pages here.
  398. // This may theoretically cause an offset to be chosen that cannot be mapped. We
  399. // will account for guard pages.
  400. const std::size_t offset_pages = KSystemControl::GenerateRandomRange(
  401. 0, region_num_pages - num_pages - guard_pages);
  402. address = block_manager->FindFreeArea(region_start + offset_pages * PageSize,
  403. region_num_pages - offset_pages, num_pages,
  404. alignment, offset, guard_pages);
  405. }
  406. }
  407. // Find the first free area.
  408. if (address == 0) {
  409. address = block_manager->FindFreeArea(region_start, region_num_pages, num_pages,
  410. alignment, offset, guard_pages);
  411. }
  412. }
  413. return address;
  414. }
  415. ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages) {
  416. ASSERT(this->IsLockedByCurrentThread());
  417. const size_t size = num_pages * PageSize;
  418. // We're making a new group, not adding to an existing one.
  419. R_UNLESS(pg.Empty(), ResultInvalidCurrentMemory);
  420. // Begin traversal.
  421. Common::PageTable::TraversalContext context;
  422. Common::PageTable::TraversalEntry next_entry;
  423. R_UNLESS(page_table_impl.BeginTraversal(next_entry, context, addr), ResultInvalidCurrentMemory);
  424. // Prepare tracking variables.
  425. PAddr cur_addr = next_entry.phys_addr;
  426. size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
  427. size_t tot_size = cur_size;
  428. // Iterate, adding to group as we go.
  429. const auto& memory_layout = system.Kernel().MemoryLayout();
  430. while (tot_size < size) {
  431. R_UNLESS(page_table_impl.ContinueTraversal(next_entry, context),
  432. ResultInvalidCurrentMemory);
  433. if (next_entry.phys_addr != (cur_addr + cur_size)) {
  434. const size_t cur_pages = cur_size / PageSize;
  435. R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory);
  436. R_TRY(pg.AddBlock(cur_addr, cur_pages));
  437. cur_addr = next_entry.phys_addr;
  438. cur_size = next_entry.block_size;
  439. } else {
  440. cur_size += next_entry.block_size;
  441. }
  442. tot_size += next_entry.block_size;
  443. }
  444. // Ensure we add the right amount for the last block.
  445. if (tot_size > size) {
  446. cur_size -= (tot_size - size);
  447. }
  448. // Add the last block.
  449. const size_t cur_pages = cur_size / PageSize;
  450. R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory);
  451. R_TRY(pg.AddBlock(cur_addr, cur_pages));
  452. return ResultSuccess;
  453. }
  454. bool KPageTable::IsValidPageGroup(const KPageLinkedList& pg_ll, VAddr addr, size_t num_pages) {
  455. ASSERT(this->IsLockedByCurrentThread());
  456. const size_t size = num_pages * PageSize;
  457. const auto& pg = pg_ll.Nodes();
  458. const auto& memory_layout = system.Kernel().MemoryLayout();
  459. // Empty groups are necessarily invalid.
  460. if (pg.empty()) {
  461. return false;
  462. }
  463. // We're going to validate that the group we'd expect is the group we see.
  464. auto cur_it = pg.begin();
  465. PAddr cur_block_address = cur_it->GetAddress();
  466. size_t cur_block_pages = cur_it->GetNumPages();
  467. auto UpdateCurrentIterator = [&]() {
  468. if (cur_block_pages == 0) {
  469. if ((++cur_it) == pg.end()) {
  470. return false;
  471. }
  472. cur_block_address = cur_it->GetAddress();
  473. cur_block_pages = cur_it->GetNumPages();
  474. }
  475. return true;
  476. };
  477. // Begin traversal.
  478. Common::PageTable::TraversalContext context;
  479. Common::PageTable::TraversalEntry next_entry;
  480. if (!page_table_impl.BeginTraversal(next_entry, context, addr)) {
  481. return false;
  482. }
  483. // Prepare tracking variables.
  484. PAddr cur_addr = next_entry.phys_addr;
  485. size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
  486. size_t tot_size = cur_size;
  487. // Iterate, comparing expected to actual.
  488. while (tot_size < size) {
  489. if (!page_table_impl.ContinueTraversal(next_entry, context)) {
  490. return false;
  491. }
  492. if (next_entry.phys_addr != (cur_addr + cur_size)) {
  493. const size_t cur_pages = cur_size / PageSize;
  494. if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) {
  495. return false;
  496. }
  497. if (!UpdateCurrentIterator()) {
  498. return false;
  499. }
  500. if (cur_block_address != cur_addr || cur_block_pages < cur_pages) {
  501. return false;
  502. }
  503. cur_block_address += cur_size;
  504. cur_block_pages -= cur_pages;
  505. cur_addr = next_entry.phys_addr;
  506. cur_size = next_entry.block_size;
  507. } else {
  508. cur_size += next_entry.block_size;
  509. }
  510. tot_size += next_entry.block_size;
  511. }
  512. // Ensure we compare the right amount for the last block.
  513. if (tot_size > size) {
  514. cur_size -= (tot_size - size);
  515. }
  516. if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) {
  517. return false;
  518. }
  519. if (!UpdateCurrentIterator()) {
  520. return false;
  521. }
  522. return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize);
  523. }
  524. ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
  525. KPageTable& src_page_table, VAddr src_addr) {
  526. KScopedLightLock lk(general_lock);
  527. const std::size_t num_pages{size / PageSize};
  528. // Check that the memory is mapped in the destination process.
  529. size_t num_allocator_blocks;
  530. R_TRY(CheckMemoryState(&num_allocator_blocks, dst_addr, size, KMemoryState::All,
  531. KMemoryState::SharedCode, KMemoryPermission::UserReadWrite,
  532. KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
  533. KMemoryAttribute::None));
  534. // Check that the memory is mapped in the source process.
  535. R_TRY(src_page_table.CheckMemoryState(src_addr, size, KMemoryState::FlagCanMapProcess,
  536. KMemoryState::FlagCanMapProcess, KMemoryPermission::None,
  537. KMemoryPermission::None, KMemoryAttribute::All,
  538. KMemoryAttribute::None));
  539. CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
  540. // Apply the memory block update.
  541. block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
  542. KMemoryAttribute::None);
  543. system.InvalidateCpuInstructionCaches();
  544. return ResultSuccess;
  545. }
  546. ResultCode KPageTable::MapPhysicalMemory(VAddr address, std::size_t size) {
  547. // Lock the physical memory lock.
  548. KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
  549. // Calculate the last address for convenience.
  550. const VAddr last_address = address + size - 1;
  551. // Define iteration variables.
  552. VAddr cur_address;
  553. std::size_t mapped_size;
  554. // The entire mapping process can be retried.
  555. while (true) {
  556. // Check if the memory is already mapped.
  557. {
  558. // Lock the table.
  559. KScopedLightLock lk(general_lock);
  560. // Iterate over the memory.
  561. cur_address = address;
  562. mapped_size = 0;
  563. auto it = block_manager->FindIterator(cur_address);
  564. while (true) {
  565. // Check that the iterator is valid.
  566. ASSERT(it != block_manager->end());
  567. // Get the memory info.
  568. const KMemoryInfo info = it->GetMemoryInfo();
  569. // Check if we're done.
  570. if (last_address <= info.GetLastAddress()) {
  571. if (info.GetState() != KMemoryState::Free) {
  572. mapped_size += (last_address + 1 - cur_address);
  573. }
  574. break;
  575. }
  576. // Track the memory if it's mapped.
  577. if (info.GetState() != KMemoryState::Free) {
  578. mapped_size += VAddr(info.GetEndAddress()) - cur_address;
  579. }
  580. // Advance.
  581. cur_address = info.GetEndAddress();
  582. ++it;
  583. }
  584. // If the size mapped is the size requested, we've nothing to do.
  585. R_SUCCEED_IF(size == mapped_size);
  586. }
  587. // Allocate and map the memory.
  588. {
  589. // Reserve the memory from the process resource limit.
  590. KScopedResourceReservation memory_reservation(
  591. system.Kernel().CurrentProcess()->GetResourceLimit(),
  592. LimitableResource::PhysicalMemory, size - mapped_size);
  593. R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
  594. // Allocate pages for the new memory.
  595. KPageLinkedList pg;
  596. R_TRY(system.Kernel().MemoryManager().AllocateAndOpenForProcess(
  597. &pg, (size - mapped_size) / PageSize,
  598. KMemoryManager::EncodeOption(memory_pool, allocation_option), 0, 0));
  599. // Map the memory.
  600. {
  601. // Lock the table.
  602. KScopedLightLock lk(general_lock);
  603. size_t num_allocator_blocks = 0;
  604. // Verify that nobody has mapped memory since we first checked.
  605. {
  606. // Iterate over the memory.
  607. size_t checked_mapped_size = 0;
  608. cur_address = address;
  609. auto it = block_manager->FindIterator(cur_address);
  610. while (true) {
  611. // Check that the iterator is valid.
  612. ASSERT(it != block_manager->end());
  613. // Get the memory info.
  614. const KMemoryInfo info = it->GetMemoryInfo();
  615. const bool is_free = info.GetState() == KMemoryState::Free;
  616. if (is_free) {
  617. if (info.GetAddress() < address) {
  618. ++num_allocator_blocks;
  619. }
  620. if (last_address < info.GetLastAddress()) {
  621. ++num_allocator_blocks;
  622. }
  623. }
  624. // Check if we're done.
  625. if (last_address <= info.GetLastAddress()) {
  626. if (!is_free) {
  627. checked_mapped_size += (last_address + 1 - cur_address);
  628. }
  629. break;
  630. }
  631. // Track the memory if it's mapped.
  632. if (!is_free) {
  633. checked_mapped_size += VAddr(info.GetEndAddress()) - cur_address;
  634. }
  635. // Advance.
  636. cur_address = info.GetEndAddress();
  637. ++it;
  638. }
  639. // If the size now isn't what it was before, somebody mapped or unmapped
  640. // concurrently. If this happened, retry.
  641. if (mapped_size != checked_mapped_size) {
  642. continue;
  643. }
  644. }
  645. // Reset the current tracking address, and make sure we clean up on failure.
  646. cur_address = address;
  647. auto unmap_guard = detail::ScopeExit([&] {
  648. if (cur_address > address) {
  649. const VAddr last_unmap_address = cur_address - 1;
  650. // Iterate, unmapping the pages.
  651. cur_address = address;
  652. auto it = block_manager->FindIterator(cur_address);
  653. while (true) {
  654. // Check that the iterator is valid.
  655. ASSERT(it != block_manager->end());
  656. // Get the memory info.
  657. const KMemoryInfo info = it->GetMemoryInfo();
  658. // If the memory state is free, we mapped it and need to unmap it.
  659. if (info.GetState() == KMemoryState::Free) {
  660. // Determine the range to unmap.
  661. const size_t cur_pages =
  662. std::min(VAddr(info.GetEndAddress()) - cur_address,
  663. last_unmap_address + 1 - cur_address) /
  664. PageSize;
  665. // Unmap.
  666. ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None,
  667. OperationType::Unmap)
  668. .IsSuccess());
  669. }
  670. // Check if we're done.
  671. if (last_unmap_address <= info.GetLastAddress()) {
  672. break;
  673. }
  674. // Advance.
  675. cur_address = info.GetEndAddress();
  676. ++it;
  677. }
  678. }
  679. });
  680. // Iterate over the memory.
  681. auto pg_it = pg.Nodes().begin();
  682. PAddr pg_phys_addr = pg_it->GetAddress();
  683. size_t pg_pages = pg_it->GetNumPages();
  684. auto it = block_manager->FindIterator(cur_address);
  685. while (true) {
  686. // Check that the iterator is valid.
  687. ASSERT(it != block_manager->end());
  688. // Get the memory info.
  689. const KMemoryInfo info = it->GetMemoryInfo();
  690. // If it's unmapped, we need to map it.
  691. if (info.GetState() == KMemoryState::Free) {
  692. // Determine the range to map.
  693. size_t map_pages = std::min(VAddr(info.GetEndAddress()) - cur_address,
  694. last_address + 1 - cur_address) /
  695. PageSize;
  696. // While we have pages to map, map them.
  697. while (map_pages > 0) {
  698. // Check if we're at the end of the physical block.
  699. if (pg_pages == 0) {
  700. // Ensure there are more pages to map.
  701. ASSERT(pg_it != pg.Nodes().end());
  702. // Advance our physical block.
  703. ++pg_it;
  704. pg_phys_addr = pg_it->GetAddress();
  705. pg_pages = pg_it->GetNumPages();
  706. }
  707. // Map whatever we can.
  708. const size_t cur_pages = std::min(pg_pages, map_pages);
  709. R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite,
  710. OperationType::Map, pg_phys_addr));
  711. // Advance.
  712. cur_address += cur_pages * PageSize;
  713. map_pages -= cur_pages;
  714. pg_phys_addr += cur_pages * PageSize;
  715. pg_pages -= cur_pages;
  716. }
  717. }
  718. // Check if we're done.
  719. if (last_address <= info.GetLastAddress()) {
  720. break;
  721. }
  722. // Advance.
  723. cur_address = info.GetEndAddress();
  724. ++it;
  725. }
  726. // We succeeded, so commit the memory reservation.
  727. memory_reservation.Commit();
  728. // Increase our tracked mapped size.
  729. mapped_physical_memory_size += (size - mapped_size);
  730. // Update the relevant memory blocks.
  731. block_manager->Update(address, size / PageSize, KMemoryState::Free,
  732. KMemoryPermission::None, KMemoryAttribute::None,
  733. KMemoryState::Normal, KMemoryPermission::UserReadWrite,
  734. KMemoryAttribute::None);
  735. // Cancel our guard.
  736. unmap_guard.Cancel();
  737. return ResultSuccess;
  738. }
  739. }
  740. }
  741. }
  742. ResultCode KPageTable::UnmapPhysicalMemory(VAddr address, std::size_t size) {
  743. // Lock the physical memory lock.
  744. KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
  745. // Lock the table.
  746. KScopedLightLock lk(general_lock);
  747. // Calculate the last address for convenience.
  748. const VAddr last_address = address + size - 1;
  749. // Define iteration variables.
  750. VAddr cur_address = 0;
  751. std::size_t mapped_size = 0;
  752. std::size_t num_allocator_blocks = 0;
  753. // Check if the memory is mapped.
  754. {
  755. // Iterate over the memory.
  756. cur_address = address;
  757. mapped_size = 0;
  758. auto it = block_manager->FindIterator(cur_address);
  759. while (true) {
  760. // Check that the iterator is valid.
  761. ASSERT(it != block_manager->end());
  762. // Get the memory info.
  763. const KMemoryInfo info = it->GetMemoryInfo();
  764. // Verify the memory's state.
  765. const bool is_normal = info.GetState() == KMemoryState::Normal &&
  766. info.GetAttribute() == KMemoryAttribute::None;
  767. const bool is_free = info.GetState() == KMemoryState::Free;
  768. R_UNLESS(is_normal || is_free, ResultInvalidCurrentMemory);
  769. if (is_normal) {
  770. R_UNLESS(info.GetAttribute() == KMemoryAttribute::None, ResultInvalidCurrentMemory);
  771. if (info.GetAddress() < address) {
  772. ++num_allocator_blocks;
  773. }
  774. if (last_address < info.GetLastAddress()) {
  775. ++num_allocator_blocks;
  776. }
  777. }
  778. // Check if we're done.
  779. if (last_address <= info.GetLastAddress()) {
  780. if (is_normal) {
  781. mapped_size += (last_address + 1 - cur_address);
  782. }
  783. break;
  784. }
  785. // Track the memory if it's mapped.
  786. if (is_normal) {
  787. mapped_size += VAddr(info.GetEndAddress()) - cur_address;
  788. }
  789. // Advance.
  790. cur_address = info.GetEndAddress();
  791. ++it;
  792. }
  793. // If there's nothing mapped, we've nothing to do.
  794. R_SUCCEED_IF(mapped_size == 0);
  795. }
  796. // Make a page group for the unmap region.
  797. KPageLinkedList pg;
  798. {
  799. auto& impl = this->PageTableImpl();
  800. // Begin traversal.
  801. Common::PageTable::TraversalContext context;
  802. Common::PageTable::TraversalEntry cur_entry = {.phys_addr = 0, .block_size = 0};
  803. bool cur_valid = false;
  804. Common::PageTable::TraversalEntry next_entry;
  805. bool next_valid = false;
  806. size_t tot_size = 0;
  807. cur_address = address;
  808. next_valid = impl.BeginTraversal(next_entry, context, cur_address);
  809. next_entry.block_size =
  810. (next_entry.block_size - (next_entry.phys_addr & (next_entry.block_size - 1)));
  811. // Iterate, building the group.
  812. while (true) {
  813. if ((!next_valid && !cur_valid) ||
  814. (next_valid && cur_valid &&
  815. next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) {
  816. cur_entry.block_size += next_entry.block_size;
  817. } else {
  818. if (cur_valid) {
  819. // ASSERT(IsHeapPhysicalAddress(cur_entry.phys_addr));
  820. R_TRY(pg.AddBlock(cur_entry.phys_addr, cur_entry.block_size / PageSize));
  821. }
  822. // Update tracking variables.
  823. tot_size += cur_entry.block_size;
  824. cur_entry = next_entry;
  825. cur_valid = next_valid;
  826. }
  827. if (cur_entry.block_size + tot_size >= size) {
  828. break;
  829. }
  830. next_valid = impl.ContinueTraversal(next_entry, context);
  831. }
  832. // Add the last block.
  833. if (cur_valid) {
  834. // ASSERT(IsHeapPhysicalAddress(cur_entry.phys_addr));
  835. R_TRY(pg.AddBlock(cur_entry.phys_addr, (size - tot_size) / PageSize));
  836. }
  837. }
  838. ASSERT(pg.GetNumPages() == mapped_size / PageSize);
  839. // Reset the current tracking address, and make sure we clean up on failure.
  840. cur_address = address;
  841. auto remap_guard = detail::ScopeExit([&] {
  842. if (cur_address > address) {
  843. const VAddr last_map_address = cur_address - 1;
  844. cur_address = address;
  845. // Iterate over the memory we unmapped.
  846. auto it = block_manager->FindIterator(cur_address);
  847. auto pg_it = pg.Nodes().begin();
  848. PAddr pg_phys_addr = pg_it->GetAddress();
  849. size_t pg_pages = pg_it->GetNumPages();
  850. while (true) {
  851. // Get the memory info for the pages we unmapped, convert to property.
  852. const KMemoryInfo info = it->GetMemoryInfo();
  853. // If the memory is normal, we unmapped it and need to re-map it.
  854. if (info.GetState() == KMemoryState::Normal) {
  855. // Determine the range to map.
  856. size_t map_pages = std::min(VAddr(info.GetEndAddress()) - cur_address,
  857. last_map_address + 1 - cur_address) /
  858. PageSize;
  859. // While we have pages to map, map them.
  860. while (map_pages > 0) {
  861. // Check if we're at the end of the physical block.
  862. if (pg_pages == 0) {
  863. // Ensure there are more pages to map.
  864. ASSERT(pg_it != pg.Nodes().end());
  865. // Advance our physical block.
  866. ++pg_it;
  867. pg_phys_addr = pg_it->GetAddress();
  868. pg_pages = pg_it->GetNumPages();
  869. }
  870. // Map whatever we can.
  871. const size_t cur_pages = std::min(pg_pages, map_pages);
  872. ASSERT(this->Operate(cur_address, cur_pages, info.GetPermission(),
  873. OperationType::Map, pg_phys_addr) == ResultSuccess);
  874. // Advance.
  875. cur_address += cur_pages * PageSize;
  876. map_pages -= cur_pages;
  877. pg_phys_addr += cur_pages * PageSize;
  878. pg_pages -= cur_pages;
  879. }
  880. }
  881. // Check if we're done.
  882. if (last_map_address <= info.GetLastAddress()) {
  883. break;
  884. }
  885. // Advance.
  886. ++it;
  887. }
  888. }
  889. });
  890. // Iterate over the memory, unmapping as we go.
  891. auto it = block_manager->FindIterator(cur_address);
  892. while (true) {
  893. // Check that the iterator is valid.
  894. ASSERT(it != block_manager->end());
  895. // Get the memory info.
  896. const KMemoryInfo info = it->GetMemoryInfo();
  897. // If the memory state is normal, we need to unmap it.
  898. if (info.GetState() == KMemoryState::Normal) {
  899. // Determine the range to unmap.
  900. const size_t cur_pages = std::min(VAddr(info.GetEndAddress()) - cur_address,
  901. last_address + 1 - cur_address) /
  902. PageSize;
  903. // Unmap.
  904. R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap));
  905. }
  906. // Check if we're done.
  907. if (last_address <= info.GetLastAddress()) {
  908. break;
  909. }
  910. // Advance.
  911. cur_address = info.GetEndAddress();
  912. ++it;
  913. }
  914. // Release the memory resource.
  915. mapped_physical_memory_size -= mapped_size;
  916. auto process{system.Kernel().CurrentProcess()};
  917. process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size);
  918. // Update memory blocks.
  919. block_manager->Update(address, size / PageSize, KMemoryState::Free, KMemoryPermission::None,
  920. KMemoryAttribute::None);
  921. // TODO(bunnei): This is a workaround until the next set of changes, where we add reference
  922. // counting for mapped pages. Until then, we must manually close the reference to the page
  923. // group.
  924. system.Kernel().MemoryManager().Close(pg);
  925. // We succeeded.
  926. remap_guard.Cancel();
  927. return ResultSuccess;
  928. }
  929. ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
  930. KScopedLightLock lk(general_lock);
  931. KMemoryState src_state{};
  932. CASCADE_CODE(CheckMemoryState(
  933. &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
  934. KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::UserReadWrite,
  935. KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
  936. if (IsRegionMapped(dst_addr, size)) {
  937. return ResultInvalidCurrentMemory;
  938. }
  939. KPageLinkedList page_linked_list;
  940. const std::size_t num_pages{size / PageSize};
  941. AddRegionToPages(src_addr, num_pages, page_linked_list);
  942. {
  943. auto block_guard = detail::ScopeExit([&] {
  944. Operate(src_addr, num_pages, KMemoryPermission::UserReadWrite,
  945. OperationType::ChangePermissions);
  946. });
  947. CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None,
  948. OperationType::ChangePermissions));
  949. CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::UserReadWrite));
  950. block_guard.Cancel();
  951. }
  952. block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None,
  953. KMemoryAttribute::Locked);
  954. block_manager->Update(dst_addr, num_pages, KMemoryState::Stack,
  955. KMemoryPermission::UserReadWrite);
  956. return ResultSuccess;
  957. }
  958. ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
  959. KScopedLightLock lk(general_lock);
  960. KMemoryState src_state{};
  961. CASCADE_CODE(CheckMemoryState(
  962. &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
  963. KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None,
  964. KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
  965. KMemoryPermission dst_perm{};
  966. CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, nullptr, dst_addr, size,
  967. KMemoryState::All, KMemoryState::Stack, KMemoryPermission::None,
  968. KMemoryPermission::None, KMemoryAttribute::Mask,
  969. KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
  970. KPageLinkedList src_pages;
  971. KPageLinkedList dst_pages;
  972. const std::size_t num_pages{size / PageSize};
  973. AddRegionToPages(src_addr, num_pages, src_pages);
  974. AddRegionToPages(dst_addr, num_pages, dst_pages);
  975. if (!dst_pages.IsEqual(src_pages)) {
  976. return ResultInvalidMemoryRegion;
  977. }
  978. {
  979. auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); });
  980. CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
  981. CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::UserReadWrite,
  982. OperationType::ChangePermissions));
  983. block_guard.Cancel();
  984. }
  985. block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::UserReadWrite);
  986. block_manager->Update(dst_addr, num_pages, KMemoryState::Free);
  987. return ResultSuccess;
  988. }
  989. ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
  990. KMemoryPermission perm) {
  991. ASSERT(this->IsLockedByCurrentThread());
  992. VAddr cur_addr{addr};
  993. for (const auto& node : page_linked_list.Nodes()) {
  994. if (const auto result{
  995. Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
  996. result.IsError()) {
  997. const std::size_t num_pages{(addr - cur_addr) / PageSize};
  998. ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)
  999. .IsSuccess());
  1000. return result;
  1001. }
  1002. cur_addr += node.GetNumPages() * PageSize;
  1003. }
  1004. return ResultSuccess;
  1005. }
  1006. ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list,
  1007. KMemoryState state, KMemoryPermission perm) {
  1008. // Check that the map is in range.
  1009. const std::size_t num_pages{page_linked_list.GetNumPages()};
  1010. const std::size_t size{num_pages * PageSize};
  1011. R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
  1012. // Lock the table.
  1013. KScopedLightLock lk(general_lock);
  1014. // Check the memory state.
  1015. R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
  1016. KMemoryPermission::None, KMemoryPermission::None,
  1017. KMemoryAttribute::None, KMemoryAttribute::None));
  1018. // Map the pages.
  1019. R_TRY(MapPages(address, page_linked_list, perm));
  1020. // Update the blocks.
  1021. block_manager->Update(address, num_pages, state, perm);
  1022. return ResultSuccess;
  1023. }
  1024. ResultCode KPageTable::MapPages(VAddr* out_addr, std::size_t num_pages, std::size_t alignment,
  1025. PAddr phys_addr, bool is_pa_valid, VAddr region_start,
  1026. std::size_t region_num_pages, KMemoryState state,
  1027. KMemoryPermission perm) {
  1028. ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize);
  1029. // Ensure this is a valid map request.
  1030. R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state),
  1031. ResultInvalidCurrentMemory);
  1032. R_UNLESS(num_pages < region_num_pages, ResultOutOfMemory);
  1033. // Lock the table.
  1034. KScopedLightLock lk(general_lock);
  1035. // Find a random address to map at.
  1036. VAddr addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0,
  1037. this->GetNumGuardPages());
  1038. R_UNLESS(addr != 0, ResultOutOfMemory);
  1039. ASSERT(Common::IsAligned(addr, alignment));
  1040. ASSERT(this->CanContain(addr, num_pages * PageSize, state));
  1041. ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
  1042. KMemoryPermission::None, KMemoryPermission::None,
  1043. KMemoryAttribute::None, KMemoryAttribute::None)
  1044. .IsSuccess());
  1045. // Perform mapping operation.
  1046. if (is_pa_valid) {
  1047. R_TRY(this->Operate(addr, num_pages, perm, OperationType::Map, phys_addr));
  1048. } else {
  1049. UNIMPLEMENTED();
  1050. }
  1051. // Update the blocks.
  1052. block_manager->Update(addr, num_pages, state, perm);
  1053. // We successfully mapped the pages.
  1054. *out_addr = addr;
  1055. return ResultSuccess;
  1056. }
  1057. ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) {
  1058. ASSERT(this->IsLockedByCurrentThread());
  1059. VAddr cur_addr{addr};
  1060. for (const auto& node : page_linked_list.Nodes()) {
  1061. if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None,
  1062. OperationType::Unmap)};
  1063. result.IsError()) {
  1064. return result;
  1065. }
  1066. cur_addr += node.GetNumPages() * PageSize;
  1067. }
  1068. return ResultSuccess;
  1069. }
  1070. ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
  1071. KMemoryState state) {
  1072. // Check that the unmap is in range.
  1073. const std::size_t num_pages{page_linked_list.GetNumPages()};
  1074. const std::size_t size{num_pages * PageSize};
  1075. R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
  1076. // Lock the table.
  1077. KScopedLightLock lk(general_lock);
  1078. // Check the memory state.
  1079. R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, state, KMemoryPermission::None,
  1080. KMemoryPermission::None, KMemoryAttribute::All,
  1081. KMemoryAttribute::None));
  1082. // Perform the unmap.
  1083. R_TRY(UnmapPages(addr, page_linked_list));
  1084. // Update the blocks.
  1085. block_manager->Update(addr, num_pages, state, KMemoryPermission::None);
  1086. return ResultSuccess;
  1087. }
  1088. ResultCode KPageTable::UnmapPages(VAddr address, std::size_t num_pages, KMemoryState state) {
  1089. // Check that the unmap is in range.
  1090. const std::size_t size = num_pages * PageSize;
  1091. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  1092. // Lock the table.
  1093. KScopedLightLock lk(general_lock);
  1094. // Check the memory state.
  1095. std::size_t num_allocator_blocks{};
  1096. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
  1097. KMemoryState::All, state, KMemoryPermission::None,
  1098. KMemoryPermission::None, KMemoryAttribute::All,
  1099. KMemoryAttribute::None));
  1100. // Perform the unmap.
  1101. R_TRY(Operate(address, num_pages, KMemoryPermission::None, OperationType::Unmap));
  1102. // Update the blocks.
  1103. block_manager->Update(address, num_pages, KMemoryState::Free, KMemoryPermission::None);
  1104. return ResultSuccess;
  1105. }
  1106. ResultCode KPageTable::MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages,
  1107. KMemoryState state_mask, KMemoryState state,
  1108. KMemoryPermission perm_mask, KMemoryPermission perm,
  1109. KMemoryAttribute attr_mask, KMemoryAttribute attr) {
  1110. // Ensure that the page group isn't null.
  1111. ASSERT(out != nullptr);
  1112. // Make sure that the region we're mapping is valid for the table.
  1113. const size_t size = num_pages * PageSize;
  1114. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  1115. // Lock the table.
  1116. KScopedLightLock lk(general_lock);
  1117. // Check if state allows us to create the group.
  1118. R_TRY(this->CheckMemoryState(address, size, state_mask | KMemoryState::FlagReferenceCounted,
  1119. state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
  1120. attr_mask, attr));
  1121. // Create a new page group for the region.
  1122. R_TRY(this->MakePageGroup(*out, address, num_pages));
  1123. return ResultSuccess;
  1124. }
  1125. ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
  1126. Svc::MemoryPermission svc_perm) {
  1127. const size_t num_pages = size / PageSize;
  1128. // Lock the table.
  1129. KScopedLightLock lk(general_lock);
  1130. // Verify we can change the memory permission.
  1131. KMemoryState old_state;
  1132. KMemoryPermission old_perm;
  1133. size_t num_allocator_blocks;
  1134. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr,
  1135. std::addressof(num_allocator_blocks), addr, size,
  1136. KMemoryState::FlagCode, KMemoryState::FlagCode,
  1137. KMemoryPermission::None, KMemoryPermission::None,
  1138. KMemoryAttribute::All, KMemoryAttribute::None));
  1139. // Determine new perm/state.
  1140. const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
  1141. KMemoryState new_state = old_state;
  1142. const bool is_w = (new_perm & KMemoryPermission::UserWrite) == KMemoryPermission::UserWrite;
  1143. const bool is_x = (new_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute;
  1144. const bool was_x =
  1145. (old_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute;
  1146. ASSERT(!(is_w && is_x));
  1147. if (is_w) {
  1148. switch (old_state) {
  1149. case KMemoryState::Code:
  1150. new_state = KMemoryState::CodeData;
  1151. break;
  1152. case KMemoryState::AliasCode:
  1153. new_state = KMemoryState::AliasCodeData;
  1154. break;
  1155. default:
  1156. ASSERT(false);
  1157. }
  1158. }
  1159. // Succeed if there's nothing to do.
  1160. R_SUCCEED_IF(old_perm == new_perm && old_state == new_state);
  1161. // Perform mapping operation.
  1162. const auto operation =
  1163. was_x ? OperationType::ChangePermissionsAndRefresh : OperationType::ChangePermissions;
  1164. R_TRY(Operate(addr, num_pages, new_perm, operation));
  1165. // Update the blocks.
  1166. block_manager->Update(addr, num_pages, new_state, new_perm, KMemoryAttribute::None);
  1167. // Ensure cache coherency, if we're setting pages as executable.
  1168. if (is_x) {
  1169. system.InvalidateCpuInstructionCacheRange(addr, size);
  1170. }
  1171. return ResultSuccess;
  1172. }
  1173. KMemoryInfo KPageTable::QueryInfoImpl(VAddr addr) {
  1174. KScopedLightLock lk(general_lock);
  1175. return block_manager->FindBlock(addr).GetMemoryInfo();
  1176. }
  1177. KMemoryInfo KPageTable::QueryInfo(VAddr addr) {
  1178. if (!Contains(addr, 1)) {
  1179. return {address_space_end, 0 - address_space_end, KMemoryState::Inaccessible,
  1180. KMemoryPermission::None, KMemoryAttribute::None, KMemoryPermission::None};
  1181. }
  1182. return QueryInfoImpl(addr);
  1183. }
  1184. ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) {
  1185. KScopedLightLock lk(general_lock);
  1186. KMemoryState state{};
  1187. KMemoryAttribute attribute{};
  1188. R_TRY(CheckMemoryState(&state, nullptr, &attribute, nullptr, addr, size,
  1189. KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
  1190. KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
  1191. KMemoryPermission::All, KMemoryPermission::UserReadWrite,
  1192. KMemoryAttribute::Mask, KMemoryAttribute::None,
  1193. KMemoryAttribute::IpcAndDeviceMapped));
  1194. block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked);
  1195. return ResultSuccess;
  1196. }
  1197. ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
  1198. KScopedLightLock lk(general_lock);
  1199. KMemoryState state{};
  1200. R_TRY(CheckMemoryState(&state, nullptr, nullptr, nullptr, addr, size,
  1201. KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
  1202. KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
  1203. KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
  1204. KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
  1205. block_manager->Update(addr, size / PageSize, state, KMemoryPermission::UserReadWrite);
  1206. return ResultSuccess;
  1207. }
  1208. ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
  1209. Svc::MemoryPermission svc_perm) {
  1210. const size_t num_pages = size / PageSize;
  1211. // Lock the table.
  1212. KScopedLightLock lk(general_lock);
  1213. // Verify we can change the memory permission.
  1214. KMemoryState old_state;
  1215. KMemoryPermission old_perm;
  1216. R_TRY(this->CheckMemoryState(
  1217. std::addressof(old_state), std::addressof(old_perm), nullptr, nullptr, addr, size,
  1218. KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None,
  1219. KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
  1220. // Determine new perm.
  1221. const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
  1222. R_SUCCEED_IF(old_perm == new_perm);
  1223. // Perform mapping operation.
  1224. R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
  1225. // Update the blocks.
  1226. block_manager->Update(addr, num_pages, old_state, new_perm, KMemoryAttribute::None);
  1227. return ResultSuccess;
  1228. }
  1229. ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr) {
  1230. const size_t num_pages = size / PageSize;
  1231. ASSERT((static_cast<KMemoryAttribute>(mask) | KMemoryAttribute::SetMask) ==
  1232. KMemoryAttribute::SetMask);
  1233. // Lock the table.
  1234. KScopedLightLock lk(general_lock);
  1235. // Verify we can change the memory attribute.
  1236. KMemoryState old_state;
  1237. KMemoryPermission old_perm;
  1238. KMemoryAttribute old_attr;
  1239. size_t num_allocator_blocks;
  1240. constexpr auto AttributeTestMask =
  1241. ~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared);
  1242. R_TRY(this->CheckMemoryState(
  1243. std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr),
  1244. std::addressof(num_allocator_blocks), addr, size, KMemoryState::FlagCanChangeAttribute,
  1245. KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
  1246. AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
  1247. // Determine the new attribute.
  1248. const KMemoryAttribute new_attr =
  1249. static_cast<KMemoryAttribute>(((old_attr & static_cast<KMemoryAttribute>(~mask)) |
  1250. static_cast<KMemoryAttribute>(attr & mask)));
  1251. // Perform operation.
  1252. this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh);
  1253. // Update the blocks.
  1254. block_manager->Update(addr, num_pages, old_state, old_perm, new_attr);
  1255. return ResultSuccess;
  1256. }
  1257. ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
  1258. // Lock the table.
  1259. KScopedLightLock lk(general_lock);
  1260. // Only process page tables are allowed to set heap size.
  1261. ASSERT(!this->IsKernel());
  1262. max_heap_size = size;
  1263. return ResultSuccess;
  1264. }
  1265. ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
  1266. // Lock the physical memory mutex.
  1267. KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
  1268. // Try to perform a reduction in heap, instead of an extension.
  1269. VAddr cur_address{};
  1270. std::size_t allocation_size{};
  1271. {
  1272. // Lock the table.
  1273. KScopedLightLock lk(general_lock);
  1274. // Validate that setting heap size is possible at all.
  1275. R_UNLESS(!is_kernel, ResultOutOfMemory);
  1276. R_UNLESS(size <= static_cast<std::size_t>(heap_region_end - heap_region_start),
  1277. ResultOutOfMemory);
  1278. R_UNLESS(size <= max_heap_size, ResultOutOfMemory);
  1279. if (size < GetHeapSize()) {
  1280. // The size being requested is less than the current size, so we need to free the end of
  1281. // the heap.
  1282. // Validate memory state.
  1283. std::size_t num_allocator_blocks;
  1284. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks),
  1285. heap_region_start + size, GetHeapSize() - size,
  1286. KMemoryState::All, KMemoryState::Normal,
  1287. KMemoryPermission::All, KMemoryPermission::UserReadWrite,
  1288. KMemoryAttribute::All, KMemoryAttribute::None));
  1289. // Unmap the end of the heap.
  1290. const auto num_pages = (GetHeapSize() - size) / PageSize;
  1291. R_TRY(Operate(heap_region_start + size, num_pages, KMemoryPermission::None,
  1292. OperationType::Unmap));
  1293. // Release the memory from the resource limit.
  1294. system.Kernel().CurrentProcess()->GetResourceLimit()->Release(
  1295. LimitableResource::PhysicalMemory, num_pages * PageSize);
  1296. // Apply the memory block update.
  1297. block_manager->Update(heap_region_start + size, num_pages, KMemoryState::Free,
  1298. KMemoryPermission::None, KMemoryAttribute::None);
  1299. // Update the current heap end.
  1300. current_heap_end = heap_region_start + size;
  1301. // Set the output.
  1302. *out = heap_region_start;
  1303. return ResultSuccess;
  1304. } else if (size == GetHeapSize()) {
  1305. // The size requested is exactly the current size.
  1306. *out = heap_region_start;
  1307. return ResultSuccess;
  1308. } else {
  1309. // We have to allocate memory. Determine how much to allocate and where while the table
  1310. // is locked.
  1311. cur_address = current_heap_end;
  1312. allocation_size = size - GetHeapSize();
  1313. }
  1314. }
  1315. // Reserve memory for the heap extension.
  1316. KScopedResourceReservation memory_reservation(
  1317. system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory,
  1318. allocation_size);
  1319. R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
  1320. // Allocate pages for the heap extension.
  1321. KPageLinkedList pg;
  1322. R_TRY(system.Kernel().MemoryManager().AllocateAndOpen(
  1323. &pg, allocation_size / PageSize,
  1324. KMemoryManager::EncodeOption(memory_pool, allocation_option)));
  1325. // Clear all the newly allocated pages.
  1326. for (const auto& it : pg.Nodes()) {
  1327. std::memset(system.DeviceMemory().GetPointer(it.GetAddress()), heap_fill_value,
  1328. it.GetSize());
  1329. }
  1330. // Map the pages.
  1331. {
  1332. // Lock the table.
  1333. KScopedLightLock lk(general_lock);
  1334. // Ensure that the heap hasn't changed since we began executing.
  1335. ASSERT(cur_address == current_heap_end);
  1336. // Check the memory state.
  1337. std::size_t num_allocator_blocks{};
  1338. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), current_heap_end,
  1339. allocation_size, KMemoryState::All, KMemoryState::Free,
  1340. KMemoryPermission::None, KMemoryPermission::None,
  1341. KMemoryAttribute::None, KMemoryAttribute::None));
  1342. // Map the pages.
  1343. const auto num_pages = allocation_size / PageSize;
  1344. R_TRY(Operate(current_heap_end, num_pages, pg, OperationType::MapGroup));
  1345. // Clear all the newly allocated pages.
  1346. for (std::size_t cur_page = 0; cur_page < num_pages; ++cur_page) {
  1347. std::memset(system.Memory().GetPointer(current_heap_end + (cur_page * PageSize)), 0,
  1348. PageSize);
  1349. }
  1350. // We succeeded, so commit our memory reservation.
  1351. memory_reservation.Commit();
  1352. // Apply the memory block update.
  1353. block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal,
  1354. KMemoryPermission::UserReadWrite, KMemoryAttribute::None);
  1355. // Update the current heap end.
  1356. current_heap_end = heap_region_start + size;
  1357. // Set the output.
  1358. *out = heap_region_start;
  1359. return ResultSuccess;
  1360. }
  1361. }
  1362. ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
  1363. bool is_map_only, VAddr region_start,
  1364. std::size_t region_num_pages, KMemoryState state,
  1365. KMemoryPermission perm, PAddr map_addr) {
  1366. KScopedLightLock lk(general_lock);
  1367. if (!CanContain(region_start, region_num_pages * PageSize, state)) {
  1368. return ResultInvalidCurrentMemory;
  1369. }
  1370. if (region_num_pages <= needed_num_pages) {
  1371. return ResultOutOfMemory;
  1372. }
  1373. const VAddr addr{
  1374. AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)};
  1375. if (!addr) {
  1376. return ResultOutOfMemory;
  1377. }
  1378. if (is_map_only) {
  1379. R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
  1380. } else {
  1381. KPageLinkedList page_group;
  1382. R_TRY(system.Kernel().MemoryManager().AllocateAndOpenForProcess(
  1383. &page_group, needed_num_pages,
  1384. KMemoryManager::EncodeOption(memory_pool, allocation_option), 0, 0));
  1385. R_TRY(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup));
  1386. }
  1387. block_manager->Update(addr, needed_num_pages, state, perm);
  1388. return addr;
  1389. }
  1390. ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
  1391. KScopedLightLock lk(general_lock);
  1392. KMemoryPermission perm{};
  1393. if (const ResultCode result{CheckMemoryState(
  1394. nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
  1395. KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
  1396. KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
  1397. KMemoryAttribute::DeviceSharedAndUncached)};
  1398. result.IsError()) {
  1399. return result;
  1400. }
  1401. block_manager->UpdateLock(
  1402. addr, size / PageSize,
  1403. [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
  1404. block->ShareToDevice(permission);
  1405. },
  1406. perm);
  1407. return ResultSuccess;
  1408. }
  1409. ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
  1410. KScopedLightLock lk(general_lock);
  1411. KMemoryPermission perm{};
  1412. if (const ResultCode result{CheckMemoryState(
  1413. nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
  1414. KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
  1415. KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
  1416. KMemoryAttribute::DeviceSharedAndUncached)};
  1417. result.IsError()) {
  1418. return result;
  1419. }
  1420. block_manager->UpdateLock(
  1421. addr, size / PageSize,
  1422. [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
  1423. block->UnshareToDevice(permission);
  1424. },
  1425. perm);
  1426. return ResultSuccess;
  1427. }
  1428. ResultCode KPageTable::LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size) {
  1429. return this->LockMemoryAndOpen(
  1430. out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
  1431. KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
  1432. KMemoryAttribute::None,
  1433. static_cast<KMemoryPermission>(KMemoryPermission::NotMapped |
  1434. KMemoryPermission::KernelReadWrite),
  1435. KMemoryAttribute::Locked);
  1436. }
  1437. ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size,
  1438. const KPageLinkedList& pg) {
  1439. return this->UnlockMemory(
  1440. addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
  1441. KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All,
  1442. KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg);
  1443. }
  1444. ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
  1445. block_manager = std::make_unique<KMemoryBlockManager>(start, end);
  1446. return ResultSuccess;
  1447. }
  1448. bool KPageTable::IsRegionMapped(VAddr address, u64 size) {
  1449. return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
  1450. KMemoryPermission::All, KMemoryPermission::None, KMemoryAttribute::Mask,
  1451. KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)
  1452. .IsError();
  1453. }
  1454. bool KPageTable::IsRegionContiguous(VAddr addr, u64 size) const {
  1455. auto start_ptr = system.Memory().GetPointer(addr);
  1456. for (u64 offset{}; offset < size; offset += PageSize) {
  1457. if (start_ptr != system.Memory().GetPointer(addr + offset)) {
  1458. return false;
  1459. }
  1460. start_ptr += PageSize;
  1461. }
  1462. return true;
  1463. }
  1464. void KPageTable::AddRegionToPages(VAddr start, std::size_t num_pages,
  1465. KPageLinkedList& page_linked_list) {
  1466. VAddr addr{start};
  1467. while (addr < start + (num_pages * PageSize)) {
  1468. const PAddr paddr{GetPhysicalAddr(addr)};
  1469. ASSERT(paddr != 0);
  1470. page_linked_list.AddBlock(paddr, 1);
  1471. addr += PageSize;
  1472. }
  1473. }
  1474. VAddr KPageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages,
  1475. u64 needed_num_pages, std::size_t align) {
  1476. if (is_aslr_enabled) {
  1477. UNIMPLEMENTED();
  1478. }
  1479. return block_manager->FindFreeArea(start, region_num_pages, needed_num_pages, align, 0,
  1480. IsKernel() ? 1 : 4);
  1481. }
  1482. ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group,
  1483. OperationType operation) {
  1484. ASSERT(this->IsLockedByCurrentThread());
  1485. ASSERT(Common::IsAligned(addr, PageSize));
  1486. ASSERT(num_pages > 0);
  1487. ASSERT(num_pages == page_group.GetNumPages());
  1488. for (const auto& node : page_group.Nodes()) {
  1489. const std::size_t size{node.GetNumPages() * PageSize};
  1490. switch (operation) {
  1491. case OperationType::MapGroup:
  1492. system.Memory().MapMemoryRegion(page_table_impl, addr, size, node.GetAddress());
  1493. break;
  1494. default:
  1495. ASSERT(false);
  1496. }
  1497. addr += size;
  1498. }
  1499. return ResultSuccess;
  1500. }
  1501. ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
  1502. OperationType operation, PAddr map_addr) {
  1503. ASSERT(this->IsLockedByCurrentThread());
  1504. ASSERT(num_pages > 0);
  1505. ASSERT(Common::IsAligned(addr, PageSize));
  1506. ASSERT(ContainsPages(addr, num_pages));
  1507. switch (operation) {
  1508. case OperationType::Unmap:
  1509. system.Memory().UnmapRegion(page_table_impl, addr, num_pages * PageSize);
  1510. break;
  1511. case OperationType::Map: {
  1512. ASSERT(map_addr);
  1513. ASSERT(Common::IsAligned(map_addr, PageSize));
  1514. system.Memory().MapMemoryRegion(page_table_impl, addr, num_pages * PageSize, map_addr);
  1515. break;
  1516. }
  1517. case OperationType::ChangePermissions:
  1518. case OperationType::ChangePermissionsAndRefresh:
  1519. break;
  1520. default:
  1521. ASSERT(false);
  1522. }
  1523. return ResultSuccess;
  1524. }
  1525. VAddr KPageTable::GetRegionAddress(KMemoryState state) const {
  1526. switch (state) {
  1527. case KMemoryState::Free:
  1528. case KMemoryState::Kernel:
  1529. return address_space_start;
  1530. case KMemoryState::Normal:
  1531. return heap_region_start;
  1532. case KMemoryState::Ipc:
  1533. case KMemoryState::NonSecureIpc:
  1534. case KMemoryState::NonDeviceIpc:
  1535. return alias_region_start;
  1536. case KMemoryState::Stack:
  1537. return stack_region_start;
  1538. case KMemoryState::Static:
  1539. case KMemoryState::ThreadLocal:
  1540. return kernel_map_region_start;
  1541. case KMemoryState::Io:
  1542. case KMemoryState::Shared:
  1543. case KMemoryState::AliasCode:
  1544. case KMemoryState::AliasCodeData:
  1545. case KMemoryState::Transfered:
  1546. case KMemoryState::SharedTransfered:
  1547. case KMemoryState::SharedCode:
  1548. case KMemoryState::GeneratedCode:
  1549. case KMemoryState::CodeOut:
  1550. case KMemoryState::Coverage:
  1551. return alias_code_region_start;
  1552. case KMemoryState::Code:
  1553. case KMemoryState::CodeData:
  1554. return code_region_start;
  1555. default:
  1556. UNREACHABLE();
  1557. }
  1558. }
  1559. std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
  1560. switch (state) {
  1561. case KMemoryState::Free:
  1562. case KMemoryState::Kernel:
  1563. return address_space_end - address_space_start;
  1564. case KMemoryState::Normal:
  1565. return heap_region_end - heap_region_start;
  1566. case KMemoryState::Ipc:
  1567. case KMemoryState::NonSecureIpc:
  1568. case KMemoryState::NonDeviceIpc:
  1569. return alias_region_end - alias_region_start;
  1570. case KMemoryState::Stack:
  1571. return stack_region_end - stack_region_start;
  1572. case KMemoryState::Static:
  1573. case KMemoryState::ThreadLocal:
  1574. return kernel_map_region_end - kernel_map_region_start;
  1575. case KMemoryState::Io:
  1576. case KMemoryState::Shared:
  1577. case KMemoryState::AliasCode:
  1578. case KMemoryState::AliasCodeData:
  1579. case KMemoryState::Transfered:
  1580. case KMemoryState::SharedTransfered:
  1581. case KMemoryState::SharedCode:
  1582. case KMemoryState::GeneratedCode:
  1583. case KMemoryState::CodeOut:
  1584. case KMemoryState::Coverage:
  1585. return alias_code_region_end - alias_code_region_start;
  1586. case KMemoryState::Code:
  1587. case KMemoryState::CodeData:
  1588. return code_region_end - code_region_start;
  1589. default:
  1590. UNREACHABLE();
  1591. }
  1592. }
  1593. bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const {
  1594. const VAddr end = addr + size;
  1595. const VAddr last = end - 1;
  1596. const VAddr region_start = this->GetRegionAddress(state);
  1597. const size_t region_size = this->GetRegionSize(state);
  1598. const bool is_in_region =
  1599. region_start <= addr && addr < end && last <= region_start + region_size - 1;
  1600. const bool is_in_heap = !(end <= heap_region_start || heap_region_end <= addr ||
  1601. heap_region_start == heap_region_end);
  1602. const bool is_in_alias = !(end <= alias_region_start || alias_region_end <= addr ||
  1603. alias_region_start == alias_region_end);
  1604. switch (state) {
  1605. case KMemoryState::Free:
  1606. case KMemoryState::Kernel:
  1607. return is_in_region;
  1608. case KMemoryState::Io:
  1609. case KMemoryState::Static:
  1610. case KMemoryState::Code:
  1611. case KMemoryState::CodeData:
  1612. case KMemoryState::Shared:
  1613. case KMemoryState::AliasCode:
  1614. case KMemoryState::AliasCodeData:
  1615. case KMemoryState::Stack:
  1616. case KMemoryState::ThreadLocal:
  1617. case KMemoryState::Transfered:
  1618. case KMemoryState::SharedTransfered:
  1619. case KMemoryState::SharedCode:
  1620. case KMemoryState::GeneratedCode:
  1621. case KMemoryState::CodeOut:
  1622. case KMemoryState::Coverage:
  1623. return is_in_region && !is_in_heap && !is_in_alias;
  1624. case KMemoryState::Normal:
  1625. ASSERT(is_in_heap);
  1626. return is_in_region && !is_in_alias;
  1627. case KMemoryState::Ipc:
  1628. case KMemoryState::NonSecureIpc:
  1629. case KMemoryState::NonDeviceIpc:
  1630. ASSERT(is_in_alias);
  1631. return is_in_region && !is_in_heap;
  1632. default:
  1633. return false;
  1634. }
  1635. }
  1636. ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
  1637. KMemoryState state, KMemoryPermission perm_mask,
  1638. KMemoryPermission perm, KMemoryAttribute attr_mask,
  1639. KMemoryAttribute attr) const {
  1640. // Validate the states match expectation.
  1641. R_UNLESS((info.state & state_mask) == state, ResultInvalidCurrentMemory);
  1642. R_UNLESS((info.perm & perm_mask) == perm, ResultInvalidCurrentMemory);
  1643. R_UNLESS((info.attribute & attr_mask) == attr, ResultInvalidCurrentMemory);
  1644. return ResultSuccess;
  1645. }
  1646. ResultCode KPageTable::CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr,
  1647. std::size_t size, KMemoryState state_mask,
  1648. KMemoryState state, KMemoryPermission perm_mask,
  1649. KMemoryPermission perm,
  1650. KMemoryAttribute attr_mask,
  1651. KMemoryAttribute attr) const {
  1652. ASSERT(this->IsLockedByCurrentThread());
  1653. // Get information about the first block.
  1654. const VAddr last_addr = addr + size - 1;
  1655. KMemoryBlockManager::const_iterator it = block_manager->FindIterator(addr);
  1656. KMemoryInfo info = it->GetMemoryInfo();
  1657. // If the start address isn't aligned, we need a block.
  1658. const size_t blocks_for_start_align =
  1659. (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
  1660. while (true) {
  1661. // Validate against the provided masks.
  1662. R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
  1663. // Break once we're done.
  1664. if (last_addr <= info.GetLastAddress()) {
  1665. break;
  1666. }
  1667. // Advance our iterator.
  1668. it++;
  1669. ASSERT(it != block_manager->cend());
  1670. info = it->GetMemoryInfo();
  1671. }
  1672. // If the end address isn't aligned, we need a block.
  1673. const size_t blocks_for_end_align =
  1674. (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
  1675. if (out_blocks_needed != nullptr) {
  1676. *out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
  1677. }
  1678. return ResultSuccess;
  1679. }
  1680. ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
  1681. KMemoryAttribute* out_attr, std::size_t* out_blocks_needed,
  1682. VAddr addr, std::size_t size, KMemoryState state_mask,
  1683. KMemoryState state, KMemoryPermission perm_mask,
  1684. KMemoryPermission perm, KMemoryAttribute attr_mask,
  1685. KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
  1686. ASSERT(this->IsLockedByCurrentThread());
  1687. // Get information about the first block.
  1688. const VAddr last_addr = addr + size - 1;
  1689. KMemoryBlockManager::const_iterator it = block_manager->FindIterator(addr);
  1690. KMemoryInfo info = it->GetMemoryInfo();
  1691. // If the start address isn't aligned, we need a block.
  1692. const size_t blocks_for_start_align =
  1693. (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
  1694. // Validate all blocks in the range have correct state.
  1695. const KMemoryState first_state = info.state;
  1696. const KMemoryPermission first_perm = info.perm;
  1697. const KMemoryAttribute first_attr = info.attribute;
  1698. while (true) {
  1699. // Validate the current block.
  1700. R_UNLESS(info.state == first_state, ResultInvalidCurrentMemory);
  1701. R_UNLESS(info.perm == first_perm, ResultInvalidCurrentMemory);
  1702. R_UNLESS((info.attribute | ignore_attr) == (first_attr | ignore_attr),
  1703. ResultInvalidCurrentMemory);
  1704. // Validate against the provided masks.
  1705. R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
  1706. // Break once we're done.
  1707. if (last_addr <= info.GetLastAddress()) {
  1708. break;
  1709. }
  1710. // Advance our iterator.
  1711. it++;
  1712. ASSERT(it != block_manager->cend());
  1713. info = it->GetMemoryInfo();
  1714. }
  1715. // If the end address isn't aligned, we need a block.
  1716. const size_t blocks_for_end_align =
  1717. (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
  1718. // Write output state.
  1719. if (out_state != nullptr) {
  1720. *out_state = first_state;
  1721. }
  1722. if (out_perm != nullptr) {
  1723. *out_perm = first_perm;
  1724. }
  1725. if (out_attr != nullptr) {
  1726. *out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
  1727. }
  1728. if (out_blocks_needed != nullptr) {
  1729. *out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
  1730. }
  1731. return ResultSuccess;
  1732. }
  1733. ResultCode KPageTable::LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_paddr, VAddr addr,
  1734. size_t size, KMemoryState state_mask, KMemoryState state,
  1735. KMemoryPermission perm_mask, KMemoryPermission perm,
  1736. KMemoryAttribute attr_mask, KMemoryAttribute attr,
  1737. KMemoryPermission new_perm, KMemoryAttribute lock_attr) {
  1738. // Validate basic preconditions.
  1739. ASSERT((lock_attr & attr) == KMemoryAttribute::None);
  1740. ASSERT((lock_attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
  1741. KMemoryAttribute::None);
  1742. // Validate the lock request.
  1743. const size_t num_pages = size / PageSize;
  1744. R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
  1745. // Lock the table.
  1746. KScopedLightLock lk(general_lock);
  1747. // Check that the output page group is empty, if it exists.
  1748. if (out_pg) {
  1749. ASSERT(out_pg->GetNumPages() == 0);
  1750. }
  1751. // Check the state.
  1752. KMemoryState old_state{};
  1753. KMemoryPermission old_perm{};
  1754. KMemoryAttribute old_attr{};
  1755. size_t num_allocator_blocks{};
  1756. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
  1757. std::addressof(old_attr), std::addressof(num_allocator_blocks),
  1758. addr, size, state_mask | KMemoryState::FlagReferenceCounted,
  1759. state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
  1760. attr_mask, attr));
  1761. // Get the physical address, if we're supposed to.
  1762. if (out_paddr != nullptr) {
  1763. ASSERT(this->GetPhysicalAddressLocked(out_paddr, addr));
  1764. }
  1765. // Make the page group, if we're supposed to.
  1766. if (out_pg != nullptr) {
  1767. R_TRY(this->MakePageGroup(*out_pg, addr, num_pages));
  1768. }
  1769. // Decide on new perm and attr.
  1770. new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
  1771. KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr | lock_attr);
  1772. // Update permission, if we need to.
  1773. if (new_perm != old_perm) {
  1774. R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
  1775. }
  1776. // Apply the memory block updates.
  1777. block_manager->Update(addr, num_pages, old_state, new_perm, new_attr);
  1778. return ResultSuccess;
  1779. }
  1780. ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask,
  1781. KMemoryState state, KMemoryPermission perm_mask,
  1782. KMemoryPermission perm, KMemoryAttribute attr_mask,
  1783. KMemoryAttribute attr, KMemoryPermission new_perm,
  1784. KMemoryAttribute lock_attr, const KPageLinkedList* pg) {
  1785. // Validate basic preconditions.
  1786. ASSERT((attr_mask & lock_attr) == lock_attr);
  1787. ASSERT((attr & lock_attr) == lock_attr);
  1788. // Validate the unlock request.
  1789. const size_t num_pages = size / PageSize;
  1790. R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
  1791. // Lock the table.
  1792. KScopedLightLock lk(general_lock);
  1793. // Check the state.
  1794. KMemoryState old_state{};
  1795. KMemoryPermission old_perm{};
  1796. KMemoryAttribute old_attr{};
  1797. size_t num_allocator_blocks{};
  1798. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
  1799. std::addressof(old_attr), std::addressof(num_allocator_blocks),
  1800. addr, size, state_mask | KMemoryState::FlagReferenceCounted,
  1801. state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
  1802. attr_mask, attr));
  1803. // Check the page group.
  1804. if (pg != nullptr) {
  1805. R_UNLESS(this->IsValidPageGroup(*pg, addr, num_pages), ResultInvalidMemoryRegion);
  1806. }
  1807. // Decide on new perm and attr.
  1808. new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
  1809. KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr & ~lock_attr);
  1810. // Update permission, if we need to.
  1811. if (new_perm != old_perm) {
  1812. R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
  1813. }
  1814. // Apply the memory block updates.
  1815. block_manager->Update(addr, num_pages, old_state, new_perm, new_attr);
  1816. return ResultSuccess;
  1817. }
  1818. } // namespace Kernel