k_page_table.cpp 83 KB

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